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