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