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