Cleaner error reporting
[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.93 2010-02-10 03:54:08 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 = 0;
1666         yaffs_Device *dev;
1667
1668         T(YAFFS_TRACE_OS,
1669                 ("yaffs_setattr of object %d\n",
1670                 yaffs_InodeToObject(inode)->objectId));
1671
1672         /* Fail if a requested resize >= 2GB */         
1673         if (attr->ia_valid & ATTR_SIZE &&
1674                 (attr->ia_size >> 31))
1675                 error = -EINVAL;
1676
1677         if (error == 0)
1678                 error = inode_change_ok(inode, attr);
1679         if (error == 0) {
1680                 int result;
1681                 if (!error){
1682                         error = inode_setattr(inode, attr);
1683                         T(YAFFS_TRACE_OS,("inode_setattr called\n"));
1684                         if (attr->ia_valid & ATTR_SIZE)
1685                                 truncate_inode_pages(&inode->i_data,attr->ia_size);
1686                 }
1687                 dev = yaffs_InodeToObject(inode)->myDev;
1688                 if (attr->ia_valid & ATTR_SIZE){
1689                         T(YAFFS_TRACE_OS,("resize to %d(%x)\n",(int)(attr->ia_size),(int)(attr->ia_size)));
1690                 }
1691                 yaffs_GrossLock(dev);
1692                 result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
1693                 if(result == YAFFS_OK) {
1694                         error = 0;
1695                 } else {
1696                         error = -EPERM;
1697                 }
1698                 yaffs_GrossUnlock(dev);
1699
1700         }
1701
1702         T(YAFFS_TRACE_OS,
1703                 ("yaffs_setattr done returning %d\n",error));
1704
1705         return error;
1706 }
1707
1708 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1709 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
1710 {
1711         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1712         struct super_block *sb = dentry->d_sb;
1713 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1714 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1715 {
1716         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1717 #else
1718 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1719 {
1720         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1721 #endif
1722
1723         T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
1724
1725         yaffs_GrossLock(dev);
1726
1727         buf->f_type = YAFFS_MAGIC;
1728         buf->f_bsize = sb->s_blocksize;
1729         buf->f_namelen = 255;
1730
1731         if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
1732                 /* Do this if chunk size is not a power of 2 */
1733
1734                 uint64_t bytesInDev;
1735                 uint64_t bytesFree;
1736
1737                 bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
1738                         ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
1739
1740                 do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
1741                 buf->f_blocks = bytesInDev;
1742
1743                 bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
1744                         ((uint64_t)(dev->nDataBytesPerChunk));
1745
1746                 do_div(bytesFree, sb->s_blocksize);
1747
1748                 buf->f_bfree = bytesFree;
1749
1750         } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
1751
1752                 buf->f_blocks =
1753                         (dev->endBlock - dev->startBlock + 1) *
1754                         dev->nChunksPerBlock /
1755                         (sb->s_blocksize / dev->nDataBytesPerChunk);
1756                 buf->f_bfree =
1757                         yaffs_GetNumberOfFreeChunks(dev) /
1758                         (sb->s_blocksize / dev->nDataBytesPerChunk);
1759         } else {
1760                 buf->f_blocks =
1761                         (dev->endBlock - dev->startBlock + 1) *
1762                         dev->nChunksPerBlock *
1763                         (dev->nDataBytesPerChunk / sb->s_blocksize);
1764
1765                 buf->f_bfree =
1766                         yaffs_GetNumberOfFreeChunks(dev) *
1767                         (dev->nDataBytesPerChunk / sb->s_blocksize);
1768         }
1769
1770         buf->f_files = 0;
1771         buf->f_ffree = 0;
1772         buf->f_bavail = buf->f_bfree;
1773
1774         yaffs_GrossUnlock(dev);
1775         return 0;
1776 }
1777
1778
1779
1780 static void yaffs_flush_sb_inodes(struct super_block *sb)
1781 {
1782         struct inode *iptr;
1783         yaffs_Object *obj;
1784         
1785         list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
1786                 obj = yaffs_InodeToObject(iptr);
1787                 if(obj){
1788                         T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId));
1789                         yaffs_FlushFile(obj,1,0);
1790                 }
1791         }
1792 }
1793
1794 static int yaffs_do_sync_fs(struct super_block *sb)
1795 {
1796
1797         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1798         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_do_sync_fs\n"));
1799
1800         if (sb->s_dirt) {
1801                 yaffs_GrossLock(dev);
1802
1803                 if (dev) {
1804                         yaffs_FlushEntireDeviceCache(dev);
1805                         yaffs_flush_sb_inodes(sb);
1806                         yaffs_CheckpointSave(dev);
1807                 }
1808
1809                 yaffs_GrossUnlock(dev);
1810
1811                 sb->s_dirt = 0;
1812         }
1813         return 0;
1814 }
1815
1816
1817 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1818 static void yaffs_write_super(struct super_block *sb)
1819 #else
1820 static int yaffs_write_super(struct super_block *sb)
1821 #endif
1822 {
1823
1824         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_write_super\n"));
1825         if (yaffs_auto_checkpoint >= 2)
1826                 yaffs_do_sync_fs(sb);
1827 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
1828         return 0;
1829 #endif
1830 }
1831
1832
1833 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
1834 static int yaffs_sync_fs(struct super_block *sb, int wait)
1835 #else
1836 static int yaffs_sync_fs(struct super_block *sb)
1837 #endif
1838 {
1839         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_sync_fs\n"));
1840
1841         if (yaffs_auto_checkpoint >= 1)
1842                 yaffs_do_sync_fs(sb);
1843
1844         return 0;
1845 }
1846
1847 #ifdef YAFFS_USE_OWN_IGET
1848
1849 static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
1850 {
1851         struct inode *inode;
1852         yaffs_Object *obj;
1853         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1854
1855         T(YAFFS_TRACE_OS,
1856                 ("yaffs_iget for %lu\n", ino));
1857
1858         inode = iget_locked(sb, ino);
1859         if (!inode)
1860                 return ERR_PTR(-ENOMEM);
1861         if (!(inode->i_state & I_NEW))
1862                 return inode;
1863
1864         /* NB This is called as a side effect of other functions, but
1865          * we had to release the lock to prevent deadlocks, so
1866          * need to lock again.
1867          */
1868
1869         yaffs_GrossLock(dev);
1870
1871         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1872
1873         yaffs_FillInodeFromObject(inode, obj);
1874
1875         yaffs_GrossUnlock(dev);
1876
1877         unlock_new_inode(inode);
1878         return inode;
1879 }
1880
1881 #else
1882
1883 static void yaffs_read_inode(struct inode *inode)
1884 {
1885         /* NB This is called as a side effect of other functions, but
1886          * we had to release the lock to prevent deadlocks, so
1887          * need to lock again.
1888          */
1889
1890         yaffs_Object *obj;
1891         yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1892
1893         T(YAFFS_TRACE_OS,
1894                 ("yaffs_read_inode for %d\n", (int)inode->i_ino));
1895
1896         yaffs_GrossLock(dev);
1897
1898         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1899
1900         yaffs_FillInodeFromObject(inode, obj);
1901
1902         yaffs_GrossUnlock(dev);
1903 }
1904
1905 #endif
1906
1907 static YLIST_HEAD(yaffs_dev_list);
1908
1909 #if 0 /* not used */
1910 static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
1911 {
1912         yaffs_Device    *dev = yaffs_SuperToDevice(sb);
1913
1914         if (*flags & MS_RDONLY) {
1915                 struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1916
1917                 T(YAFFS_TRACE_OS,
1918                         ("yaffs_remount_fs: %s: RO\n", dev->name));
1919
1920                 yaffs_GrossLock(dev);
1921
1922                 yaffs_FlushEntireDeviceCache(dev);
1923
1924                 yaffs_CheckpointSave(dev);
1925
1926                 if (mtd->sync)
1927                         mtd->sync(mtd);
1928
1929                 yaffs_GrossUnlock(dev);
1930         } else {
1931                 T(YAFFS_TRACE_OS,
1932                         ("yaffs_remount_fs: %s: RW\n", dev->name));
1933         }
1934
1935         return 0;
1936 }
1937 #endif
1938
1939 static void yaffs_put_super(struct super_block *sb)
1940 {
1941         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1942
1943         T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
1944
1945         yaffs_GrossLock(dev);
1946
1947         yaffs_FlushEntireDeviceCache(dev);
1948
1949         yaffs_CheckpointSave(dev);
1950
1951         if (dev->putSuperFunc)
1952                 dev->putSuperFunc(sb);
1953
1954         yaffs_Deinitialise(dev);
1955
1956         yaffs_GrossUnlock(dev);
1957
1958         /* we assume this is protected by lock_kernel() in mount/umount */
1959         ylist_del(&dev->devList);
1960
1961         if (dev->spareBuffer) {
1962                 YFREE(dev->spareBuffer);
1963                 dev->spareBuffer = NULL;
1964         }
1965
1966         kfree(dev);
1967 }
1968
1969
1970 static void yaffs_MTDPutSuper(struct super_block *sb)
1971 {
1972         struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1973
1974         if (mtd->sync)
1975                 mtd->sync(mtd);
1976
1977         put_mtd_device(mtd);
1978 }
1979
1980
1981 static void yaffs_MarkSuperBlockDirty(void *vsb)
1982 {
1983         struct super_block *sb = (struct super_block *)vsb;
1984
1985         T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
1986         if (sb)
1987                 sb->s_dirt = 1;
1988 }
1989
1990 typedef struct {
1991         int inband_tags;
1992         int skip_checkpoint_read;
1993         int skip_checkpoint_write;
1994         int no_cache;
1995         int tags_ecc_on;
1996         int tags_ecc_overridden;
1997         int lazy_loading_enabled;
1998         int lazy_loading_overridden;
1999         int empty_lost_and_found;
2000         int empty_lost_and_found_overridden;
2001 } yaffs_options;
2002
2003 #define MAX_OPT_LEN 30
2004 static int yaffs_parse_options(yaffs_options *options, const char *options_str)
2005 {
2006         char cur_opt[MAX_OPT_LEN + 1];
2007         int p;
2008         int error = 0;
2009
2010         /* Parse through the options which is a comma seperated list */
2011
2012         while (options_str && *options_str && !error) {
2013                 memset(cur_opt, 0, MAX_OPT_LEN + 1);
2014                 p = 0;
2015
2016                 while(*options_str == ',')
2017                         options_str++;
2018
2019                 while (*options_str && *options_str != ',') {
2020                         if (p < MAX_OPT_LEN) {
2021                                 cur_opt[p] = *options_str;
2022                                 p++;
2023                         }
2024                         options_str++;
2025                 }
2026
2027                 if (!strcmp(cur_opt, "inband-tags"))
2028                         options->inband_tags = 1;
2029                 else if (!strcmp(cur_opt, "tags-ecc-off")){
2030                         options->tags_ecc_on = 0;
2031                         options->tags_ecc_overridden=1;
2032                 } else if (!strcmp(cur_opt, "tags-ecc-on")){
2033                         options->tags_ecc_on = 1;
2034                         options->tags_ecc_overridden = 1;
2035                 } else if (!strcmp(cur_opt, "lazy-loading-off")){
2036                         options->lazy_loading_enabled = 0;
2037                         options->lazy_loading_overridden=1;
2038                 } else if (!strcmp(cur_opt, "lazy-loading-on")){
2039                         options->lazy_loading_enabled = 1;
2040                         options->lazy_loading_overridden = 1;
2041                 } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
2042                         options->empty_lost_and_found = 0;
2043                         options->empty_lost_and_found_overridden=1;
2044                 } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
2045                         options->empty_lost_and_found = 1;
2046                         options->empty_lost_and_found_overridden=1;
2047                 } else if (!strcmp(cur_opt, "no-cache"))
2048                         options->no_cache = 1;
2049                 else if (!strcmp(cur_opt, "no-checkpoint-read"))
2050                         options->skip_checkpoint_read = 1;
2051                 else if (!strcmp(cur_opt, "no-checkpoint-write"))
2052                         options->skip_checkpoint_write = 1;
2053                 else if (!strcmp(cur_opt, "no-checkpoint")) {
2054                         options->skip_checkpoint_read = 1;
2055                         options->skip_checkpoint_write = 1;
2056                 } else {
2057                         printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
2058                                         cur_opt);
2059                         error = 1;
2060                 }
2061         }
2062
2063         return error;
2064 }
2065
2066 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
2067                                                 struct super_block *sb,
2068                                                 void *data, int silent)
2069 {
2070         int nBlocks;
2071         struct inode *inode = NULL;
2072         struct dentry *root;
2073         yaffs_Device *dev = 0;
2074         char devname_buf[BDEVNAME_SIZE + 1];
2075         struct mtd_info *mtd;
2076         int err;
2077         char *data_str = (char *)data;
2078
2079         yaffs_options options;
2080
2081         sb->s_magic = YAFFS_MAGIC;
2082         sb->s_op = &yaffs_super_ops;
2083         sb->s_flags |= MS_NOATIME;
2084
2085         if (!sb)
2086                 printk(KERN_INFO "yaffs: sb is NULL\n");
2087         else if (!sb->s_dev)
2088                 printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
2089         else if (!yaffs_devname(sb, devname_buf))
2090                 printk(KERN_INFO "yaffs: devname is NULL\n");
2091         else
2092                 printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
2093                        sb->s_dev,
2094                        yaffs_devname(sb, devname_buf));
2095
2096         if (!data_str)
2097                 data_str = "";
2098
2099         printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
2100
2101         memset(&options, 0, sizeof(options));
2102
2103         if (yaffs_parse_options(&options, data_str)) {
2104                 /* Option parsing failed */
2105                 return NULL;
2106         }
2107
2108
2109         sb->s_blocksize = PAGE_CACHE_SIZE;
2110         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
2111         T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
2112         T(YAFFS_TRACE_OS,
2113           ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
2114
2115 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
2116         T(YAFFS_TRACE_OS,
2117           ("yaffs: Write verification disabled. All guarantees "
2118            "null and void\n"));
2119 #endif
2120
2121         T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
2122                                "\"%s\"\n",
2123                                MAJOR(sb->s_dev), MINOR(sb->s_dev),
2124                                yaffs_devname(sb, devname_buf)));
2125
2126         /* Check it's an mtd device..... */
2127         if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
2128                 return NULL;    /* This isn't an mtd device */
2129
2130         /* Get the device */
2131         mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
2132         if (!mtd) {
2133                 T(YAFFS_TRACE_ALWAYS,
2134                   ("yaffs: MTD device #%u doesn't appear to exist\n",
2135                    MINOR(sb->s_dev)));
2136                 return NULL;
2137         }
2138         /* Check it's NAND */
2139         if (mtd->type != MTD_NANDFLASH) {
2140                 T(YAFFS_TRACE_ALWAYS,
2141                   ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
2142                 return NULL;
2143         }
2144
2145         T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
2146         T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
2147         T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
2148         T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
2149         T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
2150         T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
2151         T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
2152         T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
2153         T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
2154         T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
2155 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2156         T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
2157 #else
2158         T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
2159 #endif
2160
2161 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
2162
2163         if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
2164                 T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
2165                 yaffsVersion = 2;
2166         }
2167
2168         /* Added NCB 26/5/2006 for completeness */
2169         if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
2170                 T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
2171                 yaffsVersion = 1;
2172         }
2173
2174 #endif
2175
2176         if (yaffsVersion == 2) {
2177                 /* Check for version 2 style functions */
2178                 if (!mtd->erase ||
2179                     !mtd->block_isbad ||
2180                     !mtd->block_markbad ||
2181                     !mtd->read ||
2182                     !mtd->write ||
2183 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2184                     !mtd->read_oob || !mtd->write_oob) {
2185 #else
2186                     !mtd->write_ecc ||
2187                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2188 #endif
2189                         T(YAFFS_TRACE_ALWAYS,
2190                           ("yaffs: MTD device does not support required "
2191                            "functions\n"));;
2192                         return NULL;
2193                 }
2194
2195                 if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2196                     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
2197                     !options.inband_tags) {
2198                         T(YAFFS_TRACE_ALWAYS,
2199                           ("yaffs: MTD device does not have the "
2200                            "right page sizes\n"));
2201                         return NULL;
2202                 }
2203         } else {
2204                 /* Check for V1 style functions */
2205                 if (!mtd->erase ||
2206                     !mtd->read ||
2207                     !mtd->write ||
2208 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2209                     !mtd->read_oob || !mtd->write_oob) {
2210 #else
2211                     !mtd->write_ecc ||
2212                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2213 #endif
2214                         T(YAFFS_TRACE_ALWAYS,
2215                           ("yaffs: MTD device does not support required "
2216                            "functions\n"));;
2217                         return NULL;
2218                 }
2219
2220                 if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
2221                     mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
2222                         T(YAFFS_TRACE_ALWAYS,
2223                           ("yaffs: MTD device does not support have the "
2224                            "right page sizes\n"));
2225                         return NULL;
2226                 }
2227         }
2228
2229         /* OK, so if we got here, we have an MTD that's NAND and looks
2230          * like it has the right capabilities
2231          * Set the yaffs_Device up for mtd
2232          */
2233
2234 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2235         sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
2236 #else
2237         sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
2238 #endif
2239         if (!dev) {
2240                 /* Deep shit could not allocate device structure */
2241                 T(YAFFS_TRACE_ALWAYS,
2242                   ("yaffs_read_super: Failed trying to allocate "
2243                    "yaffs_Device. \n"));
2244                 return NULL;
2245         }
2246
2247         memset(dev, 0, sizeof(yaffs_Device));
2248         dev->genericDevice = mtd;
2249         dev->name = mtd->name;
2250
2251         /* Set up the memory size parameters.... */
2252
2253         nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
2254
2255         dev->startBlock = 0;
2256         dev->endBlock = nBlocks - 1;
2257         dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
2258         dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
2259         dev->nReservedBlocks = 5;
2260         dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
2261         dev->inbandTags = options.inband_tags;
2262
2263 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
2264         dev->disableLazyLoad = 1;
2265 #endif
2266         if(options.lazy_loading_overridden)
2267                 dev->disableLazyLoad = !options.lazy_loading_enabled;
2268
2269 #ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
2270         dev->noTagsECC = 1;
2271 #endif
2272         if(options.tags_ecc_overridden)
2273                 dev->noTagsECC = !options.tags_ecc_on;
2274
2275 #ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
2276         dev->emptyLostAndFound = 1;
2277 #endif
2278         if(options.empty_lost_and_found_overridden)
2279                 dev->emptyLostAndFound = options.empty_lost_and_found;
2280
2281         /* ... and the functions. */
2282         if (yaffsVersion == 2) {
2283                 dev->writeChunkWithTagsToNAND =
2284                     nandmtd2_WriteChunkWithTagsToNAND;
2285                 dev->readChunkWithTagsFromNAND =
2286                     nandmtd2_ReadChunkWithTagsFromNAND;
2287                 dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
2288                 dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
2289                 dev->spareBuffer = YMALLOC(mtd->oobsize);
2290                 dev->isYaffs2 = 1;
2291 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2292                 dev->totalBytesPerChunk = mtd->writesize;
2293                 dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
2294 #else
2295                 dev->totalBytesPerChunk = mtd->oobblock;
2296                 dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
2297 #endif
2298                 nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
2299
2300                 dev->startBlock = 0;
2301                 dev->endBlock = nBlocks - 1;
2302         } else {
2303 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2304                 /* use the MTD interface in yaffs_mtdif1.c */
2305                 dev->writeChunkWithTagsToNAND =
2306                         nandmtd1_WriteChunkWithTagsToNAND;
2307                 dev->readChunkWithTagsFromNAND =
2308                         nandmtd1_ReadChunkWithTagsFromNAND;
2309                 dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
2310                 dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
2311 #else
2312                 dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
2313                 dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
2314 #endif
2315                 dev->isYaffs2 = 0;
2316         }
2317         /* ... and common functions */
2318         dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
2319         dev->initialiseNAND = nandmtd_InitialiseNAND;
2320
2321         dev->putSuperFunc = yaffs_MTDPutSuper;
2322
2323         dev->superBlock = (void *)sb;
2324         dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
2325
2326
2327 #ifndef CONFIG_YAFFS_DOES_ECC
2328         dev->useNANDECC = 1;
2329 #endif
2330
2331 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
2332         dev->wideTnodesDisabled = 1;
2333 #endif
2334
2335         dev->skipCheckpointRead = options.skip_checkpoint_read;
2336         dev->skipCheckpointWrite = options.skip_checkpoint_write;
2337
2338         /* we assume this is protected by lock_kernel() in mount/umount */
2339         ylist_add_tail(&dev->devList, &yaffs_dev_list);
2340
2341         /* Directory search handling...*/
2342         YINIT_LIST_HEAD(&dev->searchContexts);
2343         dev->removeObjectCallback = yaffs_RemoveObjectCallback;
2344
2345         init_MUTEX(&dev->grossLock);
2346
2347         yaffs_GrossLock(dev);
2348
2349         err = yaffs_GutsInitialise(dev);
2350
2351         T(YAFFS_TRACE_OS,
2352           ("yaffs_read_super: guts initialised %s\n",
2353            (err == YAFFS_OK) ? "OK" : "FAILED"));
2354
2355         /* Release lock before yaffs_get_inode() */
2356         yaffs_GrossUnlock(dev);
2357
2358         /* Create root inode */
2359         if (err == YAFFS_OK)
2360                 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
2361                                         yaffs_Root(dev));
2362
2363         if (!inode)
2364                 return NULL;
2365
2366         inode->i_op = &yaffs_dir_inode_operations;
2367         inode->i_fop = &yaffs_dir_operations;
2368
2369         T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
2370
2371         root = d_alloc_root(inode);
2372
2373         T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
2374
2375         if (!root) {
2376                 iput(inode);
2377                 return NULL;
2378         }
2379         sb->s_root = root;
2380         sb->s_dirt = !dev->isCheckpointed;
2381         T(YAFFS_TRACE_ALWAYS,
2382           ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
2383
2384         T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
2385         return sb;
2386 }
2387
2388
2389 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2390 static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
2391                                          int silent)
2392 {
2393         return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
2394 }
2395
2396 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2397 static int yaffs_read_super(struct file_system_type *fs,
2398                             int flags, const char *dev_name,
2399                             void *data, struct vfsmount *mnt)
2400 {
2401
2402         return get_sb_bdev(fs, flags, dev_name, data,
2403                            yaffs_internal_read_super_mtd, mnt);
2404 }
2405 #else
2406 static struct super_block *yaffs_read_super(struct file_system_type *fs,
2407                                             int flags, const char *dev_name,
2408                                             void *data)
2409 {
2410
2411         return get_sb_bdev(fs, flags, dev_name, data,
2412                            yaffs_internal_read_super_mtd);
2413 }
2414 #endif
2415
2416 static struct file_system_type yaffs_fs_type = {
2417         .owner = THIS_MODULE,
2418         .name = "yaffs",
2419         .get_sb = yaffs_read_super,
2420         .kill_sb = kill_block_super,
2421         .fs_flags = FS_REQUIRES_DEV,
2422 };
2423 #else
2424 static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
2425                                             int silent)
2426 {
2427         return yaffs_internal_read_super(1, sb, data, silent);
2428 }
2429
2430 static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
2431                       FS_REQUIRES_DEV);
2432 #endif
2433
2434
2435 #ifdef CONFIG_YAFFS_YAFFS2
2436
2437 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2438 static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
2439                                           int silent)
2440 {
2441         return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
2442 }
2443
2444 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2445 static int yaffs2_read_super(struct file_system_type *fs,
2446                         int flags, const char *dev_name, void *data,
2447                         struct vfsmount *mnt)
2448 {
2449         return get_sb_bdev(fs, flags, dev_name, data,
2450                         yaffs2_internal_read_super_mtd, mnt);
2451 }
2452 #else
2453 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
2454                                              int flags, const char *dev_name,
2455                                              void *data)
2456 {
2457
2458         return get_sb_bdev(fs, flags, dev_name, data,
2459                            yaffs2_internal_read_super_mtd);
2460 }
2461 #endif
2462
2463 static struct file_system_type yaffs2_fs_type = {
2464         .owner = THIS_MODULE,
2465         .name = "yaffs2",
2466         .get_sb = yaffs2_read_super,
2467         .kill_sb = kill_block_super,
2468         .fs_flags = FS_REQUIRES_DEV,
2469 };
2470 #else
2471 static struct super_block *yaffs2_read_super(struct super_block *sb,
2472                                              void *data, int silent)
2473 {
2474         return yaffs_internal_read_super(2, sb, data, silent);
2475 }
2476
2477 static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
2478                       FS_REQUIRES_DEV);
2479 #endif
2480
2481 #endif                          /* CONFIG_YAFFS_YAFFS2 */
2482
2483 static struct proc_dir_entry *my_proc_entry;
2484
2485 static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
2486 {
2487         buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
2488         buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
2489         buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
2490         buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
2491         buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
2492         buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
2493         buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
2494         buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
2495         buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
2496         buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
2497         buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
2498         buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
2499         buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
2500         buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
2501         buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
2502         buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
2503         buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
2504         buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
2505         buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
2506         buf += sprintf(buf, "passiveGCs......... %d\n",
2507                     dev->passiveGarbageCollections);
2508         buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
2509         buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
2510         buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
2511         buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
2512         buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
2513         buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
2514         buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
2515         buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
2516         buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
2517         buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
2518         buf +=
2519             sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
2520
2521         return buf;
2522 }
2523
2524
2525 static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
2526 {
2527         buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
2528         buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC);
2529         buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
2530         buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
2531         buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->emptyLostAndFound);
2532         buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->disableLazyLoad);
2533
2534         return buf;
2535 }
2536
2537 static int yaffs_proc_read(char *page,
2538                            char **start,
2539                            off_t offset, int count, int *eof, void *data)
2540 {
2541         struct ylist_head *item;
2542         char *buf = page;
2543         int step = offset;
2544         int n = 0;
2545
2546         /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2547          * We use 'offset' (*ppos) to indicate where we are in devList.
2548          * This also assumes the user has posted a read buffer large
2549          * enough to hold the complete output; but that's life in /proc.
2550          */
2551
2552         *(int *)start = 1;
2553
2554         /* Print header first */
2555         if (step == 0)
2556                 buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
2557                                "\n%s\n%s\n", yaffs_fs_c_version,
2558                                yaffs_guts_c_version);
2559         else if (step == 1)
2560                 buf += sprintf(buf,"\n");
2561         else {
2562                 step-=2;
2563                 
2564                 /* hold lock_kernel while traversing yaffs_dev_list */
2565                 lock_kernel();
2566
2567                 /* Locate and print the Nth entry.  Order N-squared but N is small. */
2568                 ylist_for_each(item, &yaffs_dev_list) {
2569                         yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
2570                         if (n < (step & ~1)) {
2571                                 n+=2;
2572                                 continue;
2573                         }
2574                         if((step & 1)==0){
2575                                 buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
2576                                 buf = yaffs_dump_dev_part0(buf, dev);
2577                         } else
2578                                 buf = yaffs_dump_dev_part1(buf, dev);
2579                         
2580                         break;
2581                 }
2582                 unlock_kernel();
2583         }
2584
2585         return buf - page < count ? buf - page : count;
2586 }
2587
2588 /**
2589  * Set the verbosity of the warnings and error messages.
2590  *
2591  * Note that the names can only be a..z or _ with the current code.
2592  */
2593
2594 static struct {
2595         char *mask_name;
2596         unsigned mask_bitfield;
2597 } mask_flags[] = {
2598         {"allocate", YAFFS_TRACE_ALLOCATE},
2599         {"always", YAFFS_TRACE_ALWAYS},
2600         {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
2601         {"buffers", YAFFS_TRACE_BUFFERS},
2602         {"bug", YAFFS_TRACE_BUG},
2603         {"checkpt", YAFFS_TRACE_CHECKPOINT},
2604         {"deletion", YAFFS_TRACE_DELETION},
2605         {"erase", YAFFS_TRACE_ERASE},
2606         {"error", YAFFS_TRACE_ERROR},
2607         {"gc_detail", YAFFS_TRACE_GC_DETAIL},
2608         {"gc", YAFFS_TRACE_GC},
2609         {"mtd", YAFFS_TRACE_MTD},
2610         {"nandaccess", YAFFS_TRACE_NANDACCESS},
2611         {"os", YAFFS_TRACE_OS},
2612         {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
2613         {"scan", YAFFS_TRACE_SCAN},
2614         {"tracing", YAFFS_TRACE_TRACING},
2615         {"sync", YAFFS_TRACE_SYNC},
2616
2617         {"verify", YAFFS_TRACE_VERIFY},
2618         {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
2619         {"verify_full", YAFFS_TRACE_VERIFY_FULL},
2620         {"verify_all", YAFFS_TRACE_VERIFY_ALL},
2621
2622         {"write", YAFFS_TRACE_WRITE},
2623         {"all", 0xffffffff},
2624         {"none", 0},
2625         {NULL, 0},
2626 };
2627
2628 #define MAX_MASK_NAME_LENGTH 40
2629 static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
2630                                          unsigned long count, void *data)
2631 {
2632         unsigned rg = 0, mask_bitfield;
2633         char *end;
2634         char *mask_name;
2635         const char *x;
2636         char substring[MAX_MASK_NAME_LENGTH + 1];
2637         int i;
2638         int done = 0;
2639         int add, len = 0;
2640         int pos = 0;
2641
2642         rg = yaffs_traceMask;
2643
2644         while (!done && (pos < count)) {
2645                 done = 1;
2646                 while ((pos < count) && isspace(buf[pos]))
2647                         pos++;
2648
2649                 switch (buf[pos]) {
2650                 case '+':
2651                 case '-':
2652                 case '=':
2653                         add = buf[pos];
2654                         pos++;
2655                         break;
2656
2657                 default:
2658                         add = ' ';
2659                         break;
2660                 }
2661                 mask_name = NULL;
2662
2663                 mask_bitfield = simple_strtoul(buf + pos, &end, 0);
2664
2665                 if (end > buf + pos) {
2666                         mask_name = "numeral";
2667                         len = end - (buf + pos);
2668                         pos += len;
2669                         done = 0;
2670                 } else {
2671                         for (x = buf + pos, i = 0;
2672                             (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
2673                             i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
2674                                 substring[i] = *x;
2675                         substring[i] = '\0';
2676
2677                         for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2678                                 if (strcmp(substring, mask_flags[i].mask_name) == 0) {
2679                                         mask_name = mask_flags[i].mask_name;
2680                                         mask_bitfield = mask_flags[i].mask_bitfield;
2681                                         done = 0;
2682                                         break;
2683                                 }
2684                         }
2685                 }
2686
2687                 if (mask_name != NULL) {
2688                         done = 0;
2689                         switch (add) {
2690                         case '-':
2691                                 rg &= ~mask_bitfield;
2692                                 break;
2693                         case '+':
2694                                 rg |= mask_bitfield;
2695                                 break;
2696                         case '=':
2697                                 rg = mask_bitfield;
2698                                 break;
2699                         default:
2700                                 rg |= mask_bitfield;
2701                                 break;
2702                         }
2703                 }
2704         }
2705
2706         yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
2707
2708         printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
2709
2710         if (rg & YAFFS_TRACE_ALWAYS) {
2711                 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2712                         char flag;
2713                         flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
2714                         printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
2715                 }
2716         }
2717
2718         return count;
2719 }
2720
2721
2722 static int yaffs_proc_write(struct file *file, const char *buf,
2723                                          unsigned long count, void *data)
2724 {
2725         return yaffs_proc_write_trace_options(file, buf, count, data);
2726 }
2727
2728 /* Stuff to handle installation of file systems */
2729 struct file_system_to_install {
2730         struct file_system_type *fst;
2731         int installed;
2732 };
2733
2734 static struct file_system_to_install fs_to_install[] = {
2735         {&yaffs_fs_type, 0},
2736         {&yaffs2_fs_type, 0},
2737         {NULL, 0}
2738 };
2739
2740 static int __init init_yaffs_fs(void)
2741 {
2742         int error = 0;
2743         struct file_system_to_install *fsinst;
2744
2745         T(YAFFS_TRACE_ALWAYS,
2746           ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2747
2748         /* Install the proc_fs entry */
2749         my_proc_entry = create_proc_entry("yaffs",
2750                                                S_IRUGO | S_IFREG,
2751                                                YPROC_ROOT);
2752
2753         if (my_proc_entry) {
2754                 my_proc_entry->write_proc = yaffs_proc_write;
2755                 my_proc_entry->read_proc = yaffs_proc_read;
2756                 my_proc_entry->data = NULL;
2757         } else
2758                 return -ENOMEM;
2759
2760         /* Now add the file system entries */
2761
2762         fsinst = fs_to_install;
2763
2764         while (fsinst->fst && !error) {
2765                 error = register_filesystem(fsinst->fst);
2766                 if (!error)
2767                         fsinst->installed = 1;
2768                 fsinst++;
2769         }
2770
2771         /* Any errors? uninstall  */
2772         if (error) {
2773                 fsinst = fs_to_install;
2774
2775                 while (fsinst->fst) {
2776                         if (fsinst->installed) {
2777                                 unregister_filesystem(fsinst->fst);
2778                                 fsinst->installed = 0;
2779                         }
2780                         fsinst++;
2781                 }
2782         }
2783
2784         return error;
2785 }
2786
2787 static void __exit exit_yaffs_fs(void)
2788 {
2789
2790         struct file_system_to_install *fsinst;
2791
2792         T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
2793                                " removing. \n"));
2794
2795         remove_proc_entry("yaffs", YPROC_ROOT);
2796
2797         fsinst = fs_to_install;
2798
2799         while (fsinst->fst) {
2800                 if (fsinst->installed) {
2801                         unregister_filesystem(fsinst->fst);
2802                         fsinst->installed = 0;
2803                 }
2804                 fsinst++;
2805         }
2806 }
2807
2808 module_init(init_yaffs_fs)
2809 module_exit(exit_yaffs_fs)
2810
2811 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2812 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2813 MODULE_LICENSE("GPL");