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