5f0c7b29f73cef858d7bb0a8e1ad6065a178b9c2
[yaffs2.git] / yaffs_fs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  * Acknowledgements:
9  * Luc van OostenRyck for numerous patches.
10  * Nick Bane for numerous patches.
11  * Nick Bane for 2.5/2.6 integration.
12  * Andras Toth for mknod rdev issue.
13  * Michael Fischer for finding the problem with inode inconsistency.
14  * Some code bodily lifted from JFFS
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License version 2 as
18  * published by the Free Software Foundation.
19  */
20
21 /*
22  *
23  * This is the file system front-end to YAFFS that hooks it up to
24  * the VFS.
25  *
26  * Special notes:
27  * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
28  *         this superblock
29  * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this
30  *         superblock
31  * >> inode->u.generic_ip points to the associated yaffs_Object.
32  */
33
34 const char *yaffs_fs_c_version =
35     "$Id: yaffs_fs.c,v 1.75 2009-03-05 01:45:28 charles Exp $";
36 extern const char *yaffs_guts_c_version;
37
38 #include <linux/version.h>
39 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
40 #include <linux/config.h>
41 #endif
42 #include <linux/kernel.h>
43 #include <linux/module.h>
44 #include <linux/slab.h>
45 #include <linux/init.h>
46 #include <linux/fs.h>
47 #include <linux/proc_fs.h>
48 #include <linux/smp_lock.h>
49 #include <linux/pagemap.h>
50 #include <linux/mtd/mtd.h>
51 #include <linux/interrupt.h>
52 #include <linux/string.h>
53 #include <linux/ctype.h>
54
55 #include "asm/div64.h"
56
57 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
58
59 #include <linux/statfs.h>       /* Added NCB 15-8-2003 */
60 #include <asm/statfs.h>
61 #define UnlockPage(p) unlock_page(p)
62 #define Page_Uptodate(page)     test_bit(PG_uptodate, &(page)->flags)
63
64 /* FIXME: use sb->s_id instead ? */
65 #define yaffs_devname(sb, buf)  bdevname(sb->s_bdev, buf)
66
67 #else
68
69 #include <linux/locks.h>
70 #define BDEVNAME_SIZE           0
71 #define yaffs_devname(sb, buf)  kdevname(sb->s_dev)
72
73 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
74 /* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
75 #define __user
76 #endif
77
78 #endif
79
80 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
81 #define YPROC_ROOT  &proc_root
82 #else
83 #define YPROC_ROOT  NULL
84 #endif
85
86 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
87 #define WRITE_SIZE_STR "writesize"
88 #define WRITE_SIZE(mtd) (mtd)->writesize
89 #else
90 #define WRITE_SIZE_STR "oobblock"
91 #define WRITE_SIZE(mtd) (mtd)->oobblock
92 #endif
93
94 #if(LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
95 #define YAFFS_USE_WRITE_BEGIN_END 1
96 #else
97 #define YAFFS_USE_WRITE_BEGIN_END 0
98 #endif
99
100 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
101 static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
102 {
103         uint64_t result = partition_size;
104         do_div(result,block_size);
105         return (uint32_t)result;
106 }
107 #else
108 #define YCALCBLOCKS(s,b) ((s)/(b))
109 #endif
110
111 #include <asm/uaccess.h>
112
113 #include "yportenv.h"
114 #include "yaffs_guts.h"
115
116 #include <linux/mtd/mtd.h>
117 #include "yaffs_mtdif.h"
118 #include "yaffs_mtdif1.h"
119 #include "yaffs_mtdif2.h"
120
121 unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
122 unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
123 unsigned int yaffs_auto_checkpoint = 1;
124
125 /* Module Parameters */
126 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
127 module_param(yaffs_traceMask,uint,0644);
128 module_param(yaffs_wr_attempts,uint,0644);
129 module_param(yaffs_auto_checkpoint,uint,0644);
130 #else
131 MODULE_PARM(yaffs_traceMask,"i");
132 MODULE_PARM(yaffs_wr_attempts,"i");
133 MODULE_PARM(yaffs_auto_checkpoint,"i");
134 #endif
135
136 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
137 /* use iget and read_inode */
138 #define Y_IGET(sb,inum) iget((sb),(inum))
139 static void yaffs_read_inode(struct inode *inode);
140
141 #else
142 /* Call local equivalent */
143 #define YAFFS_USE_OWN_IGET
144 #define Y_IGET(sb,inum) yaffs_iget((sb),(inum))
145
146 static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino);
147 #endif
148
149 /*#define T(x) printk x */
150
151 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
152 #define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
153 #else
154 #define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
155 #endif
156
157 #define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
158 #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
159
160 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
161 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
162 #else
163 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
164 #endif
165
166 static void yaffs_put_super(struct super_block *sb);
167
168 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
169                                 loff_t * pos);
170 static ssize_t yaffs_hold_space(struct file *f);
171 static void yaffs_release_space(struct file *f);
172
173 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
174 static int yaffs_file_flush(struct file *file, fl_owner_t id);
175 #else
176 static int yaffs_file_flush(struct file *file);
177 #endif
178
179 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
180                              int datasync);
181
182 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
183
184 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
185 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
186                         struct nameidata *n);
187 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
188                                    struct nameidata *n);
189 #else
190 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
191 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
192 #endif
193 static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
194                       struct dentry *dentry);
195 static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
196 static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
197                          const char *symname);
198 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
199
200 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
201 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
202                        dev_t dev);
203 #else
204 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
205                        int dev);
206 #endif
207 static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
208                         struct inode *new_dir, struct dentry *new_dentry);
209 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
210
211 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
212 static int yaffs_sync_fs(struct super_block *sb, int wait);
213 static void yaffs_write_super(struct super_block *sb);
214 #else
215 static int yaffs_sync_fs(struct super_block *sb);
216 static int yaffs_write_super(struct super_block *sb);
217 #endif
218
219 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
220 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
221 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
222 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
223 #else
224 static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
225 #endif
226
227 #ifdef YAFFS_HAS_PUT_INODE
228 static void yaffs_put_inode(struct inode *inode);
229 #endif
230
231 static void yaffs_delete_inode(struct inode *);
232 static void yaffs_clear_inode(struct inode *);
233
234 static int yaffs_readpage(struct file *file, struct page *page);
235 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
236 static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
237 #else
238 static int yaffs_writepage(struct page *page);
239 #endif
240
241
242 #if (YAFFS_USE_WRITE_BEGIN_END != 0)
243 static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
244                              loff_t pos, unsigned len, unsigned flags,
245                           struct page **pagep, void **fsdata);
246 static int yaffs_write_end(struct file *filp, struct address_space *mapping,
247                            loff_t pos, unsigned len, unsigned copied,
248                            struct page *pg, void *fsdadata);
249 #else
250 static int yaffs_prepare_write(struct file *f, struct page *pg,
251                                unsigned offset, unsigned to);
252 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
253                               unsigned to);
254                                                                                                 
255 #endif
256
257 static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
258                           int buflen);
259 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
260 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
261 #else
262 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
263 #endif
264
265 static struct address_space_operations yaffs_file_address_operations = {
266         .readpage = yaffs_readpage,
267         .writepage = yaffs_writepage,
268 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
269         .write_begin = yaffs_write_begin,
270         .write_end = yaffs_write_end,
271 #else
272         .prepare_write = yaffs_prepare_write,
273         .commit_write = yaffs_commit_write,
274 #endif
275 };
276
277 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
278 static struct file_operations yaffs_file_operations = {
279         .read = do_sync_read,
280         .write = do_sync_write,
281         .aio_read = generic_file_aio_read,
282         .aio_write = generic_file_aio_write,
283         .mmap = generic_file_mmap,
284         .flush = yaffs_file_flush,
285         .fsync = yaffs_sync_object,
286         .splice_read = generic_file_splice_read,
287         .splice_write = generic_file_splice_write,
288         .llseek = generic_file_llseek,
289 };
290
291 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
292
293 static struct file_operations yaffs_file_operations = {
294         .read = do_sync_read,
295         .write = do_sync_write,
296         .aio_read = generic_file_aio_read,
297         .aio_write = generic_file_aio_write,
298         .mmap = generic_file_mmap,
299         .flush = yaffs_file_flush,
300         .fsync = yaffs_sync_object,
301         .sendfile = generic_file_sendfile,
302 };
303
304 #else
305
306 static struct file_operations yaffs_file_operations = {
307         .read = generic_file_read,
308         .write = generic_file_write,
309         .mmap = generic_file_mmap,
310         .flush = yaffs_file_flush,
311         .fsync = yaffs_sync_object,
312 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
313         .sendfile = generic_file_sendfile,
314 #endif
315 };
316 #endif
317
318 static struct inode_operations yaffs_file_inode_operations = {
319         .setattr = yaffs_setattr,
320 };
321
322 static struct inode_operations yaffs_symlink_inode_operations = {
323         .readlink = yaffs_readlink,
324         .follow_link = yaffs_follow_link,
325         .setattr = yaffs_setattr,
326 };
327
328 static struct inode_operations yaffs_dir_inode_operations = {
329         .create = yaffs_create,
330         .lookup = yaffs_lookup,
331         .link = yaffs_link,
332         .unlink = yaffs_unlink,
333         .symlink = yaffs_symlink,
334         .mkdir = yaffs_mkdir,
335         .rmdir = yaffs_unlink,
336         .mknod = yaffs_mknod,
337         .rename = yaffs_rename,
338         .setattr = yaffs_setattr,
339 };
340
341 static struct file_operations yaffs_dir_operations = {
342         .read = generic_read_dir,
343         .readdir = yaffs_readdir,
344         .fsync = yaffs_sync_object,
345 };
346
347 static struct super_operations yaffs_super_ops = {
348         .statfs = yaffs_statfs,
349
350 #ifndef YAFFS_USE_OWN_IGET
351         .read_inode = yaffs_read_inode,
352 #endif
353 #ifdef YAFFS_HAS_PUT_INODE
354         .put_inode = yaffs_put_inode,
355 #endif
356         .put_super = yaffs_put_super,
357         .delete_inode = yaffs_delete_inode,
358         .clear_inode = yaffs_clear_inode,
359         .sync_fs = yaffs_sync_fs,
360         .write_super = yaffs_write_super,
361 };
362
363 static void yaffs_GrossLock(yaffs_Device * dev)
364 {
365         T(YAFFS_TRACE_OS, ( "yaffs locking %p\n",current));
366
367         down(&dev->grossLock);
368         T(YAFFS_TRACE_OS, ( "yaffs locked %p\n",current));
369         
370 }
371
372 static void yaffs_GrossUnlock(yaffs_Device * dev)
373 {
374         T(YAFFS_TRACE_OS, ( "yaffs unlocking %p\n",current));
375         up(&dev->grossLock);
376
377 }
378
379 static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
380                           int buflen)
381 {
382         unsigned char *alias;
383         int ret;
384
385         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
386
387         yaffs_GrossLock(dev);
388
389         alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
390
391         yaffs_GrossUnlock(dev);
392
393         if (!alias)
394                 return -ENOMEM;
395
396         ret = vfs_readlink(dentry, buffer, buflen, alias);
397         kfree(alias);
398         return ret;
399 }
400
401 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
402 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
403 #else
404 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
405 #endif
406 {
407         unsigned char *alias;
408         int ret;
409         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
410
411         yaffs_GrossLock(dev);
412
413         alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
414
415         yaffs_GrossUnlock(dev);
416
417         if (!alias)
418         {
419                 ret = -ENOMEM;
420                 goto out;
421         }
422
423         ret = vfs_follow_link(nd, alias);
424         kfree(alias);
425 out:
426 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
427         return ERR_PTR (ret);
428 #else
429         return ret;
430 #endif
431 }
432
433 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
434                               yaffs_Object * obj);
435
436 /*
437  * Lookup is used to find objects in the fs
438  */
439 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
440
441 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
442                                    struct nameidata *n)
443 #else
444 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
445 #endif
446 {
447         yaffs_Object *obj;
448         struct inode *inode = NULL;     /* NCB 2.5/2.6 needs NULL here */
449
450         yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
451
452         yaffs_GrossLock(dev);
453
454         T(YAFFS_TRACE_OS,
455           ( "yaffs_lookup for %d:%s\n",
456            yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
457
458         obj =
459             yaffs_FindObjectByName(yaffs_InodeToObject(dir),
460                                    dentry->d_name.name);
461
462         obj = yaffs_GetEquivalentObject(obj);   /* in case it was a hardlink */
463
464         /* Can't hold gross lock when calling yaffs_get_inode() */
465         yaffs_GrossUnlock(dev);
466
467         if (obj) {
468                 T(YAFFS_TRACE_OS,
469                   ( "yaffs_lookup found %d\n", obj->objectId));
470
471                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
472
473                 if (inode) {
474                         T(YAFFS_TRACE_OS,
475                           ( "yaffs_loookup dentry \n"));
476 /* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
477  * d_add even if NULL inode */
478 #if 0
479                         /*dget(dentry); // try to solve directory bug */
480                         d_add(dentry, inode);
481
482                         /* return dentry; */
483                         return NULL;
484 #endif
485                 }
486
487         } else {
488                 T(YAFFS_TRACE_OS, ( "yaffs_lookup not found\n"));
489
490         }
491
492 /* added NCB for 2.5/6 compatability - forces add even if inode is
493  * NULL which creates dentry hash */
494         d_add(dentry, inode);
495
496         return NULL;
497         /*      return (ERR_PTR(-EIO)); */
498
499 }
500
501
502 #ifdef YAFFS_HAS_PUT_INODE
503
504 /* For now put inode is just for debugging
505  * Put inode is called when the inode **structure** is put.
506  */
507 static void yaffs_put_inode(struct inode *inode)
508 {
509         T(YAFFS_TRACE_OS,
510           ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
511            atomic_read(&inode->i_count)));
512
513 }
514 #endif
515
516 /* clear is called to tell the fs to release any per-inode data it holds */
517 static void yaffs_clear_inode(struct inode *inode)
518 {
519         yaffs_Object *obj;
520         yaffs_Device *dev;
521
522         obj = yaffs_InodeToObject(inode);
523
524         T(YAFFS_TRACE_OS,
525           ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
526            atomic_read(&inode->i_count),
527            obj ? "object exists" : "null object"));
528
529         if (obj) {
530                 dev = obj->myDev;
531                 yaffs_GrossLock(dev);
532
533                 /* Clear the association between the inode and
534                  * the yaffs_Object.
535                  */
536                 obj->myInode = NULL;
537                 yaffs_InodeToObjectLV(inode) = NULL;
538
539                 /* If the object freeing was deferred, then the real
540                  * free happens now.
541                  * This should fix the inode inconsistency problem.
542                  */
543
544                 yaffs_HandleDeferedFree(obj);
545
546                 yaffs_GrossUnlock(dev);
547         }
548
549 }
550
551 /* delete is called when the link count is zero and the inode
552  * is put (ie. nobody wants to know about it anymore, time to
553  * delete the file).
554  * NB Must call clear_inode()
555  */
556 static void yaffs_delete_inode(struct inode *inode)
557 {
558         yaffs_Object *obj = yaffs_InodeToObject(inode);
559         yaffs_Device *dev;
560
561         T(YAFFS_TRACE_OS,
562           ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
563            atomic_read(&inode->i_count),
564            obj ? "object exists" : "null object"));
565
566         if (obj) {
567                 dev = obj->myDev;
568                 yaffs_GrossLock(dev);
569                 yaffs_DeleteObject(obj);
570                 yaffs_GrossUnlock(dev);
571         }
572 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
573         truncate_inode_pages (&inode->i_data, 0);
574 #endif
575         clear_inode(inode);
576 }
577
578 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
579 static int yaffs_file_flush(struct file *file, fl_owner_t id)
580 #else
581 static int yaffs_file_flush(struct file *file)
582 #endif
583 {
584         yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
585
586         yaffs_Device *dev = obj->myDev;
587
588         T(YAFFS_TRACE_OS,
589           ( "yaffs_file_flush object %d (%s)\n", obj->objectId,
590            obj->dirty ? "dirty" : "clean"));
591
592         yaffs_GrossLock(dev);
593
594         yaffs_FlushFile(obj, 1);
595
596         yaffs_GrossUnlock(dev);
597
598         return 0;
599 }
600
601 static int yaffs_readpage_nolock(struct file *f, struct page *pg)
602 {
603         /* Lifted from jffs2 */
604
605         yaffs_Object *obj;
606         unsigned char *pg_buf;
607         int ret;
608
609         yaffs_Device *dev;
610
611         T(YAFFS_TRACE_OS, ( "yaffs_readpage at %08x, size %08x\n",
612                            (unsigned)(pg->index << PAGE_CACHE_SHIFT),
613                            (unsigned)PAGE_CACHE_SIZE));
614
615         obj = yaffs_DentryToObject(f->f_dentry);
616
617         dev = obj->myDev;
618
619 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
620         BUG_ON(!PageLocked(pg));
621 #else
622         if (!PageLocked(pg))
623                 PAGE_BUG(pg);
624 #endif
625
626         pg_buf = kmap(pg);
627         /* FIXME: Can kmap fail? */
628
629         yaffs_GrossLock(dev);
630
631         ret =
632             yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT,
633                                    PAGE_CACHE_SIZE);
634
635         yaffs_GrossUnlock(dev);
636
637         if (ret >= 0)
638                 ret = 0;
639
640         if (ret) {
641                 ClearPageUptodate(pg);
642                 SetPageError(pg);
643         } else {
644                 SetPageUptodate(pg);
645                 ClearPageError(pg);
646         }
647
648         flush_dcache_page(pg);
649         kunmap(pg);
650
651         T(YAFFS_TRACE_OS, ( "yaffs_readpage done\n"));
652         return ret;
653 }
654
655 static int yaffs_readpage_unlock(struct file *f, struct page *pg)
656 {
657         int ret = yaffs_readpage_nolock(f, pg);
658         UnlockPage(pg);
659         return ret;
660 }
661
662 static int yaffs_readpage(struct file *f, struct page *pg)
663 {
664         return yaffs_readpage_unlock(f, pg);
665 }
666
667 /* writepage inspired by/stolen from smbfs */
668
669 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
670 static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
671 #else
672 static int yaffs_writepage(struct page *page)
673 #endif
674 {
675         struct address_space *mapping = page->mapping;
676         loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
677         struct inode *inode;
678         unsigned long end_index;
679         char *buffer;
680         yaffs_Object *obj;
681         int nWritten = 0;
682         unsigned nBytes;
683
684         if (!mapping)
685                 BUG();
686         inode = mapping->host;
687         if (!inode)
688                 BUG();
689
690         if (offset > inode->i_size) {
691                 T(YAFFS_TRACE_OS,
692                   (
693                    "yaffs_writepage at %08x, inode size = %08x!!!\n",
694                    (unsigned)(page->index << PAGE_CACHE_SHIFT),
695                    (unsigned)inode->i_size));
696                 T(YAFFS_TRACE_OS,
697                   ( "                -> don't care!!\n"));
698                 unlock_page(page);
699                 return 0;
700         }
701
702         end_index = inode->i_size >> PAGE_CACHE_SHIFT;
703
704         /* easy case */
705         if (page->index < end_index) {
706                 nBytes = PAGE_CACHE_SIZE;
707         } else {
708                 nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
709         }
710
711         get_page(page);
712
713         buffer = kmap(page);
714
715         obj = yaffs_InodeToObject(inode);
716         yaffs_GrossLock(obj->myDev);
717
718         T(YAFFS_TRACE_OS,
719           ( "yaffs_writepage at %08x, size %08x\n",
720            (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
721         T(YAFFS_TRACE_OS,
722           ( "writepag0: obj = %05x, ino = %05x\n",
723            (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
724
725         nWritten =
726             yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT,
727                                   nBytes, 0);
728
729         T(YAFFS_TRACE_OS,
730           ( "writepag1: obj = %05x, ino = %05x\n",
731            (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
732
733         yaffs_GrossUnlock(obj->myDev);
734
735         kunmap(page);
736         SetPageUptodate(page);
737         UnlockPage(page);
738         put_page(page);
739
740         return (nWritten == nBytes) ? 0 : -ENOSPC;
741 }
742
743
744 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
745 static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
746                              loff_t pos, unsigned len, unsigned flags,
747                           struct page **pagep, void **fsdata)
748
749 {
750         struct page *pg = NULL;
751         pgoff_t index = pos >> PAGE_CACHE_SHIFT;
752         uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
753         uint32_t to = offset + len;
754         
755         int ret = 0;
756         int space_held = 0;
757         
758         T(YAFFS_TRACE_OS, ( "start yaffs_write_begin\n"));
759         /* Get a page */
760 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
761         pg = grab_cache_page_write_begin(mapping,index,flags);
762 #else
763         pg = __grab_cache_page(mapping,index);
764 #endif
765
766         *pagep = pg;    
767         if(!pg){
768                 ret =  -ENOMEM;
769                 goto out;
770         }
771         /* Get fs space */
772         space_held = yaffs_hold_space(filp);
773         
774         if(!space_held){
775                 ret = -ENOSPC;
776                 goto out;
777         }
778                 
779         /* Update page if required */
780         
781         if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
782                 ret = yaffs_readpage_nolock(filp, pg);
783         
784         if(ret)
785                 goto out;
786
787         /* Happy path return */
788         T(YAFFS_TRACE_OS, ( "end yaffs_write_begin - ok\n"));
789                 
790         return 0;
791                 
792 out:
793         T(YAFFS_TRACE_OS, ( "end yaffs_write_begin fail returning %d\n",ret));
794         if(space_held){
795                 yaffs_release_space(filp);
796         }
797         if(pg) {
798                 unlock_page(pg);
799                 page_cache_release(pg);
800         }
801         return ret;
802 }
803
804 #else
805
806 static int yaffs_prepare_write(struct file *f, struct page *pg,
807                                unsigned offset, unsigned to)
808 {
809
810         T(YAFFS_TRACE_OS, ( "yaffs_prepair_write\n"));
811         if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
812                 return yaffs_readpage_nolock(f, pg);
813         return 0;
814
815 }
816 #endif
817
818 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
819 static int yaffs_write_end(struct file *filp, struct address_space *mapping,
820                            loff_t pos, unsigned len, unsigned copied,
821                            struct page *pg, void *fsdadata)
822 {
823         int ret = 0;
824         void *addr, *kva;
825         uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE -1); 
826
827
828         
829         kva=kmap(pg);
830         addr = kva + offset_into_page;
831
832         T(YAFFS_TRACE_OS,
833           ( "yaffs_write_end addr %x pos %x nBytes %d\n", (unsigned) addr,
834            (int)pos, copied));
835
836         ret = yaffs_file_write(filp, addr, copied, &pos);
837
838         if (ret != copied) {
839                 T(YAFFS_TRACE_OS,
840                   (
841                    "yaffs_write_end not same size ret %d  copied %d\n",
842                    ret, copied ));
843                 SetPageError(pg);
844                 ClearPageUptodate(pg);
845         } else {
846                 SetPageUptodate(pg);
847         }
848
849         kunmap(pg);
850
851         yaffs_release_space(filp);
852         unlock_page(pg);
853         page_cache_release(pg);
854         return ret;
855 }
856 #else
857
858 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
859                               unsigned to)
860 {
861
862         void *addr, *kva;
863         
864         loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
865         int nBytes = to - offset;
866         int nWritten;
867
868         unsigned spos = pos;
869         unsigned saddr;
870         
871         kva=kmap(pg);
872         addr = kva + offset;
873
874         saddr = (unsigned) addr;
875
876         T(YAFFS_TRACE_OS,
877           ( "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
878            spos, nBytes));
879
880         nWritten = yaffs_file_write(f, addr, nBytes, &pos);
881
882         if (nWritten != nBytes) {
883                 T(YAFFS_TRACE_OS,
884                   (
885                    "yaffs_commit_write not same size nWritten %d  nBytes %d\n",
886                    nWritten, nBytes));
887                 SetPageError(pg);
888                 ClearPageUptodate(pg);
889         } else {
890                 SetPageUptodate(pg);
891         }
892
893         kunmap(pg);
894
895         T(YAFFS_TRACE_OS,
896           ( "yaffs_commit_write returning %d\n",
897            nWritten == nBytes ? 0 : nWritten));
898
899         return nWritten == nBytes ? 0 : nWritten;
900
901 }
902 #endif
903
904
905 static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
906 {
907         if (inode && obj) {
908
909
910                 /* Check mode against the variant type and attempt to repair if broken. */
911                 __u32 mode = obj->yst_mode;
912                 switch( obj->variantType ){
913                 case YAFFS_OBJECT_TYPE_FILE :
914                         if( ! S_ISREG(mode) ){
915                                 obj->yst_mode &= ~S_IFMT;
916                                 obj->yst_mode |= S_IFREG;
917                         }
918
919                         break;
920                 case YAFFS_OBJECT_TYPE_SYMLINK :
921                         if( ! S_ISLNK(mode) ){
922                                 obj->yst_mode &= ~S_IFMT;
923                                 obj->yst_mode |= S_IFLNK;
924                         }
925
926                         break;
927                 case YAFFS_OBJECT_TYPE_DIRECTORY :
928                         if( ! S_ISDIR(mode) ){
929                                 obj->yst_mode &= ~S_IFMT;
930                                 obj->yst_mode |= S_IFDIR;
931                         }
932
933                         break;
934                 case YAFFS_OBJECT_TYPE_UNKNOWN :
935                 case YAFFS_OBJECT_TYPE_HARDLINK :
936                 case YAFFS_OBJECT_TYPE_SPECIAL :
937                 default:
938                         /* TODO? */
939                         break;
940                 }
941
942                 inode->i_flags |= S_NOATIME;
943                 
944                 inode->i_ino = obj->objectId;
945                 inode->i_mode = obj->yst_mode;
946                 inode->i_uid = obj->yst_uid;
947                 inode->i_gid = obj->yst_gid;
948 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
949                 inode->i_blksize = inode->i_sb->s_blocksize;
950 #endif
951 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
952
953                 inode->i_rdev = old_decode_dev(obj->yst_rdev);
954                 inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
955                 inode->i_atime.tv_nsec = 0;
956                 inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
957                 inode->i_mtime.tv_nsec = 0;
958                 inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
959                 inode->i_ctime.tv_nsec = 0;
960 #else
961                 inode->i_rdev = obj->yst_rdev;
962                 inode->i_atime = obj->yst_atime;
963                 inode->i_mtime = obj->yst_mtime;
964                 inode->i_ctime = obj->yst_ctime;
965 #endif
966                 inode->i_size = yaffs_GetObjectFileLength(obj);
967                 inode->i_blocks = (inode->i_size + 511) >> 9;
968
969                 inode->i_nlink = yaffs_GetObjectLinkCount(obj);
970
971                 T(YAFFS_TRACE_OS,
972                   (
973                    "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
974                    inode->i_mode, inode->i_uid, inode->i_gid,
975                    (int)inode->i_size, atomic_read(&inode->i_count)));
976
977                 switch (obj->yst_mode & S_IFMT) {
978                 default:        /* fifo, device or socket */
979 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
980                         init_special_inode(inode, obj->yst_mode,
981                                            old_decode_dev(obj->yst_rdev));
982 #else
983                         init_special_inode(inode, obj->yst_mode,
984                                            (dev_t) (obj->yst_rdev));
985 #endif
986                         break;
987                 case S_IFREG:   /* file */
988                         inode->i_op = &yaffs_file_inode_operations;
989                         inode->i_fop = &yaffs_file_operations;
990                         inode->i_mapping->a_ops =
991                             &yaffs_file_address_operations;
992                         break;
993                 case S_IFDIR:   /* directory */
994                         inode->i_op = &yaffs_dir_inode_operations;
995                         inode->i_fop = &yaffs_dir_operations;
996                         break;
997                 case S_IFLNK:   /* symlink */
998                         inode->i_op = &yaffs_symlink_inode_operations;
999                         break;
1000                 }
1001
1002                 yaffs_InodeToObjectLV(inode) = obj;
1003
1004                 obj->myInode = inode;
1005
1006         } else {
1007                 T(YAFFS_TRACE_OS,
1008                   ( "yaffs_FileInode invalid parameters\n"));
1009         }
1010
1011 }
1012
1013 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1014                               yaffs_Object * obj)
1015 {
1016         struct inode *inode;
1017
1018         if (!sb) {
1019                 T(YAFFS_TRACE_OS,
1020                   ( "yaffs_get_inode for NULL super_block!!\n"));
1021                 return NULL;
1022
1023         }
1024
1025         if (!obj) {
1026                 T(YAFFS_TRACE_OS,
1027                   ( "yaffs_get_inode for NULL object!!\n"));
1028                 return NULL;
1029
1030         }
1031
1032         T(YAFFS_TRACE_OS,
1033           ( "yaffs_get_inode for object %d\n", obj->objectId));
1034
1035         inode = Y_IGET(sb, obj->objectId);
1036         if(IS_ERR(inode))
1037           return NULL;
1038
1039         /* NB Side effect: iget calls back to yaffs_read_inode(). */
1040         /* iget also increments the inode's i_count */
1041         /* NB You can't be holding grossLock or deadlock will happen! */
1042
1043         return inode;
1044 }
1045
1046 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1047                                 loff_t * pos)
1048 {
1049         yaffs_Object *obj;
1050         int nWritten, ipos;
1051         struct inode *inode;
1052         yaffs_Device *dev;
1053
1054         obj = yaffs_DentryToObject(f->f_dentry);
1055
1056         dev = obj->myDev;
1057
1058         yaffs_GrossLock(dev);
1059
1060         inode = f->f_dentry->d_inode;
1061
1062         if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
1063                 ipos = inode->i_size;
1064         } else {
1065                 ipos = *pos;
1066         }
1067
1068         if (!obj) {
1069                 T(YAFFS_TRACE_OS,
1070                   ( "yaffs_file_write: hey obj is null!\n"));
1071         } else {
1072                 T(YAFFS_TRACE_OS,
1073                   (
1074                    "yaffs_file_write about to write writing %zu bytes"
1075                    "to object %d at %d\n",
1076                    n, obj->objectId, ipos));
1077         }
1078
1079         nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
1080
1081         T(YAFFS_TRACE_OS,
1082           ( "yaffs_file_write writing %zu bytes, %d written at %d\n",
1083            n, nWritten, ipos));
1084         if (nWritten > 0) {
1085                 ipos += nWritten;
1086                 *pos = ipos;
1087                 if (ipos > inode->i_size) {
1088                         inode->i_size = ipos;
1089                         inode->i_blocks = (ipos + 511) >> 9;
1090
1091                         T(YAFFS_TRACE_OS,
1092                           (
1093                            "yaffs_file_write size updated to %d bytes, "
1094                            "%d blocks\n",
1095                            ipos, (int)(inode->i_blocks)));
1096                 }
1097
1098         }
1099         yaffs_GrossUnlock(dev);
1100         return nWritten == 0 ? -ENOSPC : nWritten;
1101 }
1102
1103 /* Space holding and freeing is done to ensure we have space available for write_begin/end */
1104 /* For now we just assume few parallel writes and check against a small number. */
1105 /* Todo: need to do this with a counter to handle parallel reads better */
1106
1107 static ssize_t yaffs_hold_space(struct file *f)
1108 {
1109         yaffs_Object *obj;
1110         yaffs_Device *dev;
1111         
1112         int nFreeChunks;
1113
1114         
1115         obj = yaffs_DentryToObject(f->f_dentry);
1116
1117         dev = obj->myDev;
1118
1119         yaffs_GrossLock(dev);
1120
1121         nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
1122         
1123         yaffs_GrossUnlock(dev);
1124
1125         return (nFreeChunks > 20) ? 1 : 0;
1126 }
1127
1128 static void yaffs_release_space(struct file *f)
1129 {
1130         yaffs_Object *obj;
1131         yaffs_Device *dev;
1132         
1133         
1134         obj = yaffs_DentryToObject(f->f_dentry);
1135
1136         dev = obj->myDev;
1137
1138         yaffs_GrossLock(dev);
1139
1140         
1141         yaffs_GrossUnlock(dev);
1142
1143 }
1144
1145 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
1146 {
1147         yaffs_Object *obj;
1148         yaffs_Device *dev;
1149         struct inode *inode = f->f_dentry->d_inode;
1150         unsigned long offset, curoffs;
1151         struct ylist_head *i;
1152         yaffs_Object *l;
1153
1154         char name[YAFFS_MAX_NAME_LENGTH + 1];
1155
1156         obj = yaffs_DentryToObject(f->f_dentry);
1157         dev = obj->myDev;
1158
1159         yaffs_GrossLock(dev);
1160
1161         offset = f->f_pos;
1162
1163         T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
1164
1165         if (offset == 0) {
1166                 T(YAFFS_TRACE_OS,
1167                   ( "yaffs_readdir: entry . ino %d \n",
1168                    (int)inode->i_ino));
1169                 if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
1170                     < 0) {
1171                         goto out;
1172                 }
1173                 offset++;
1174                 f->f_pos++;
1175         }
1176         if (offset == 1) {
1177                 T(YAFFS_TRACE_OS,
1178                   ( "yaffs_readdir: entry .. ino %d \n",
1179                    (int)f->f_dentry->d_parent->d_inode->i_ino));
1180                 if (filldir
1181                     (dirent, "..", 2, offset,
1182                      f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1183                         goto out;
1184                 }
1185                 offset++;
1186                 f->f_pos++;
1187         }
1188
1189         curoffs = 1;
1190
1191         /* If the directory has changed since the open or last call to
1192            readdir, rewind to after the 2 canned entries. */
1193
1194         if (f->f_version != inode->i_version) {
1195                 offset = 2;
1196                 f->f_pos = offset;
1197                 f->f_version = inode->i_version;
1198         }
1199
1200         ylist_for_each(i, &obj->variant.directoryVariant.children) {
1201                 curoffs++;
1202                 if (curoffs >= offset) {
1203                         l = ylist_entry(i, yaffs_Object, siblings);
1204
1205                         yaffs_GetObjectName(l, name,
1206                                             YAFFS_MAX_NAME_LENGTH + 1);
1207                         T(YAFFS_TRACE_OS,
1208                           ( "yaffs_readdir: %s inode %d\n", name,
1209                            yaffs_GetObjectInode(l)));
1210
1211                         if (filldir(dirent,
1212                                     name,
1213                                     strlen(name),
1214                                     offset,
1215                                     yaffs_GetObjectInode(l),
1216                                     yaffs_GetObjectType(l))
1217                             < 0) {
1218                                 goto up_and_out;
1219                         }
1220
1221                         offset++;
1222                         f->f_pos++;
1223                 }
1224         }
1225
1226       up_and_out:
1227       out:
1228
1229         yaffs_GrossUnlock(dev);
1230
1231         return 0;
1232 }
1233
1234 /*
1235  * File creation. Allocate an inode, and we're done..
1236  */
1237  
1238 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
1239 #define YCRED(x) x
1240 #else
1241 #define YCRED(x) x->cred
1242 #endif
1243
1244 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1245 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1246                        dev_t rdev)
1247 #else
1248 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1249                        int rdev)
1250 #endif
1251 {
1252         struct inode *inode;
1253
1254         yaffs_Object *obj = NULL;
1255         yaffs_Device *dev;
1256
1257         yaffs_Object *parent = yaffs_InodeToObject(dir);
1258
1259         int error = -ENOSPC;
1260         uid_t uid = YCRED(current)->fsuid;
1261         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
1262
1263         if((dir->i_mode & S_ISGID) && S_ISDIR(mode))
1264                 mode |= S_ISGID;
1265
1266         if (parent) {
1267                 T(YAFFS_TRACE_OS,
1268                   ( "yaffs_mknod: parent object %d type %d\n",
1269                    parent->objectId, parent->variantType));
1270         } else {
1271                 T(YAFFS_TRACE_OS,
1272                   ( "yaffs_mknod: could not get parent object\n"));
1273                 return -EPERM;
1274         }
1275
1276         T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
1277                            "mode %x dev %x\n",
1278                            dentry->d_name.name, mode, rdev));
1279
1280         dev = parent->myDev;
1281
1282         yaffs_GrossLock(dev);
1283
1284         switch (mode & S_IFMT) {
1285         default:
1286                 /* Special (socket, fifo, device...) */
1287                 T(YAFFS_TRACE_OS, (
1288                                    "yaffs_mknod: making special\n"));
1289 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1290                 obj =
1291                     yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1292                                        gid, old_encode_dev(rdev));
1293 #else
1294                 obj =
1295                     yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1296                                        gid, rdev);
1297 #endif
1298                 break;
1299         case S_IFREG:           /* file          */
1300                 T(YAFFS_TRACE_OS, ( "yaffs_mknod: making file\n"));
1301                 obj =
1302                     yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
1303                                     gid);
1304                 break;
1305         case S_IFDIR:           /* directory */
1306                 T(YAFFS_TRACE_OS,
1307                   ( "yaffs_mknod: making directory\n"));
1308                 obj =
1309                     yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
1310                                          uid, gid);
1311                 break;
1312         case S_IFLNK:           /* symlink */
1313                 T(YAFFS_TRACE_OS, ( "yaffs_mknod: making symlink\n"));
1314                 obj = NULL;     /* Do we ever get here? */
1315                 break;
1316         }
1317
1318         /* Can not call yaffs_get_inode() with gross lock held */
1319         yaffs_GrossUnlock(dev);
1320
1321         if (obj) {
1322                 inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
1323                 d_instantiate(dentry, inode);
1324                 T(YAFFS_TRACE_OS,
1325                   ( "yaffs_mknod created object %d count = %d\n",
1326                    obj->objectId, atomic_read(&inode->i_count)));
1327                 error = 0;
1328         } else {
1329                 T(YAFFS_TRACE_OS,
1330                   ( "yaffs_mknod failed making object\n"));
1331                 error = -ENOMEM;
1332         }
1333
1334         return error;
1335 }
1336
1337 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1338 {
1339         int retVal;
1340         T(YAFFS_TRACE_OS, ( "yaffs_mkdir\n"));
1341         retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1342 #if 0
1343         /* attempt to fix dir bug - didn't work */
1344         if (!retVal) {
1345                 dget(dentry);
1346         }
1347 #endif
1348         return retVal;
1349 }
1350
1351 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1352 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1353                         struct nameidata *n)
1354 #else
1355 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1356 #endif
1357 {
1358         T(YAFFS_TRACE_OS, ( "yaffs_create\n"));
1359         return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1360 }
1361
1362 static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
1363 {
1364         int retVal;
1365
1366         yaffs_Device *dev;
1367
1368         T(YAFFS_TRACE_OS,
1369           ( "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
1370            dentry->d_name.name));
1371
1372         dev = yaffs_InodeToObject(dir)->myDev;
1373
1374         yaffs_GrossLock(dev);
1375
1376         retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
1377
1378         if (retVal == YAFFS_OK) {
1379                 dentry->d_inode->i_nlink--;
1380                 dir->i_version++;
1381                 yaffs_GrossUnlock(dev);
1382                 mark_inode_dirty(dentry->d_inode);
1383                 return 0;
1384         }
1385         yaffs_GrossUnlock(dev);
1386         return -ENOTEMPTY;
1387 }
1388
1389 /*
1390  * Create a link...
1391  */
1392 static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1393                       struct dentry *dentry)
1394 {
1395         struct inode *inode = old_dentry->d_inode;
1396         yaffs_Object *obj = NULL;
1397         yaffs_Object *link = NULL;
1398         yaffs_Device *dev;
1399
1400         T(YAFFS_TRACE_OS, ( "yaffs_link\n"));
1401
1402         obj = yaffs_InodeToObject(inode);
1403         dev = obj->myDev;
1404
1405         yaffs_GrossLock(dev);
1406
1407         if (!S_ISDIR(inode->i_mode))    /* Don't link directories */
1408         {
1409                 link =
1410                     yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
1411                                obj);
1412         }
1413
1414         if (link) {
1415                 old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1416                 d_instantiate(dentry, old_dentry->d_inode);
1417                 atomic_inc(&old_dentry->d_inode->i_count);
1418                 T(YAFFS_TRACE_OS,
1419                   ( "yaffs_link link count %d i_count %d\n",
1420                    old_dentry->d_inode->i_nlink,
1421                    atomic_read(&old_dentry->d_inode->i_count)));
1422
1423         }
1424
1425         yaffs_GrossUnlock(dev);
1426
1427         if (link) {
1428
1429                 return 0;
1430         }
1431
1432         return -EPERM;
1433 }
1434
1435 static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1436                          const char *symname)
1437 {
1438         yaffs_Object *obj;
1439         yaffs_Device *dev;
1440         uid_t uid = YCRED(current)->fsuid;
1441         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
1442
1443         T(YAFFS_TRACE_OS, ( "yaffs_symlink\n"));
1444
1445         dev = yaffs_InodeToObject(dir)->myDev;
1446         yaffs_GrossLock(dev);
1447         obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
1448                                  S_IFLNK | S_IRWXUGO, uid, gid, symname);
1449         yaffs_GrossUnlock(dev);
1450
1451         if (obj) {
1452
1453                 struct inode *inode;
1454
1455                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1456                 d_instantiate(dentry, inode);
1457                 T(YAFFS_TRACE_OS, ( "symlink created OK\n"));
1458                 return 0;
1459         } else {
1460                 T(YAFFS_TRACE_OS, ( "symlink not created\n"));
1461
1462         }
1463
1464         return -ENOMEM;
1465 }
1466
1467 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1468                              int datasync)
1469 {
1470
1471         yaffs_Object *obj;
1472         yaffs_Device *dev;
1473
1474         obj = yaffs_DentryToObject(dentry);
1475
1476         dev = obj->myDev;
1477
1478         T(YAFFS_TRACE_OS, ( "yaffs_sync_object\n"));
1479         yaffs_GrossLock(dev);
1480         yaffs_FlushFile(obj, 1);
1481         yaffs_GrossUnlock(dev);
1482         return 0;
1483 }
1484
1485 /*
1486  * The VFS layer already does all the dentry stuff for rename.
1487  *
1488  * NB: POSIX says you can rename an object over an old object of the same name
1489  */
1490 static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1491                         struct inode *new_dir, struct dentry *new_dentry)
1492 {
1493         yaffs_Device *dev;
1494         int retVal = YAFFS_FAIL;
1495         yaffs_Object *target;
1496
1497         T(YAFFS_TRACE_OS, ( "yaffs_rename\n"));
1498         dev = yaffs_InodeToObject(old_dir)->myDev;
1499
1500         yaffs_GrossLock(dev);
1501
1502         /* Check if the target is an existing directory that is not empty. */
1503         target =
1504             yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
1505                                    new_dentry->d_name.name);
1506
1507
1508
1509         if (target &&
1510             target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1511             !ylist_empty(&target->variant.directoryVariant.children)) {
1512
1513                 T(YAFFS_TRACE_OS, ( "target is non-empty dir\n"));
1514
1515                 retVal = YAFFS_FAIL;
1516         } else {
1517
1518                 /* Now does unlinking internally using shadowing mechanism */
1519                 T(YAFFS_TRACE_OS, ( "calling yaffs_RenameObject\n"));
1520
1521                 retVal =
1522                     yaffs_RenameObject(yaffs_InodeToObject(old_dir),
1523                                        old_dentry->d_name.name,
1524                                        yaffs_InodeToObject(new_dir),
1525                                        new_dentry->d_name.name);
1526
1527         }
1528         yaffs_GrossUnlock(dev);
1529
1530         if (retVal == YAFFS_OK) {
1531                 if(target) {
1532                         new_dentry->d_inode->i_nlink--;
1533                         mark_inode_dirty(new_dentry->d_inode);
1534                 }
1535
1536                 return 0;
1537         } else {
1538                 return -ENOTEMPTY;
1539         }
1540
1541 }
1542
1543 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1544 {
1545         struct inode *inode = dentry->d_inode;
1546         int error;
1547         yaffs_Device *dev;
1548
1549         T(YAFFS_TRACE_OS,
1550           ( "yaffs_setattr of object %d\n",
1551            yaffs_InodeToObject(inode)->objectId));
1552
1553         if ((error = inode_change_ok(inode, attr)) == 0) {
1554
1555                 dev = yaffs_InodeToObject(inode)->myDev;
1556                 yaffs_GrossLock(dev);
1557                 if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
1558                     YAFFS_OK) {
1559                         error = 0;
1560                 } else {
1561                         error = -EPERM;
1562                 }
1563                 yaffs_GrossUnlock(dev);
1564                 if (!error)
1565                         error = inode_setattr(inode, attr);
1566         }
1567         return error;
1568 }
1569
1570 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1571 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
1572 {
1573         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1574         struct super_block *sb = dentry->d_sb;
1575 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1576 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1577 {
1578         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1579 #else
1580 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1581 {
1582         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1583 #endif
1584
1585         T(YAFFS_TRACE_OS, ( "yaffs_statfs\n"));
1586
1587         yaffs_GrossLock(dev);
1588
1589         buf->f_type = YAFFS_MAGIC;
1590         buf->f_bsize = sb->s_blocksize;
1591         buf->f_namelen = 255;
1592         
1593         if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
1594                 /* Do this if chunk size is not a power of 2 */
1595                 
1596                 uint64_t bytesInDev;
1597                 uint64_t bytesFree;
1598
1599                 bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
1600                              ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
1601         
1602                 do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
1603                 buf->f_blocks = bytesInDev;
1604
1605                 bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
1606                              ((uint64_t)(dev->nDataBytesPerChunk));
1607         
1608                 do_div(bytesFree,sb->s_blocksize);
1609         
1610                 buf->f_bfree = bytesFree;
1611         
1612         } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
1613         
1614                 buf->f_blocks =
1615                            (dev->endBlock - dev->startBlock + 1) * 
1616                             dev->nChunksPerBlock / 
1617                             (sb->s_blocksize / dev->nDataBytesPerChunk);
1618                 buf->f_bfree =
1619                            yaffs_GetNumberOfFreeChunks(dev) / 
1620                            (sb->s_blocksize / dev->nDataBytesPerChunk);
1621         } else {
1622                buf->f_blocks =
1623                            (dev->endBlock - dev->startBlock + 1) * 
1624                            dev->nChunksPerBlock * 
1625                            (dev->nDataBytesPerChunk / sb->s_blocksize);
1626                            
1627                        buf->f_bfree =
1628                            yaffs_GetNumberOfFreeChunks(dev) * 
1629                            (dev->nDataBytesPerChunk / sb->s_blocksize);
1630         }
1631         
1632         
1633         buf->f_files = 0;
1634         buf->f_ffree = 0;
1635         buf->f_bavail = buf->f_bfree;
1636
1637         yaffs_GrossUnlock(dev);
1638         return 0;
1639 }
1640
1641
1642 static int yaffs_do_sync_fs(struct super_block *sb)
1643 {
1644
1645         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1646         T(YAFFS_TRACE_OS, ( "yaffs_do_sync_fs\n"));
1647
1648         if(sb->s_dirt) {
1649                 yaffs_GrossLock(dev);
1650
1651                 if(dev){
1652                         yaffs_FlushEntireDeviceCache(dev);
1653                         yaffs_CheckpointSave(dev);
1654                 }
1655
1656                 yaffs_GrossUnlock(dev);
1657
1658                 sb->s_dirt = 0;
1659         }
1660         return 0;
1661 }
1662
1663
1664 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1665 static void yaffs_write_super(struct super_block *sb)
1666 #else
1667 static int yaffs_write_super(struct super_block *sb)
1668 #endif
1669 {
1670
1671         T(YAFFS_TRACE_OS, ( "yaffs_write_super\n"));
1672         if (yaffs_auto_checkpoint >= 2)
1673                 yaffs_do_sync_fs(sb);
1674 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
1675         return 0; 
1676 #endif
1677 }
1678
1679
1680 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1681 static int yaffs_sync_fs(struct super_block *sb, int wait)
1682 #else
1683 static int yaffs_sync_fs(struct super_block *sb)
1684 #endif
1685 {
1686
1687         T(YAFFS_TRACE_OS, ( "yaffs_sync_fs\n"));
1688
1689         if (yaffs_auto_checkpoint >= 1)
1690                 yaffs_do_sync_fs(sb);
1691         
1692         return 0; 
1693
1694 }
1695
1696 #ifdef YAFFS_USE_OWN_IGET
1697
1698 static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino)
1699 {
1700         struct inode *inode;
1701         yaffs_Object *obj;
1702         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1703
1704         T(YAFFS_TRACE_OS,
1705           ( "yaffs_iget for %lu\n", ino));
1706
1707         inode = iget_locked(sb, ino);
1708         if (!inode)
1709                 return ERR_PTR(-ENOMEM);
1710         if (!(inode->i_state & I_NEW))
1711                 return inode;
1712
1713        /* NB This is called as a side effect of other functions, but
1714         * we had to release the lock to prevent deadlocks, so
1715         * need to lock again.
1716         */
1717     
1718         yaffs_GrossLock(dev);
1719
1720         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1721
1722         yaffs_FillInodeFromObject(inode, obj);
1723
1724         yaffs_GrossUnlock(dev);
1725         
1726         unlock_new_inode(inode);
1727         return inode;
1728 }
1729
1730 #else
1731
1732 static void yaffs_read_inode(struct inode *inode)
1733 {
1734         /* NB This is called as a side effect of other functions, but
1735          * we had to release the lock to prevent deadlocks, so
1736          * need to lock again.
1737          */
1738
1739         yaffs_Object *obj;
1740         yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1741
1742         T(YAFFS_TRACE_OS,
1743           ( "yaffs_read_inode for %d\n", (int)inode->i_ino));
1744
1745         yaffs_GrossLock(dev);
1746
1747         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1748
1749         yaffs_FillInodeFromObject(inode, obj);
1750
1751         yaffs_GrossUnlock(dev);
1752 }
1753
1754 #endif
1755
1756 static YLIST_HEAD(yaffs_dev_list);
1757
1758 #if 0 // not used
1759 static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
1760 {
1761         yaffs_Device    *dev = yaffs_SuperToDevice(sb);
1762
1763         if( *flags & MS_RDONLY ) {
1764                 struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1765
1766                 T(YAFFS_TRACE_OS,
1767                         ( "yaffs_remount_fs: %s: RO\n", dev->name ));
1768
1769                 yaffs_GrossLock(dev);
1770
1771                 yaffs_FlushEntireDeviceCache(dev);
1772
1773                 yaffs_CheckpointSave(dev);
1774
1775                 if (mtd->sync)
1776                         mtd->sync(mtd);
1777
1778                 yaffs_GrossUnlock(dev);
1779         }
1780         else {
1781                 T(YAFFS_TRACE_OS,
1782                         ( "yaffs_remount_fs: %s: RW\n", dev->name ));
1783         }
1784
1785         return 0;
1786 }
1787 #endif
1788
1789 static void yaffs_put_super(struct super_block *sb)
1790 {
1791         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1792
1793         T(YAFFS_TRACE_OS, ( "yaffs_put_super\n"));
1794
1795         yaffs_GrossLock(dev);
1796
1797         yaffs_FlushEntireDeviceCache(dev);
1798
1799         yaffs_CheckpointSave(dev);
1800
1801         if (dev->putSuperFunc) {
1802                 dev->putSuperFunc(sb);
1803         }
1804
1805         yaffs_Deinitialise(dev);
1806
1807         yaffs_GrossUnlock(dev);
1808
1809         /* we assume this is protected by lock_kernel() in mount/umount */
1810         ylist_del(&dev->devList);
1811
1812         if(dev->spareBuffer){
1813                 YFREE(dev->spareBuffer);
1814                 dev->spareBuffer = NULL;
1815         }
1816
1817         kfree(dev);
1818 }
1819
1820
1821 static void yaffs_MTDPutSuper(struct super_block *sb)
1822 {
1823
1824         struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1825
1826         if (mtd->sync) {
1827                 mtd->sync(mtd);
1828         }
1829
1830         put_mtd_device(mtd);
1831 }
1832
1833
1834 static void yaffs_MarkSuperBlockDirty(void *vsb)
1835 {
1836         struct super_block *sb = (struct super_block *)vsb;
1837
1838         T(YAFFS_TRACE_OS, ( "yaffs_MarkSuperBlockDirty() sb = %p\n",sb));
1839         if(sb)
1840                 sb->s_dirt = 1;
1841 }
1842
1843 typedef struct {
1844         int inband_tags;
1845         int skip_checkpoint_read;
1846         int skip_checkpoint_write;
1847         int no_cache;
1848 } yaffs_options;
1849
1850 #define MAX_OPT_LEN 20
1851 static int yaffs_parse_options(yaffs_options *options, const char *options_str)
1852 {
1853         char cur_opt[MAX_OPT_LEN+1];
1854         int p;
1855         int error = 0;
1856
1857         /* Parse through the options which is a comma seperated list */
1858
1859         while(options_str && *options_str && !error){
1860                 memset(cur_opt,0,MAX_OPT_LEN+1);
1861                 p = 0;
1862
1863                 while(*options_str && *options_str != ','){
1864                         if(p < MAX_OPT_LEN){
1865                                 cur_opt[p] = *options_str;
1866                                 p++;
1867                         }
1868                         options_str++;
1869                 }
1870
1871                 if(!strcmp(cur_opt,"inband-tags"))
1872                         options->inband_tags = 1;
1873                 else if(!strcmp(cur_opt,"no-cache"))
1874                         options->no_cache = 1;
1875                 else if(!strcmp(cur_opt,"no-checkpoint-read"))
1876                         options->skip_checkpoint_read = 1;
1877                 else if(!strcmp(cur_opt,"no-checkpoint-write"))
1878                         options->skip_checkpoint_write = 1;
1879                 else if(!strcmp(cur_opt,"no-checkpoint")){
1880                         options->skip_checkpoint_read = 1;
1881                         options->skip_checkpoint_write = 1;
1882                 } else {
1883                         printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt);
1884                         error = 1;
1885                 }
1886
1887         }
1888
1889         return error;
1890 }
1891
1892 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
1893                                                      struct super_block *sb,
1894                                                      void *data, int silent)
1895 {
1896         int nBlocks;
1897         struct inode *inode = NULL;
1898         struct dentry *root;
1899         yaffs_Device *dev = 0;
1900         char devname_buf[BDEVNAME_SIZE + 1];
1901         struct mtd_info *mtd;
1902         int err;
1903         char *data_str = (char *)data;
1904
1905         yaffs_options options;
1906
1907         sb->s_magic = YAFFS_MAGIC;
1908         sb->s_op = &yaffs_super_ops;
1909         sb->s_flags |= MS_NOATIME;
1910
1911         if (!sb)
1912                 printk(KERN_INFO "yaffs: sb is NULL\n");
1913         else if (!sb->s_dev)
1914                 printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
1915         else if (!yaffs_devname(sb, devname_buf))
1916                 printk(KERN_INFO "yaffs: devname is NULL\n");
1917         else
1918                 printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
1919                        sb->s_dev,
1920                        yaffs_devname(sb, devname_buf));
1921
1922         if(!data_str)
1923                 data_str = "";
1924
1925         printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str);
1926
1927         memset(&options,0,sizeof(options));
1928
1929         if(yaffs_parse_options(&options,data_str)){
1930                 /* Option parsing failed */
1931                 return NULL;
1932         }
1933
1934
1935         sb->s_blocksize = PAGE_CACHE_SIZE;
1936         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1937         T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
1938         T(YAFFS_TRACE_OS,
1939           ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
1940
1941 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1942         T(YAFFS_TRACE_OS,
1943           ("yaffs: Write verification disabled. All guarantees "
1944            "null and void\n"));
1945 #endif
1946
1947         T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
1948                                "\"%s\"\n",
1949                                MAJOR(sb->s_dev), MINOR(sb->s_dev),
1950                                yaffs_devname(sb, devname_buf)));
1951
1952         /* Check it's an mtd device..... */
1953         if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
1954                 return NULL;    /* This isn't an mtd device */
1955         }
1956         /* Get the device */
1957         mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1958         if (!mtd) {
1959                 T(YAFFS_TRACE_ALWAYS,
1960                   ("yaffs: MTD device #%u doesn't appear to exist\n",
1961                    MINOR(sb->s_dev)));
1962                 return NULL;
1963         }
1964         /* Check it's NAND */
1965         if (mtd->type != MTD_NANDFLASH) {
1966                 T(YAFFS_TRACE_ALWAYS,
1967                   ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
1968                 return NULL;
1969         }
1970
1971         T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
1972         T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
1973         T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
1974         T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
1975         T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
1976         T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
1977         T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
1978         T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
1979         T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
1980         T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
1981 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
1982         T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
1983 #else
1984         T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
1985 #endif
1986
1987 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
1988
1989         if (yaffsVersion == 1 &&
1990             WRITE_SIZE(mtd) >= 2048) {
1991             T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
1992             yaffsVersion = 2;
1993         }
1994
1995         /* Added NCB 26/5/2006 for completeness */
1996         if (yaffsVersion == 2 && 
1997             !options.inband_tags &&
1998             WRITE_SIZE(mtd) == 512){
1999             T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
2000             yaffsVersion = 1;
2001         }
2002
2003 #endif
2004
2005         if (yaffsVersion == 2) {
2006                 /* Check for version 2 style functions */
2007                 if (!mtd->erase ||
2008                     !mtd->block_isbad ||
2009                     !mtd->block_markbad ||
2010                     !mtd->read ||
2011                     !mtd->write ||
2012 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2013                     !mtd->read_oob || !mtd->write_oob) {
2014 #else
2015                     !mtd->write_ecc ||
2016                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2017 #endif
2018                         T(YAFFS_TRACE_ALWAYS,
2019                           ("yaffs: MTD device does not support required "
2020                            "functions\n"));;
2021                         return NULL;
2022                 }
2023
2024                 if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2025                     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
2026                     !options.inband_tags) {
2027                         T(YAFFS_TRACE_ALWAYS,
2028                           ("yaffs: MTD device does not have the "
2029                            "right page sizes\n"));
2030                         return NULL;
2031                 }
2032         } else {
2033                 /* Check for V1 style functions */
2034                 if (!mtd->erase ||
2035                     !mtd->read ||
2036                     !mtd->write ||
2037 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2038                     !mtd->read_oob || !mtd->write_oob) {
2039 #else
2040                     !mtd->write_ecc ||
2041                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2042 #endif
2043                         T(YAFFS_TRACE_ALWAYS,
2044                           ("yaffs: MTD device does not support required "
2045                            "functions\n"));;
2046                         return NULL;
2047                 }
2048
2049                 if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
2050                     mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
2051                         T(YAFFS_TRACE_ALWAYS,
2052                           ("yaffs: MTD device does not support have the "
2053                            "right page sizes\n"));
2054                         return NULL;
2055                 }
2056         }
2057
2058         /* OK, so if we got here, we have an MTD that's NAND and looks
2059          * like it has the right capabilities
2060          * Set the yaffs_Device up for mtd
2061          */
2062
2063 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2064         sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
2065 #else
2066         sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
2067 #endif
2068         if (!dev) {
2069                 /* Deep shit could not allocate device structure */
2070                 T(YAFFS_TRACE_ALWAYS,
2071                   ("yaffs_read_super: Failed trying to allocate "
2072                    "yaffs_Device. \n"));
2073                 return NULL;
2074         }
2075
2076         memset(dev, 0, sizeof(yaffs_Device));
2077         dev->genericDevice = mtd;
2078         dev->name = mtd->name;
2079
2080         /* Set up the memory size parameters.... */
2081
2082         nBlocks = YCALCBLOCKS(mtd->size ,(YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
2083
2084         dev->startBlock = 0;
2085         dev->endBlock = nBlocks - 1;
2086         dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
2087         dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
2088         dev->nReservedBlocks = 5;
2089         dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
2090         dev->inbandTags = options.inband_tags;
2091
2092         /* ... and the functions. */
2093         if (yaffsVersion == 2) {
2094                 dev->writeChunkWithTagsToNAND =
2095                     nandmtd2_WriteChunkWithTagsToNAND;
2096                 dev->readChunkWithTagsFromNAND =
2097                     nandmtd2_ReadChunkWithTagsFromNAND;
2098                 dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
2099                 dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
2100                 dev->spareBuffer = YMALLOC(mtd->oobsize);
2101                 dev->isYaffs2 = 1;
2102 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2103                 dev->totalBytesPerChunk = mtd->writesize;
2104                 dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
2105 #else
2106                 dev->totalBytesPerChunk = mtd->oobblock;
2107                 dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
2108 #endif
2109                 nBlocks = YCALCBLOCKS(mtd->size,mtd->erasesize);
2110
2111                 dev->startBlock = 0;
2112                 dev->endBlock = nBlocks - 1;
2113         } else {
2114 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2115                 /* use the MTD interface in yaffs_mtdif1.c */
2116                 dev->writeChunkWithTagsToNAND =
2117                         nandmtd1_WriteChunkWithTagsToNAND;
2118                 dev->readChunkWithTagsFromNAND =
2119                         nandmtd1_ReadChunkWithTagsFromNAND;
2120                 dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
2121                 dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
2122 #else
2123                 dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
2124                 dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
2125 #endif
2126                 dev->isYaffs2 = 0;
2127         }
2128         /* ... and common functions */
2129         dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
2130         dev->initialiseNAND = nandmtd_InitialiseNAND;
2131
2132         dev->putSuperFunc = yaffs_MTDPutSuper;
2133
2134         dev->superBlock = (void *)sb;
2135         dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
2136
2137
2138 #ifndef CONFIG_YAFFS_DOES_ECC
2139         dev->useNANDECC = 1;
2140 #endif
2141
2142 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
2143         dev->wideTnodesDisabled = 1;
2144 #endif
2145
2146         dev->skipCheckpointRead = options.skip_checkpoint_read;
2147         dev->skipCheckpointWrite = options.skip_checkpoint_write;
2148
2149         /* we assume this is protected by lock_kernel() in mount/umount */
2150         ylist_add_tail(&dev->devList, &yaffs_dev_list);
2151
2152         init_MUTEX(&dev->grossLock);
2153
2154         yaffs_GrossLock(dev);
2155
2156         err = yaffs_GutsInitialise(dev);
2157
2158         T(YAFFS_TRACE_OS,
2159           ("yaffs_read_super: guts initialised %s\n",
2160            (err == YAFFS_OK) ? "OK" : "FAILED"));
2161
2162         /* Release lock before yaffs_get_inode() */
2163         yaffs_GrossUnlock(dev);
2164
2165         /* Create root inode */
2166         if (err == YAFFS_OK)
2167                 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
2168                                         yaffs_Root(dev));
2169
2170         if (!inode)
2171                 return NULL;
2172
2173         inode->i_op = &yaffs_dir_inode_operations;
2174         inode->i_fop = &yaffs_dir_operations;
2175
2176         T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
2177
2178         root = d_alloc_root(inode);
2179
2180         T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
2181
2182         if (!root) {
2183                 iput(inode);
2184                 return NULL;
2185         }
2186         sb->s_root = root;
2187         sb->s_dirt = !dev->isCheckpointed;
2188         T(YAFFS_TRACE_ALWAYS,
2189           ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
2190
2191         T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
2192         return sb;
2193 }
2194
2195
2196 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2197 static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
2198                                          int silent)
2199 {
2200         return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
2201 }
2202
2203 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2204 static int yaffs_read_super(struct file_system_type *fs,
2205                             int flags, const char *dev_name,
2206                             void *data, struct vfsmount *mnt)
2207 {
2208
2209         return get_sb_bdev(fs, flags, dev_name, data,
2210                            yaffs_internal_read_super_mtd, mnt);
2211 }
2212 #else
2213 static struct super_block *yaffs_read_super(struct file_system_type *fs,
2214                                             int flags, const char *dev_name,
2215                                             void *data)
2216 {
2217
2218         return get_sb_bdev(fs, flags, dev_name, data,
2219                            yaffs_internal_read_super_mtd);
2220 }
2221 #endif
2222
2223 static struct file_system_type yaffs_fs_type = {
2224         .owner = THIS_MODULE,
2225         .name = "yaffs",
2226         .get_sb = yaffs_read_super,
2227         .kill_sb = kill_block_super,
2228         .fs_flags = FS_REQUIRES_DEV,
2229 };
2230 #else
2231 static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
2232                                             int silent)
2233 {
2234         return yaffs_internal_read_super(1, sb, data, silent);
2235 }
2236
2237 static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
2238                       FS_REQUIRES_DEV);
2239 #endif
2240
2241
2242 #ifdef CONFIG_YAFFS_YAFFS2
2243
2244 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2245 static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
2246                                           int silent)
2247 {
2248         return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
2249 }
2250
2251 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2252 static int yaffs2_read_super(struct file_system_type *fs,
2253                         int flags, const char *dev_name, void *data,
2254                         struct vfsmount *mnt)
2255 {
2256         return get_sb_bdev(fs, flags, dev_name, data,
2257                         yaffs2_internal_read_super_mtd, mnt);
2258 }
2259 #else
2260 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
2261                                              int flags, const char *dev_name,
2262                                              void *data)
2263 {
2264
2265         return get_sb_bdev(fs, flags, dev_name, data,
2266                            yaffs2_internal_read_super_mtd);
2267 }
2268 #endif
2269
2270 static struct file_system_type yaffs2_fs_type = {
2271         .owner = THIS_MODULE,
2272         .name = "yaffs2",
2273         .get_sb = yaffs2_read_super,
2274         .kill_sb = kill_block_super,
2275         .fs_flags = FS_REQUIRES_DEV,
2276 };
2277 #else
2278 static struct super_block *yaffs2_read_super(struct super_block *sb,
2279                                              void *data, int silent)
2280 {
2281         return yaffs_internal_read_super(2, sb, data, silent);
2282 }
2283
2284 static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
2285                       FS_REQUIRES_DEV);
2286 #endif
2287
2288 #endif                          /* CONFIG_YAFFS_YAFFS2 */
2289
2290 static struct proc_dir_entry *my_proc_entry;
2291
2292 static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
2293 {
2294         buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
2295         buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
2296         buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
2297         buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
2298         buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
2299         buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
2300         buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
2301         buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
2302         buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
2303         buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
2304         buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
2305         buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
2306         buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
2307         buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
2308         buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
2309         buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
2310         buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
2311         buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
2312         buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
2313         buf += sprintf(buf, "passiveGCs......... %d\n",
2314                     dev->passiveGarbageCollections);
2315         buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
2316         buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
2317         buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
2318         buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
2319         buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
2320         buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
2321         buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
2322         buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
2323         buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
2324         buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
2325         buf +=
2326             sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
2327         buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
2328         buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
2329         buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
2330
2331         return buf;
2332 }
2333
2334 static int yaffs_proc_read(char *page,
2335                            char **start,
2336                            off_t offset, int count, int *eof, void *data)
2337 {
2338         struct ylist_head *item;
2339         char *buf = page;
2340         int step = offset;
2341         int n = 0;
2342
2343         /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2344          * We use 'offset' (*ppos) to indicate where we are in devList.
2345          * This also assumes the user has posted a read buffer large
2346          * enough to hold the complete output; but that's life in /proc.
2347          */
2348
2349         *(int *)start = 1;
2350
2351         /* Print header first */
2352         if (step == 0) {
2353                 buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
2354                                "\n%s\n%s\n", yaffs_fs_c_version,
2355                                yaffs_guts_c_version);
2356         }
2357
2358         /* hold lock_kernel while traversing yaffs_dev_list */
2359         lock_kernel();
2360
2361         /* Locate and print the Nth entry.  Order N-squared but N is small. */
2362         ylist_for_each(item, &yaffs_dev_list) {
2363                 yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
2364                 if (n < step) {
2365                         n++;
2366                         continue;
2367                 }
2368                 buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
2369                 buf = yaffs_dump_dev(buf, dev);
2370                 break;
2371         }
2372         unlock_kernel();
2373
2374         return buf - page < count ? buf - page : count;
2375 }
2376
2377 /**
2378  * Set the verbosity of the warnings and error messages.
2379  *
2380  * Note that the names can only be a..z or _ with the current code.
2381  */
2382
2383 static struct {
2384         char *mask_name;
2385         unsigned mask_bitfield;
2386 } mask_flags[] = {
2387         {"allocate", YAFFS_TRACE_ALLOCATE},
2388         {"always", YAFFS_TRACE_ALWAYS},
2389         {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
2390         {"buffers", YAFFS_TRACE_BUFFERS},
2391         {"bug", YAFFS_TRACE_BUG},
2392         {"checkpt", YAFFS_TRACE_CHECKPOINT},
2393         {"deletion", YAFFS_TRACE_DELETION},
2394         {"erase", YAFFS_TRACE_ERASE},
2395         {"error", YAFFS_TRACE_ERROR},
2396         {"gc_detail", YAFFS_TRACE_GC_DETAIL},
2397         {"gc", YAFFS_TRACE_GC},
2398         {"mtd", YAFFS_TRACE_MTD},
2399         {"nandaccess", YAFFS_TRACE_NANDACCESS},
2400         {"os", YAFFS_TRACE_OS},
2401         {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
2402         {"scan", YAFFS_TRACE_SCAN},
2403         {"tracing", YAFFS_TRACE_TRACING},
2404
2405         {"verify", YAFFS_TRACE_VERIFY},
2406         {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
2407         {"verify_full", YAFFS_TRACE_VERIFY_FULL},
2408         {"verify_all", YAFFS_TRACE_VERIFY_ALL},
2409
2410         {"write", YAFFS_TRACE_WRITE},
2411         {"all", 0xffffffff},
2412         {"none", 0},
2413         {NULL, 0},
2414 };
2415
2416 #define MAX_MASK_NAME_LENGTH 40
2417 static int yaffs_proc_write(struct file *file, const char *buf,
2418                                          unsigned long count, void *data)
2419 {
2420         unsigned rg = 0, mask_bitfield;
2421         char *end;
2422         char *mask_name;
2423         const char *x;
2424         char substring[MAX_MASK_NAME_LENGTH+1];
2425         int i;
2426         int done = 0;
2427         int add, len = 0;
2428         int pos = 0;
2429
2430         rg = yaffs_traceMask;
2431
2432         while (!done && (pos < count)) {
2433                 done = 1;
2434                 while ((pos < count) && isspace(buf[pos])) {
2435                         pos++;
2436                 }
2437
2438                 switch (buf[pos]) {
2439                 case '+':
2440                 case '-':
2441                 case '=':
2442                         add = buf[pos];
2443                         pos++;
2444                         break;
2445
2446                 default:
2447                         add = ' ';
2448                         break;
2449                 }
2450                 mask_name = NULL;
2451
2452                 mask_bitfield = simple_strtoul(buf + pos, &end, 0);
2453                 if (end > buf + pos) {
2454                         mask_name = "numeral";
2455                         len = end - (buf + pos);
2456                         pos += len;
2457                         done = 0;
2458                 } else {
2459                         for(x = buf + pos, i = 0;
2460                             (*x == '_' || (*x >='a' && *x <= 'z')) &&
2461                             i <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
2462                             substring[i] = *x;
2463                         substring[i] = '\0';
2464
2465                         for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2466                                 if(strcmp(substring,mask_flags[i].mask_name) == 0){
2467                                         mask_name = mask_flags[i].mask_name;
2468                                         mask_bitfield = mask_flags[i].mask_bitfield;
2469                                         done = 0;
2470                                         break;
2471                                 }
2472                         }
2473                 }
2474
2475                 if (mask_name != NULL) {
2476                         done = 0;
2477                         switch(add) {
2478                         case '-':
2479                                 rg &= ~mask_bitfield;
2480                                 break;
2481                         case '+':
2482                                 rg |= mask_bitfield;
2483                                 break;
2484                         case '=':
2485                                 rg = mask_bitfield;
2486                                 break;
2487                         default:
2488                                 rg |= mask_bitfield;
2489                                 break;
2490                         }
2491                 }
2492         }
2493
2494         yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
2495
2496         printk("new trace = 0x%08X\n",yaffs_traceMask);
2497
2498         if (rg & YAFFS_TRACE_ALWAYS) {
2499                 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2500                         char flag;
2501                         flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
2502                         printk("%c%s\n", flag, mask_flags[i].mask_name);
2503                 }
2504         }
2505
2506         return count;
2507 }
2508
2509 /* Stuff to handle installation of file systems */
2510 struct file_system_to_install {
2511         struct file_system_type *fst;
2512         int installed;
2513 };
2514
2515 static struct file_system_to_install fs_to_install[] = {
2516 //#ifdef CONFIG_YAFFS_YAFFS1
2517         {&yaffs_fs_type, 0},
2518 //#endif
2519 //#ifdef CONFIG_YAFFS_YAFFS2
2520         {&yaffs2_fs_type, 0},
2521 //#endif
2522         {NULL, 0}
2523 };
2524
2525 static int __init init_yaffs_fs(void)
2526 {
2527         int error = 0;
2528         struct file_system_to_install *fsinst;
2529
2530         T(YAFFS_TRACE_ALWAYS,
2531           ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2532
2533         /* Install the proc_fs entry */
2534         my_proc_entry = create_proc_entry("yaffs",
2535                                                S_IRUGO | S_IFREG,
2536                                                YPROC_ROOT);
2537
2538         if (my_proc_entry) {
2539                 my_proc_entry->write_proc = yaffs_proc_write;
2540                 my_proc_entry->read_proc = yaffs_proc_read;
2541                 my_proc_entry->data = NULL;
2542         } else {
2543                 return -ENOMEM;
2544         }
2545
2546         /* Now add the file system entries */
2547
2548         fsinst = fs_to_install;
2549
2550         while (fsinst->fst && !error) {
2551                 error = register_filesystem(fsinst->fst);
2552                 if (!error) {
2553                         fsinst->installed = 1;
2554                 }
2555                 fsinst++;
2556         }
2557
2558         /* Any errors? uninstall  */
2559         if (error) {
2560                 fsinst = fs_to_install;
2561
2562                 while (fsinst->fst) {
2563                         if (fsinst->installed) {
2564                                 unregister_filesystem(fsinst->fst);
2565                                 fsinst->installed = 0;
2566                         }
2567                         fsinst++;
2568                 }
2569         }
2570
2571         return error;
2572 }
2573
2574 static void __exit exit_yaffs_fs(void)
2575 {
2576
2577         struct file_system_to_install *fsinst;
2578
2579         T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
2580                                " removing. \n"));
2581
2582         remove_proc_entry("yaffs", YPROC_ROOT);
2583
2584         fsinst = fs_to_install;
2585
2586         while (fsinst->fst) {
2587                 if (fsinst->installed) {
2588                         unregister_filesystem(fsinst->fst);
2589                         fsinst->installed = 0;
2590                 }
2591                 fsinst++;
2592         }
2593
2594 }
2595
2596 module_init(init_yaffs_fs)
2597 module_exit(exit_yaffs_fs)
2598
2599 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2600 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2601 MODULE_LICENSE("GPL");