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