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