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