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