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