2d0f8a068ef0755038db472a9068e4aee4944f9a
[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.68 2008-07-23 03:35:12 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 = page_address(pg) + offset;
718         loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
719         int nBytes = to - offset;
720         int nWritten;
721
722         unsigned spos = pos;
723         unsigned saddr = (unsigned)addr;
724
725         T(YAFFS_TRACE_OS,
726           (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
727            spos, nBytes));
728
729         nWritten = yaffs_file_write(f, addr, nBytes, &pos);
730
731         if (nWritten != nBytes) {
732                 T(YAFFS_TRACE_OS,
733                   (KERN_DEBUG
734                    "yaffs_commit_write not same size nWritten %d  nBytes %d\n",
735                    nWritten, nBytes));
736                 SetPageError(pg);
737                 ClearPageUptodate(pg);
738         } else {
739                 SetPageUptodate(pg);
740         }
741
742         T(YAFFS_TRACE_OS,
743           (KERN_DEBUG "yaffs_commit_write returning %d\n",
744            nWritten == nBytes ? 0 : nWritten));
745
746         return nWritten == nBytes ? 0 : nWritten;
747
748 }
749
750 static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
751 {
752         if (inode && obj) {
753
754
755                 /* Check mode against the variant type and attempt to repair if broken. */
756                 __u32 mode = obj->yst_mode;
757                 switch( obj->variantType ){
758                 case YAFFS_OBJECT_TYPE_FILE :
759                         if( ! S_ISREG(mode) ){
760                                 obj->yst_mode &= ~S_IFMT;
761                                 obj->yst_mode |= S_IFREG;
762                         }
763
764                         break;
765                 case YAFFS_OBJECT_TYPE_SYMLINK :
766                         if( ! S_ISLNK(mode) ){
767                                 obj->yst_mode &= ~S_IFMT;
768                                 obj->yst_mode |= S_IFLNK;
769                         }
770
771                         break;
772                 case YAFFS_OBJECT_TYPE_DIRECTORY :
773                         if( ! S_ISDIR(mode) ){
774                                 obj->yst_mode &= ~S_IFMT;
775                                 obj->yst_mode |= S_IFDIR;
776                         }
777
778                         break;
779                 case YAFFS_OBJECT_TYPE_UNKNOWN :
780                 case YAFFS_OBJECT_TYPE_HARDLINK :
781                 case YAFFS_OBJECT_TYPE_SPECIAL :
782                 default:
783                         /* TODO? */
784                         break;
785                 }
786
787                 inode->i_flags |= S_NOATIME;
788                 
789                 inode->i_ino = obj->objectId;
790                 inode->i_mode = obj->yst_mode;
791                 inode->i_uid = obj->yst_uid;
792                 inode->i_gid = obj->yst_gid;
793 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
794                 inode->i_blksize = inode->i_sb->s_blocksize;
795 #endif
796 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
797
798                 inode->i_rdev = old_decode_dev(obj->yst_rdev);
799                 inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
800                 inode->i_atime.tv_nsec = 0;
801                 inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
802                 inode->i_mtime.tv_nsec = 0;
803                 inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
804                 inode->i_ctime.tv_nsec = 0;
805 #else
806                 inode->i_rdev = obj->yst_rdev;
807                 inode->i_atime = obj->yst_atime;
808                 inode->i_mtime = obj->yst_mtime;
809                 inode->i_ctime = obj->yst_ctime;
810 #endif
811                 inode->i_size = yaffs_GetObjectFileLength(obj);
812                 inode->i_blocks = (inode->i_size + 511) >> 9;
813
814                 inode->i_nlink = yaffs_GetObjectLinkCount(obj);
815
816                 T(YAFFS_TRACE_OS,
817                   (KERN_DEBUG
818                    "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
819                    inode->i_mode, inode->i_uid, inode->i_gid,
820                    (int)inode->i_size, atomic_read(&inode->i_count)));
821
822                 switch (obj->yst_mode & S_IFMT) {
823                 default:        /* fifo, device or socket */
824 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
825                         init_special_inode(inode, obj->yst_mode,
826                                            old_decode_dev(obj->yst_rdev));
827 #else
828                         init_special_inode(inode, obj->yst_mode,
829                                            (dev_t) (obj->yst_rdev));
830 #endif
831                         break;
832                 case S_IFREG:   /* file */
833                         inode->i_op = &yaffs_file_inode_operations;
834                         inode->i_fop = &yaffs_file_operations;
835                         inode->i_mapping->a_ops =
836                             &yaffs_file_address_operations;
837                         break;
838                 case S_IFDIR:   /* directory */
839                         inode->i_op = &yaffs_dir_inode_operations;
840                         inode->i_fop = &yaffs_dir_operations;
841                         break;
842                 case S_IFLNK:   /* symlink */
843                         inode->i_op = &yaffs_symlink_inode_operations;
844                         break;
845                 }
846
847                 yaffs_InodeToObjectLV(inode) = obj;
848
849                 obj->myInode = inode;
850
851         } else {
852                 T(YAFFS_TRACE_OS,
853                   (KERN_DEBUG "yaffs_FileInode invalid parameters\n"));
854         }
855
856 }
857
858 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
859                               yaffs_Object * obj)
860 {
861         struct inode *inode;
862
863         if (!sb) {
864                 T(YAFFS_TRACE_OS,
865                   (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n"));
866                 return NULL;
867
868         }
869
870         if (!obj) {
871                 T(YAFFS_TRACE_OS,
872                   (KERN_DEBUG "yaffs_get_inode for NULL object!!\n"));
873                 return NULL;
874
875         }
876
877         T(YAFFS_TRACE_OS,
878           (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
879
880         inode = Y_IGET(sb, obj->objectId);
881         if(IS_ERR(inode))
882           return NULL;
883
884         /* NB Side effect: iget calls back to yaffs_read_inode(). */
885         /* iget also increments the inode's i_count */
886         /* NB You can't be holding grossLock or deadlock will happen! */
887
888         return inode;
889 }
890
891 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
892                                 loff_t * pos)
893 {
894         yaffs_Object *obj;
895         int nWritten, ipos;
896         struct inode *inode;
897         yaffs_Device *dev;
898
899         obj = yaffs_DentryToObject(f->f_dentry);
900
901         dev = obj->myDev;
902
903         yaffs_GrossLock(dev);
904
905         inode = f->f_dentry->d_inode;
906
907         if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
908                 ipos = inode->i_size;
909         } else {
910                 ipos = *pos;
911         }
912
913         if (!obj) {
914                 T(YAFFS_TRACE_OS,
915                   (KERN_DEBUG "yaffs_file_write: hey obj is null!\n"));
916         } else {
917                 T(YAFFS_TRACE_OS,
918                   (KERN_DEBUG
919                    "yaffs_file_write about to write writing %d bytes"
920                    "to object %d at %d\n",
921                    n, obj->objectId, ipos));
922         }
923
924         nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
925
926         T(YAFFS_TRACE_OS,
927           (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n",
928            n, nWritten, ipos));
929         if (nWritten > 0) {
930                 ipos += nWritten;
931                 *pos = ipos;
932                 if (ipos > inode->i_size) {
933                         inode->i_size = ipos;
934                         inode->i_blocks = (ipos + 511) >> 9;
935
936                         T(YAFFS_TRACE_OS,
937                           (KERN_DEBUG
938                            "yaffs_file_write size updated to %d bytes, "
939                            "%d blocks\n",
940                            ipos, (int)(inode->i_blocks)));
941                 }
942
943         }
944         yaffs_GrossUnlock(dev);
945         return nWritten == 0 ? -ENOSPC : nWritten;
946 }
947
948 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
949 {
950         yaffs_Object *obj;
951         yaffs_Device *dev;
952         struct inode *inode = f->f_dentry->d_inode;
953         unsigned long offset, curoffs;
954         struct ylist_head *i;
955         yaffs_Object *l;
956
957         char name[YAFFS_MAX_NAME_LENGTH + 1];
958
959         obj = yaffs_DentryToObject(f->f_dentry);
960         dev = obj->myDev;
961
962         yaffs_GrossLock(dev);
963
964         offset = f->f_pos;
965
966         T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
967
968         if (offset == 0) {
969                 T(YAFFS_TRACE_OS,
970                   (KERN_DEBUG "yaffs_readdir: entry . ino %d \n",
971                    (int)inode->i_ino));
972                 if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
973                     < 0) {
974                         goto out;
975                 }
976                 offset++;
977                 f->f_pos++;
978         }
979         if (offset == 1) {
980                 T(YAFFS_TRACE_OS,
981                   (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n",
982                    (int)f->f_dentry->d_parent->d_inode->i_ino));
983                 if (filldir
984                     (dirent, "..", 2, offset,
985                      f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
986                         goto out;
987                 }
988                 offset++;
989                 f->f_pos++;
990         }
991
992         curoffs = 1;
993
994         /* If the directory has changed since the open or last call to
995            readdir, rewind to after the 2 canned entries. */
996
997         if (f->f_version != inode->i_version) {
998                 offset = 2;
999                 f->f_pos = offset;
1000                 f->f_version = inode->i_version;
1001         }
1002
1003         ylist_for_each(i, &obj->variant.directoryVariant.children) {
1004                 curoffs++;
1005                 if (curoffs >= offset) {
1006                         l = ylist_entry(i, yaffs_Object, siblings);
1007
1008                         yaffs_GetObjectName(l, name,
1009                                             YAFFS_MAX_NAME_LENGTH + 1);
1010                         T(YAFFS_TRACE_OS,
1011                           (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
1012                            yaffs_GetObjectInode(l)));
1013
1014                         if (filldir(dirent,
1015                                     name,
1016                                     strlen(name),
1017                                     offset,
1018                                     yaffs_GetObjectInode(l),
1019                                     yaffs_GetObjectType(l))
1020                             < 0) {
1021                                 goto up_and_out;
1022                         }
1023
1024                         offset++;
1025                         f->f_pos++;
1026                 }
1027         }
1028
1029       up_and_out:
1030       out:
1031
1032         yaffs_GrossUnlock(dev);
1033
1034         return 0;
1035 }
1036
1037 /*
1038  * File creation. Allocate an inode, and we're done..
1039  */
1040 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1041 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1042                        dev_t rdev)
1043 #else
1044 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1045                        int rdev)
1046 #endif
1047 {
1048         struct inode *inode;
1049
1050         yaffs_Object *obj = NULL;
1051         yaffs_Device *dev;
1052
1053         yaffs_Object *parent = yaffs_InodeToObject(dir);
1054
1055         int error = -ENOSPC;
1056         uid_t uid = current->fsuid;
1057         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1058
1059         if((dir->i_mode & S_ISGID) && S_ISDIR(mode))
1060                 mode |= S_ISGID;
1061
1062         if (parent) {
1063                 T(YAFFS_TRACE_OS,
1064                   (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n",
1065                    parent->objectId, parent->variantType));
1066         } else {
1067                 T(YAFFS_TRACE_OS,
1068                   (KERN_DEBUG "yaffs_mknod: could not get parent object\n"));
1069                 return -EPERM;
1070         }
1071
1072         T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
1073                            "mode %x dev %x\n",
1074                            dentry->d_name.name, mode, rdev));
1075
1076         dev = parent->myDev;
1077
1078         yaffs_GrossLock(dev);
1079
1080         switch (mode & S_IFMT) {
1081         default:
1082                 /* Special (socket, fifo, device...) */
1083                 T(YAFFS_TRACE_OS, (KERN_DEBUG
1084                                    "yaffs_mknod: making special\n"));
1085 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1086                 obj =
1087                     yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1088                                        gid, old_encode_dev(rdev));
1089 #else
1090                 obj =
1091                     yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1092                                        gid, rdev);
1093 #endif
1094                 break;
1095         case S_IFREG:           /* file          */
1096                 T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
1097                 obj =
1098                     yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
1099                                     gid);
1100                 break;
1101         case S_IFDIR:           /* directory */
1102                 T(YAFFS_TRACE_OS,
1103                   (KERN_DEBUG "yaffs_mknod: making directory\n"));
1104                 obj =
1105                     yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
1106                                          uid, gid);
1107                 break;
1108         case S_IFLNK:           /* symlink */
1109                 T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
1110                 obj = NULL;     /* Do we ever get here? */
1111                 break;
1112         }
1113
1114         /* Can not call yaffs_get_inode() with gross lock held */
1115         yaffs_GrossUnlock(dev);
1116
1117         if (obj) {
1118                 inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
1119                 d_instantiate(dentry, inode);
1120                 T(YAFFS_TRACE_OS,
1121                   (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
1122                    obj->objectId, atomic_read(&inode->i_count)));
1123                 error = 0;
1124         } else {
1125                 T(YAFFS_TRACE_OS,
1126                   (KERN_DEBUG "yaffs_mknod failed making object\n"));
1127                 error = -ENOMEM;
1128         }
1129
1130         return error;
1131 }
1132
1133 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1134 {
1135         int retVal;
1136         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
1137         retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1138 #if 0
1139         /* attempt to fix dir bug - didn't work */
1140         if (!retVal) {
1141                 dget(dentry);
1142         }
1143 #endif
1144         return retVal;
1145 }
1146
1147 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1148 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1149                         struct nameidata *n)
1150 #else
1151 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1152 #endif
1153 {
1154         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
1155         return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1156 }
1157
1158 static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
1159 {
1160         int retVal;
1161
1162         yaffs_Device *dev;
1163
1164         T(YAFFS_TRACE_OS,
1165           (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
1166            dentry->d_name.name));
1167
1168         dev = yaffs_InodeToObject(dir)->myDev;
1169
1170         yaffs_GrossLock(dev);
1171
1172         retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
1173
1174         if (retVal == YAFFS_OK) {
1175                 dentry->d_inode->i_nlink--;
1176                 dir->i_version++;
1177                 yaffs_GrossUnlock(dev);
1178                 mark_inode_dirty(dentry->d_inode);
1179                 return 0;
1180         }
1181         yaffs_GrossUnlock(dev);
1182         return -ENOTEMPTY;
1183 }
1184
1185 /*
1186  * Create a link...
1187  */
1188 static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1189                       struct dentry *dentry)
1190 {
1191         struct inode *inode = old_dentry->d_inode;
1192         yaffs_Object *obj = NULL;
1193         yaffs_Object *link = NULL;
1194         yaffs_Device *dev;
1195
1196         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n"));
1197
1198         obj = yaffs_InodeToObject(inode);
1199         dev = obj->myDev;
1200
1201         yaffs_GrossLock(dev);
1202
1203         if (!S_ISDIR(inode->i_mode))    /* Don't link directories */
1204         {
1205                 link =
1206                     yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
1207                                obj);
1208         }
1209
1210         if (link) {
1211                 old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1212                 d_instantiate(dentry, old_dentry->d_inode);
1213                 atomic_inc(&old_dentry->d_inode->i_count);
1214                 T(YAFFS_TRACE_OS,
1215                   (KERN_DEBUG "yaffs_link link count %d i_count %d\n",
1216                    old_dentry->d_inode->i_nlink,
1217                    atomic_read(&old_dentry->d_inode->i_count)));
1218
1219         }
1220
1221         yaffs_GrossUnlock(dev);
1222
1223         if (link) {
1224
1225                 return 0;
1226         }
1227
1228         return -EPERM;
1229 }
1230
1231 static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1232                          const char *symname)
1233 {
1234         yaffs_Object *obj;
1235         yaffs_Device *dev;
1236         uid_t uid = current->fsuid;
1237         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1238
1239         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n"));
1240
1241         dev = yaffs_InodeToObject(dir)->myDev;
1242         yaffs_GrossLock(dev);
1243         obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
1244                                  S_IFLNK | S_IRWXUGO, uid, gid, symname);
1245         yaffs_GrossUnlock(dev);
1246
1247         if (obj) {
1248
1249                 struct inode *inode;
1250
1251                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1252                 d_instantiate(dentry, inode);
1253                 T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n"));
1254                 return 0;
1255         } else {
1256                 T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n"));
1257
1258         }
1259
1260         return -ENOMEM;
1261 }
1262
1263 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1264                              int datasync)
1265 {
1266
1267         yaffs_Object *obj;
1268         yaffs_Device *dev;
1269
1270         obj = yaffs_DentryToObject(dentry);
1271
1272         dev = obj->myDev;
1273
1274         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n"));
1275         yaffs_GrossLock(dev);
1276         yaffs_FlushFile(obj, 1);
1277         yaffs_GrossUnlock(dev);
1278         return 0;
1279 }
1280
1281 /*
1282  * The VFS layer already does all the dentry stuff for rename.
1283  *
1284  * NB: POSIX says you can rename an object over an old object of the same name
1285  */
1286 static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1287                         struct inode *new_dir, struct dentry *new_dentry)
1288 {
1289         yaffs_Device *dev;
1290         int retVal = YAFFS_FAIL;
1291         yaffs_Object *target;
1292
1293         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n"));
1294         dev = yaffs_InodeToObject(old_dir)->myDev;
1295
1296         yaffs_GrossLock(dev);
1297
1298         /* Check if the target is an existing directory that is not empty. */
1299         target =
1300             yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
1301                                    new_dentry->d_name.name);
1302
1303
1304
1305         if (target &&
1306             target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1307             !ylist_empty(&target->variant.directoryVariant.children)) {
1308
1309                 T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
1310
1311                 retVal = YAFFS_FAIL;
1312         } else {
1313
1314                 /* Now does unlinking internally using shadowing mechanism */
1315                 T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n"));
1316
1317                 retVal =
1318                     yaffs_RenameObject(yaffs_InodeToObject(old_dir),
1319                                        old_dentry->d_name.name,
1320                                        yaffs_InodeToObject(new_dir),
1321                                        new_dentry->d_name.name);
1322
1323         }
1324         yaffs_GrossUnlock(dev);
1325
1326         if (retVal == YAFFS_OK) {
1327                 if(target) {
1328                         new_dentry->d_inode->i_nlink--;
1329                         mark_inode_dirty(new_dentry->d_inode);
1330                 }
1331
1332                 return 0;
1333         } else {
1334                 return -ENOTEMPTY;
1335         }
1336
1337 }
1338
1339 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1340 {
1341         struct inode *inode = dentry->d_inode;
1342         int error;
1343         yaffs_Device *dev;
1344
1345         T(YAFFS_TRACE_OS,
1346           (KERN_DEBUG "yaffs_setattr of object %d\n",
1347            yaffs_InodeToObject(inode)->objectId));
1348
1349         if ((error = inode_change_ok(inode, attr)) == 0) {
1350
1351                 dev = yaffs_InodeToObject(inode)->myDev;
1352                 yaffs_GrossLock(dev);
1353                 if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
1354                     YAFFS_OK) {
1355                         error = 0;
1356                 } else {
1357                         error = -EPERM;
1358                 }
1359                 yaffs_GrossUnlock(dev);
1360                 if (!error)
1361                         error = inode_setattr(inode, attr);
1362         }
1363         return error;
1364 }
1365
1366 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1367 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
1368 {
1369         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1370         struct super_block *sb = dentry->d_sb;
1371 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1372 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1373 {
1374         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1375 #else
1376 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1377 {
1378         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1379 #endif
1380
1381         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
1382
1383         yaffs_GrossLock(dev);
1384
1385         buf->f_type = YAFFS_MAGIC;
1386         buf->f_bsize = sb->s_blocksize;
1387         buf->f_namelen = 255;
1388         
1389         if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
1390                 /* Do this if chunk size is not a power of 2 */
1391                 
1392                 uint64_t bytesInDev;
1393                 uint64_t bytesFree;
1394
1395                 bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
1396                              ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
1397         
1398                 do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
1399                 buf->f_blocks = bytesInDev;
1400
1401                 bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
1402                              ((uint64_t)(dev->nDataBytesPerChunk));
1403         
1404                 do_div(bytesFree,sb->s_blocksize);
1405         
1406                 buf->f_bfree = bytesFree;
1407         
1408         } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
1409         
1410                 buf->f_blocks =
1411                            (dev->endBlock - dev->startBlock + 1) * 
1412                             dev->nChunksPerBlock / 
1413                             (sb->s_blocksize / dev->nDataBytesPerChunk);
1414                 buf->f_bfree =
1415                            yaffs_GetNumberOfFreeChunks(dev) / 
1416                            (sb->s_blocksize / dev->nDataBytesPerChunk);
1417         } else {
1418                buf->f_blocks =
1419                            (dev->endBlock - dev->startBlock + 1) * 
1420                            dev->nChunksPerBlock * 
1421                            (dev->nDataBytesPerChunk / sb->s_blocksize);
1422                            
1423                        buf->f_bfree =
1424                            yaffs_GetNumberOfFreeChunks(dev) * 
1425                            (dev->nDataBytesPerChunk / sb->s_blocksize);
1426         }
1427         
1428         
1429         buf->f_files = 0;
1430         buf->f_ffree = 0;
1431         buf->f_bavail = buf->f_bfree;
1432
1433         yaffs_GrossUnlock(dev);
1434         return 0;
1435 }
1436
1437
1438 static int yaffs_do_sync_fs(struct super_block *sb)
1439 {
1440
1441         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1442         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
1443
1444         if(sb->s_dirt) {
1445                 yaffs_GrossLock(dev);
1446
1447                 if(dev){
1448                         yaffs_FlushEntireDeviceCache(dev);
1449                         yaffs_CheckpointSave(dev);
1450                 }
1451
1452                 yaffs_GrossUnlock(dev);
1453
1454                 sb->s_dirt = 0;
1455         }
1456         return 0;
1457 }
1458
1459
1460 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1461 static void yaffs_write_super(struct super_block *sb)
1462 #else
1463 static int yaffs_write_super(struct super_block *sb)
1464 #endif
1465 {
1466
1467         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
1468         yaffs_do_sync_fs(sb);
1469 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
1470         return 0; 
1471 #endif
1472 }
1473
1474
1475 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1476 static int yaffs_sync_fs(struct super_block *sb, int wait)
1477 #else
1478 static int yaffs_sync_fs(struct super_block *sb)
1479 #endif
1480 {
1481
1482         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
1483
1484         yaffs_do_sync_fs(sb);
1485         
1486         return 0; 
1487
1488 }
1489
1490 #ifdef YAFFS_USE_OWN_IGET
1491
1492 static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino)
1493 {
1494         struct inode *inode;
1495         yaffs_Object *obj;
1496         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1497
1498         T(YAFFS_TRACE_OS,
1499           (KERN_DEBUG "yaffs_iget for %lu\n", ino));
1500
1501         inode = iget_locked(sb, ino);
1502         if (!inode)
1503                 return ERR_PTR(-ENOMEM);
1504         if (!(inode->i_state & I_NEW))
1505                 return inode;
1506
1507        /* NB This is called as a side effect of other functions, but
1508         * we had to release the lock to prevent deadlocks, so
1509         * need to lock again.
1510         */
1511     
1512         yaffs_GrossLock(dev);
1513
1514         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1515
1516         yaffs_FillInodeFromObject(inode, obj);
1517
1518         yaffs_GrossUnlock(dev);
1519         
1520         unlock_new_inode(inode);
1521         return inode;
1522 }
1523
1524 #else
1525
1526 static void yaffs_read_inode(struct inode *inode)
1527 {
1528         /* NB This is called as a side effect of other functions, but
1529          * we had to release the lock to prevent deadlocks, so
1530          * need to lock again.
1531          */
1532
1533         yaffs_Object *obj;
1534         yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1535
1536         T(YAFFS_TRACE_OS,
1537           (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino));
1538
1539         yaffs_GrossLock(dev);
1540
1541         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1542
1543         yaffs_FillInodeFromObject(inode, obj);
1544
1545         yaffs_GrossUnlock(dev);
1546 }
1547
1548 #endif
1549
1550 static YLIST_HEAD(yaffs_dev_list);
1551
1552 #if 0 // not used
1553 static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
1554 {
1555         yaffs_Device    *dev = yaffs_SuperToDevice(sb);
1556
1557         if( *flags & MS_RDONLY ) {
1558                 struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1559
1560                 T(YAFFS_TRACE_OS,
1561                         (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name ));
1562
1563                 yaffs_GrossLock(dev);
1564
1565                 yaffs_FlushEntireDeviceCache(dev);
1566
1567                 yaffs_CheckpointSave(dev);
1568
1569                 if (mtd->sync)
1570                         mtd->sync(mtd);
1571
1572                 yaffs_GrossUnlock(dev);
1573         }
1574         else {
1575                 T(YAFFS_TRACE_OS,
1576                         (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name ));
1577         }
1578
1579         return 0;
1580 }
1581 #endif
1582
1583 static void yaffs_put_super(struct super_block *sb)
1584 {
1585         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1586
1587         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n"));
1588
1589         yaffs_GrossLock(dev);
1590
1591         yaffs_FlushEntireDeviceCache(dev);
1592
1593         yaffs_CheckpointSave(dev);
1594
1595         if (dev->putSuperFunc) {
1596                 dev->putSuperFunc(sb);
1597         }
1598
1599         yaffs_Deinitialise(dev);
1600
1601         yaffs_GrossUnlock(dev);
1602
1603         /* we assume this is protected by lock_kernel() in mount/umount */
1604         ylist_del(&dev->devList);
1605
1606         if(dev->spareBuffer){
1607                 YFREE(dev->spareBuffer);
1608                 dev->spareBuffer = NULL;
1609         }
1610
1611         kfree(dev);
1612 }
1613
1614
1615 static void yaffs_MTDPutSuper(struct super_block *sb)
1616 {
1617
1618         struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1619
1620         if (mtd->sync) {
1621                 mtd->sync(mtd);
1622         }
1623
1624         put_mtd_device(mtd);
1625 }
1626
1627
1628 static void yaffs_MarkSuperBlockDirty(void *vsb)
1629 {
1630         struct super_block *sb = (struct super_block *)vsb;
1631
1632         T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb));
1633 //      if(sb)
1634 //              sb->s_dirt = 1;
1635 }
1636
1637 typedef struct {
1638         int inband_tags;
1639         int skip_checkpoint_read;
1640         int skip_checkpoint_write;
1641         int no_cache;
1642 } yaffs_options;
1643
1644 #define MAX_OPT_LEN 20
1645 static int yaffs_parse_options(yaffs_options *options, const char *options_str)
1646 {
1647         char cur_opt[MAX_OPT_LEN+1];
1648         int p;
1649         int error = 0;
1650
1651         /* Parse through the options which is a comma seperated list */
1652
1653         while(options_str && *options_str && !error){
1654                 memset(cur_opt,0,MAX_OPT_LEN+1);
1655                 p = 0;
1656
1657                 while(*options_str && *options_str != ','){
1658                         if(p < MAX_OPT_LEN){
1659                                 cur_opt[p] = *options_str;
1660                                 p++;
1661                         }
1662                         options_str++;
1663                 }
1664
1665                 if(!strcmp(cur_opt,"inband-tags"))
1666                         options->inband_tags = 1;
1667                 else if(!strcmp(cur_opt,"no-cache"))
1668                         options->no_cache = 1;
1669                 else if(!strcmp(cur_opt,"no-checkpoint-read"))
1670                         options->skip_checkpoint_read = 1;
1671                 else if(!strcmp(cur_opt,"no-checkpoint-write"))
1672                         options->skip_checkpoint_write = 1;
1673                 else if(!strcmp(cur_opt,"no-checkpoint")){
1674                         options->skip_checkpoint_read = 1;
1675                         options->skip_checkpoint_write = 1;
1676                 } else {
1677                         printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt);
1678                         error = 1;
1679                 }
1680
1681         }
1682
1683         return error;
1684 }
1685
1686 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
1687                                                      struct super_block *sb,
1688                                                      void *data, int silent)
1689 {
1690         int nBlocks;
1691         struct inode *inode = NULL;
1692         struct dentry *root;
1693         yaffs_Device *dev = 0;
1694         char devname_buf[BDEVNAME_SIZE + 1];
1695         struct mtd_info *mtd;
1696         int err;
1697         char *data_str = (char *)data;
1698
1699         yaffs_options options;
1700
1701         sb->s_magic = YAFFS_MAGIC;
1702         sb->s_op = &yaffs_super_ops;
1703         sb->s_flags |= MS_NOATIME;
1704
1705         if (!sb)
1706                 printk(KERN_INFO "yaffs: sb is NULL\n");
1707         else if (!sb->s_dev)
1708                 printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
1709         else if (!yaffs_devname(sb, devname_buf))
1710                 printk(KERN_INFO "yaffs: devname is NULL\n");
1711         else
1712                 printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
1713                        sb->s_dev,
1714                        yaffs_devname(sb, devname_buf));
1715
1716         if(!data_str)
1717                 data_str = "";
1718
1719         printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str);
1720
1721         memset(&options,0,sizeof(options));
1722
1723         if(yaffs_parse_options(&options,data_str)){
1724                 /* Option parsing failed */
1725                 return NULL;
1726         }
1727
1728
1729         sb->s_blocksize = PAGE_CACHE_SIZE;
1730         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1731         T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
1732         T(YAFFS_TRACE_OS,
1733           ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
1734
1735 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1736         T(YAFFS_TRACE_OS,
1737           ("yaffs: Write verification disabled. All guarantees "
1738            "null and void\n"));
1739 #endif
1740
1741         T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
1742                                "\"%s\"\n",
1743                                MAJOR(sb->s_dev), MINOR(sb->s_dev),
1744                                yaffs_devname(sb, devname_buf)));
1745
1746         /* Check it's an mtd device..... */
1747         if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
1748                 return NULL;    /* This isn't an mtd device */
1749         }
1750         /* Get the device */
1751         mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1752         if (!mtd) {
1753                 T(YAFFS_TRACE_ALWAYS,
1754                   ("yaffs: MTD device #%u doesn't appear to exist\n",
1755                    MINOR(sb->s_dev)));
1756                 return NULL;
1757         }
1758         /* Check it's NAND */
1759         if (mtd->type != MTD_NANDFLASH) {
1760                 T(YAFFS_TRACE_ALWAYS,
1761                   ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
1762                 return NULL;
1763         }
1764
1765         T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
1766         T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
1767         T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
1768         T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
1769         T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
1770         T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
1771         T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
1772         T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
1773         T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
1774         T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
1775         T(YAFFS_TRACE_OS, (" size %d\n", mtd->size));
1776
1777 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
1778
1779         if (yaffsVersion == 1 &&
1780             WRITE_SIZE(mtd) >= 2048) {
1781             T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
1782             yaffsVersion = 2;
1783         }
1784
1785         /* Added NCB 26/5/2006 for completeness */
1786         if (yaffsVersion == 2 && 
1787             !options.inband_tags &&
1788             WRITE_SIZE(mtd) == 512){
1789             T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
1790             yaffsVersion = 1;
1791         }
1792
1793 #endif
1794
1795         if (yaffsVersion == 2) {
1796                 /* Check for version 2 style functions */
1797                 if (!mtd->erase ||
1798                     !mtd->block_isbad ||
1799                     !mtd->block_markbad ||
1800                     !mtd->read ||
1801                     !mtd->write ||
1802 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1803                     !mtd->read_oob || !mtd->write_oob) {
1804 #else
1805                     !mtd->write_ecc ||
1806                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
1807 #endif
1808                         T(YAFFS_TRACE_ALWAYS,
1809                           ("yaffs: MTD device does not support required "
1810                            "functions\n"));;
1811                         return NULL;
1812                 }
1813
1814                 if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
1815                     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
1816                     !options.inband_tags) {
1817                         T(YAFFS_TRACE_ALWAYS,
1818                           ("yaffs: MTD device does not have the "
1819                            "right page sizes\n"));
1820                         return NULL;
1821                 }
1822         } else {
1823                 /* Check for V1 style functions */
1824                 if (!mtd->erase ||
1825                     !mtd->read ||
1826                     !mtd->write ||
1827 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1828                     !mtd->read_oob || !mtd->write_oob) {
1829 #else
1830                     !mtd->write_ecc ||
1831                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
1832 #endif
1833                         T(YAFFS_TRACE_ALWAYS,
1834                           ("yaffs: MTD device does not support required "
1835                            "functions\n"));;
1836                         return NULL;
1837                 }
1838
1839                 if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
1840                     mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
1841                         T(YAFFS_TRACE_ALWAYS,
1842                           ("yaffs: MTD device does not support have the "
1843                            "right page sizes\n"));
1844                         return NULL;
1845                 }
1846         }
1847
1848         /* OK, so if we got here, we have an MTD that's NAND and looks
1849          * like it has the right capabilities
1850          * Set the yaffs_Device up for mtd
1851          */
1852
1853 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1854         sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
1855 #else
1856         sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
1857 #endif
1858         if (!dev) {
1859                 /* Deep shit could not allocate device structure */
1860                 T(YAFFS_TRACE_ALWAYS,
1861                   ("yaffs_read_super: Failed trying to allocate "
1862                    "yaffs_Device. \n"));
1863                 return NULL;
1864         }
1865
1866         memset(dev, 0, sizeof(yaffs_Device));
1867         dev->genericDevice = mtd;
1868         dev->name = mtd->name;
1869
1870         /* Set up the memory size parameters.... */
1871
1872         nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
1873         dev->startBlock = 0;
1874         dev->endBlock = nBlocks - 1;
1875         dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
1876         dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
1877         dev->nReservedBlocks = 5;
1878         dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
1879         dev->inbandTags = options.inband_tags;
1880
1881         /* ... and the functions. */
1882         if (yaffsVersion == 2) {
1883                 dev->writeChunkWithTagsToNAND =
1884                     nandmtd2_WriteChunkWithTagsToNAND;
1885                 dev->readChunkWithTagsFromNAND =
1886                     nandmtd2_ReadChunkWithTagsFromNAND;
1887                 dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
1888                 dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
1889                 dev->spareBuffer = YMALLOC(mtd->oobsize);
1890                 dev->isYaffs2 = 1;
1891 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1892                 dev->totalBytesPerChunk = mtd->writesize;
1893                 dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
1894 #else
1895                 dev->totalBytesPerChunk = mtd->oobblock;
1896                 dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
1897 #endif
1898                 nBlocks = mtd->size / mtd->erasesize;
1899
1900                 dev->startBlock = 0;
1901                 dev->endBlock = nBlocks - 1;
1902         } else {
1903 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1904                 /* use the MTD interface in yaffs_mtdif1.c */
1905                 dev->writeChunkWithTagsToNAND =
1906                         nandmtd1_WriteChunkWithTagsToNAND;
1907                 dev->readChunkWithTagsFromNAND =
1908                         nandmtd1_ReadChunkWithTagsFromNAND;
1909                 dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
1910                 dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
1911 #else
1912                 dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
1913                 dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
1914 #endif
1915                 dev->isYaffs2 = 0;
1916         }
1917         /* ... and common functions */
1918         dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
1919         dev->initialiseNAND = nandmtd_InitialiseNAND;
1920
1921         dev->putSuperFunc = yaffs_MTDPutSuper;
1922
1923         dev->superBlock = (void *)sb;
1924         dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
1925
1926
1927 #ifndef CONFIG_YAFFS_DOES_ECC
1928         dev->useNANDECC = 1;
1929 #endif
1930
1931 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
1932         dev->wideTnodesDisabled = 1;
1933 #endif
1934
1935         dev->skipCheckpointRead = options.skip_checkpoint_read;
1936         dev->skipCheckpointWrite = options.skip_checkpoint_write;
1937
1938         /* we assume this is protected by lock_kernel() in mount/umount */
1939         ylist_add_tail(&dev->devList, &yaffs_dev_list);
1940
1941         init_MUTEX(&dev->grossLock);
1942
1943         yaffs_GrossLock(dev);
1944
1945         err = yaffs_GutsInitialise(dev);
1946
1947         T(YAFFS_TRACE_OS,
1948           ("yaffs_read_super: guts initialised %s\n",
1949            (err == YAFFS_OK) ? "OK" : "FAILED"));
1950
1951         /* Release lock before yaffs_get_inode() */
1952         yaffs_GrossUnlock(dev);
1953
1954         /* Create root inode */
1955         if (err == YAFFS_OK)
1956                 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
1957                                         yaffs_Root(dev));
1958
1959         if (!inode)
1960                 return NULL;
1961
1962         inode->i_op = &yaffs_dir_inode_operations;
1963         inode->i_fop = &yaffs_dir_operations;
1964
1965         T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
1966
1967         root = d_alloc_root(inode);
1968
1969         T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
1970
1971         if (!root) {
1972                 iput(inode);
1973                 return NULL;
1974         }
1975         sb->s_root = root;
1976
1977         T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
1978         return sb;
1979 }
1980
1981
1982 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1983 static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
1984                                          int silent)
1985 {
1986         return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
1987 }
1988
1989 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1990 static int yaffs_read_super(struct file_system_type *fs,
1991                             int flags, const char *dev_name,
1992                             void *data, struct vfsmount *mnt)
1993 {
1994
1995         return get_sb_bdev(fs, flags, dev_name, data,
1996                            yaffs_internal_read_super_mtd, mnt);
1997 }
1998 #else
1999 static struct super_block *yaffs_read_super(struct file_system_type *fs,
2000                                             int flags, const char *dev_name,
2001                                             void *data)
2002 {
2003
2004         return get_sb_bdev(fs, flags, dev_name, data,
2005                            yaffs_internal_read_super_mtd);
2006 }
2007 #endif
2008
2009 static struct file_system_type yaffs_fs_type = {
2010         .owner = THIS_MODULE,
2011         .name = "yaffs",
2012         .get_sb = yaffs_read_super,
2013         .kill_sb = kill_block_super,
2014         .fs_flags = FS_REQUIRES_DEV,
2015 };
2016 #else
2017 static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
2018                                             int silent)
2019 {
2020         return yaffs_internal_read_super(1, sb, data, silent);
2021 }
2022
2023 static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
2024                       FS_REQUIRES_DEV);
2025 #endif
2026
2027
2028 #ifdef CONFIG_YAFFS_YAFFS2
2029
2030 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2031 static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
2032                                           int silent)
2033 {
2034         return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
2035 }
2036
2037 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2038 static int yaffs2_read_super(struct file_system_type *fs,
2039                         int flags, const char *dev_name, void *data,
2040                         struct vfsmount *mnt)
2041 {
2042         return get_sb_bdev(fs, flags, dev_name, data,
2043                         yaffs2_internal_read_super_mtd, mnt);
2044 }
2045 #else
2046 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
2047                                              int flags, const char *dev_name,
2048                                              void *data)
2049 {
2050
2051         return get_sb_bdev(fs, flags, dev_name, data,
2052                            yaffs2_internal_read_super_mtd);
2053 }
2054 #endif
2055
2056 static struct file_system_type yaffs2_fs_type = {
2057         .owner = THIS_MODULE,
2058         .name = "yaffs2",
2059         .get_sb = yaffs2_read_super,
2060         .kill_sb = kill_block_super,
2061         .fs_flags = FS_REQUIRES_DEV,
2062 };
2063 #else
2064 static struct super_block *yaffs2_read_super(struct super_block *sb,
2065                                              void *data, int silent)
2066 {
2067         return yaffs_internal_read_super(2, sb, data, silent);
2068 }
2069
2070 static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
2071                       FS_REQUIRES_DEV);
2072 #endif
2073
2074 #endif                          /* CONFIG_YAFFS_YAFFS2 */
2075
2076 static struct proc_dir_entry *my_proc_entry;
2077
2078 static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
2079 {
2080         buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
2081         buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
2082         buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
2083         buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
2084         buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
2085         buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
2086         buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
2087         buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
2088         buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
2089         buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
2090         buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
2091         buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
2092         buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
2093         buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
2094         buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
2095         buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
2096         buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
2097         buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
2098         buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
2099         buf += sprintf(buf, "passiveGCs......... %d\n",
2100                     dev->passiveGarbageCollections);
2101         buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
2102         buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
2103         buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
2104         buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
2105         buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
2106         buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
2107         buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
2108         buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
2109         buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
2110         buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
2111         buf +=
2112             sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
2113         buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
2114         buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
2115         buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
2116
2117         return buf;
2118 }
2119
2120 static int yaffs_proc_read(char *page,
2121                            char **start,
2122                            off_t offset, int count, int *eof, void *data)
2123 {
2124         struct ylist_head *item;
2125         char *buf = page;
2126         int step = offset;
2127         int n = 0;
2128
2129         /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2130          * We use 'offset' (*ppos) to indicate where we are in devList.
2131          * This also assumes the user has posted a read buffer large
2132          * enough to hold the complete output; but that's life in /proc.
2133          */
2134
2135         *(int *)start = 1;
2136
2137         /* Print header first */
2138         if (step == 0) {
2139                 buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
2140                                "\n%s\n%s\n", yaffs_fs_c_version,
2141                                yaffs_guts_c_version);
2142         }
2143
2144         /* hold lock_kernel while traversing yaffs_dev_list */
2145         lock_kernel();
2146
2147         /* Locate and print the Nth entry.  Order N-squared but N is small. */
2148         ylist_for_each(item, &yaffs_dev_list) {
2149                 yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
2150                 if (n < step) {
2151                         n++;
2152                         continue;
2153                 }
2154                 buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
2155                 buf = yaffs_dump_dev(buf, dev);
2156                 break;
2157         }
2158         unlock_kernel();
2159
2160         return buf - page < count ? buf - page : count;
2161 }
2162
2163 /**
2164  * Set the verbosity of the warnings and error messages.
2165  *
2166  * Note that the names can only be a..z or _ with the current code.
2167  */
2168
2169 static struct {
2170         char *mask_name;
2171         unsigned mask_bitfield;
2172 } mask_flags[] = {
2173         {"allocate", YAFFS_TRACE_ALLOCATE},
2174         {"always", YAFFS_TRACE_ALWAYS},
2175         {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
2176         {"buffers", YAFFS_TRACE_BUFFERS},
2177         {"bug", YAFFS_TRACE_BUG},
2178         {"checkpt", YAFFS_TRACE_CHECKPOINT},
2179         {"deletion", YAFFS_TRACE_DELETION},
2180         {"erase", YAFFS_TRACE_ERASE},
2181         {"error", YAFFS_TRACE_ERROR},
2182         {"gc_detail", YAFFS_TRACE_GC_DETAIL},
2183         {"gc", YAFFS_TRACE_GC},
2184         {"mtd", YAFFS_TRACE_MTD},
2185         {"nandaccess", YAFFS_TRACE_NANDACCESS},
2186         {"os", YAFFS_TRACE_OS},
2187         {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
2188         {"scan", YAFFS_TRACE_SCAN},
2189         {"tracing", YAFFS_TRACE_TRACING},
2190
2191         {"verify", YAFFS_TRACE_VERIFY},
2192         {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
2193         {"verify_full", YAFFS_TRACE_VERIFY_FULL},
2194         {"verify_all", YAFFS_TRACE_VERIFY_ALL},
2195
2196         {"write", YAFFS_TRACE_WRITE},
2197         {"all", 0xffffffff},
2198         {"none", 0},
2199         {NULL, 0},
2200 };
2201
2202 #define MAX_MASK_NAME_LENGTH 40
2203 static int yaffs_proc_write(struct file *file, const char *buf,
2204                                          unsigned long count, void *data)
2205 {
2206         unsigned rg = 0, mask_bitfield;
2207         char *end;
2208         char *mask_name;
2209         const char *x;
2210         char substring[MAX_MASK_NAME_LENGTH+1];
2211         int i;
2212         int done = 0;
2213         int add, len = 0;
2214         int pos = 0;
2215
2216         rg = yaffs_traceMask;
2217
2218         while (!done && (pos < count)) {
2219                 done = 1;
2220                 while ((pos < count) && isspace(buf[pos])) {
2221                         pos++;
2222                 }
2223
2224                 switch (buf[pos]) {
2225                 case '+':
2226                 case '-':
2227                 case '=':
2228                         add = buf[pos];
2229                         pos++;
2230                         break;
2231
2232                 default:
2233                         add = ' ';
2234                         break;
2235                 }
2236                 mask_name = NULL;
2237
2238                 mask_bitfield = simple_strtoul(buf + pos, &end, 0);
2239                 if (end > buf + pos) {
2240                         mask_name = "numeral";
2241                         len = end - (buf + pos);
2242                         pos += len;
2243                         done = 0;
2244                 } else {
2245                         for(x = buf + pos, i = 0;
2246                             (*x == '_' || (*x >='a' && *x <= 'z')) &&
2247                             i <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
2248                             substring[i] = *x;
2249                         substring[i] = '\0';
2250
2251                         for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2252                                 if(strcmp(substring,mask_flags[i].mask_name) == 0){
2253                                         mask_name = mask_flags[i].mask_name;
2254                                         mask_bitfield = mask_flags[i].mask_bitfield;
2255                                         done = 0;
2256                                         break;
2257                                 }
2258                         }
2259                 }
2260
2261                 if (mask_name != NULL) {
2262                         done = 0;
2263                         switch(add) {
2264                         case '-':
2265                                 rg &= ~mask_bitfield;
2266                                 break;
2267                         case '+':
2268                                 rg |= mask_bitfield;
2269                                 break;
2270                         case '=':
2271                                 rg = mask_bitfield;
2272                                 break;
2273                         default:
2274                                 rg |= mask_bitfield;
2275                                 break;
2276                         }
2277                 }
2278         }
2279
2280         yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
2281
2282         printk("new trace = 0x%08X\n",yaffs_traceMask);
2283
2284         if (rg & YAFFS_TRACE_ALWAYS) {
2285                 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2286                         char flag;
2287                         flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
2288                         printk("%c%s\n", flag, mask_flags[i].mask_name);
2289                 }
2290         }
2291
2292         return count;
2293 }
2294
2295 /* Stuff to handle installation of file systems */
2296 struct file_system_to_install {
2297         struct file_system_type *fst;
2298         int installed;
2299 };
2300
2301 static struct file_system_to_install fs_to_install[] = {
2302 //#ifdef CONFIG_YAFFS_YAFFS1
2303         {&yaffs_fs_type, 0},
2304 //#endif
2305 //#ifdef CONFIG_YAFFS_YAFFS2
2306         {&yaffs2_fs_type, 0},
2307 //#endif
2308         {NULL, 0}
2309 };
2310
2311 static int __init init_yaffs_fs(void)
2312 {
2313         int error = 0;
2314         struct file_system_to_install *fsinst;
2315
2316         T(YAFFS_TRACE_ALWAYS,
2317           ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2318
2319         /* Install the proc_fs entry */
2320         my_proc_entry = create_proc_entry("yaffs",
2321                                                S_IRUGO | S_IFREG,
2322                                                YPROC_ROOT);
2323
2324         if (my_proc_entry) {
2325                 my_proc_entry->write_proc = yaffs_proc_write;
2326                 my_proc_entry->read_proc = yaffs_proc_read;
2327                 my_proc_entry->data = NULL;
2328         } else {
2329                 return -ENOMEM;
2330         }
2331
2332         /* Now add the file system entries */
2333
2334         fsinst = fs_to_install;
2335
2336         while (fsinst->fst && !error) {
2337                 error = register_filesystem(fsinst->fst);
2338                 if (!error) {
2339                         fsinst->installed = 1;
2340                 }
2341                 fsinst++;
2342         }
2343
2344         /* Any errors? uninstall  */
2345         if (error) {
2346                 fsinst = fs_to_install;
2347
2348                 while (fsinst->fst) {
2349                         if (fsinst->installed) {
2350                                 unregister_filesystem(fsinst->fst);
2351                                 fsinst->installed = 0;
2352                         }
2353                         fsinst++;
2354                 }
2355         }
2356
2357         return error;
2358 }
2359
2360 static void __exit exit_yaffs_fs(void)
2361 {
2362
2363         struct file_system_to_install *fsinst;
2364
2365         T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
2366                                " removing. \n"));
2367
2368         remove_proc_entry("yaffs", YPROC_ROOT);
2369
2370         fsinst = fs_to_install;
2371
2372         while (fsinst->fst) {
2373                 if (fsinst->installed) {
2374                         unregister_filesystem(fsinst->fst);
2375                         fsinst->installed = 0;
2376                 }
2377                 fsinst++;
2378         }
2379
2380 }
2381
2382 module_init(init_yaffs_fs)
2383 module_exit(exit_yaffs_fs)
2384
2385 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2386 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2387 MODULE_LICENSE("GPL");