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