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