Change st_xxx to yst_xxx to fix compilation issues
[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.41 2005-10-11 23:43:27 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->yst_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->yst_mode;
613                 inode->i_uid = obj->yst_uid;
614                 inode->i_gid = obj->yst_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->yst_rdev);
620                 inode->i_atime.tv_sec = (time_t)(obj->yst_atime);
621                 inode->i_atime.tv_nsec = 0;
622                 inode->i_mtime.tv_sec = (time_t)obj->yst_mtime;
623                 inode->i_mtime.tv_nsec =0;
624                 inode->i_ctime.tv_sec = (time_t)obj->yst_ctime;
625                 inode->i_ctime.tv_nsec = 0;
626 #else
627                 inode->i_rdev = obj->yst_rdev;
628                 inode->i_atime = obj->yst_atime;
629                 inode->i_mtime = obj->yst_mtime;
630                 inode->i_ctime = obj->yst_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->yst_mode & S_IFMT) 
641                 {
642                         default: // fifo, device or socket
643 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
644                                init_special_inode(inode, obj->yst_mode,old_decode_dev(obj->yst_rdev));
645 #else
646                                  init_special_inode(inode, obj->yst_mode,(dev_t)(obj->yst_rdev));
647 #endif
648                                 break;
649                         case S_IFREG:   // file         
650                                 inode->i_op = &yaffs_file_inode_operations;
651                                 inode->i_fop = &yaffs_file_operations;
652                                 inode->i_mapping->a_ops = &yaffs_file_address_operations;
653                                 break;
654                         case S_IFDIR:   // directory
655                                 inode->i_op = &yaffs_dir_inode_operations;
656                                 inode->i_fop = &yaffs_dir_operations;
657                                 break;
658                         case S_IFLNK:   // symlink
659                                 inode->i_op = &yaffs_symlink_inode_operations;
660                                 break;
661                 }
662                 
663                 
664                 inode->u.generic_ip = obj;
665                 obj->myInode = inode;
666                 
667         }
668         else
669         {
670                 T(YAFFS_TRACE_OS,("yaffs_FileInode invalid parameters\n"));
671         }
672
673 }
674
675 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj)
676 {
677         struct inode * inode;
678         
679         T(YAFFS_TRACE_OS,("yaffs_get_inode for object %d\n",obj->objectId));
680
681         inode = iget(sb,obj->objectId);
682
683         // NB Side effect: iget calls back to yaffs_read_inode().
684         // iget also increments the inode's i_count
685         
686         return inode;
687 }
688
689 static ssize_t yaffs_file_read(struct file *f, char *buf, size_t n, loff_t *pos)
690 {
691         yaffs_Object *obj;
692         int nRead,ipos;
693         struct inode *inode;
694         yaffs_Device *dev;
695         
696         T(YAFFS_TRACE_OS,("yaffs_file_read\n"));
697
698         obj  = yaffs_DentryToObject(f->f_dentry);
699         
700         dev = obj->myDev;
701         
702         yaffs_GrossLock(dev);
703         
704         inode = f->f_dentry->d_inode;
705         
706         if (*pos < inode->i_size) 
707         {
708                         if (*pos + n > inode->i_size)
709                         {
710                                 n = inode->i_size - *pos;
711                         }
712         }
713         else
714         {
715                 n = 0;
716         }
717         
718         nRead = yaffs_ReadDataFromFile(obj,buf,*pos,n);
719         if(nRead > 0)
720         {
721                 f->f_pos += nRead;
722         }
723         
724         yaffs_GrossUnlock(dev);
725         
726         ipos = *pos;
727         
728         T(YAFFS_TRACE_OS,("yaffs_file_read read %d bytes, %d read at %d\n",n,nRead,ipos));
729         return nRead;
730         
731 }
732
733
734 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos)
735 {
736         yaffs_Object *obj;
737         int nWritten,ipos;
738         struct inode *inode;
739         yaffs_Device *dev;
740         
741         
742         obj  = yaffs_DentryToObject(f->f_dentry);
743         
744         dev = obj->myDev;
745         
746         yaffs_GrossLock(dev);
747
748         inode = f->f_dentry->d_inode;
749
750         if(!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
751         {
752                 ipos = inode->i_size;
753         }
754         else
755         {
756                 ipos = *pos;
757         }
758         
759         
760         if(!obj)
761         {
762                 T(YAFFS_TRACE_OS,("yaffs_file_write: hey obj is null!\n"));
763         }
764         else
765         {
766                 T(YAFFS_TRACE_OS,("yaffs_file_write about to write writing %d bytes to object %d at %d\n",n,obj->objectId,ipos));
767         }
768
769         nWritten = yaffs_WriteDataToFile(obj,buf,ipos,n);
770
771         T(YAFFS_TRACE_OS,("yaffs_file_write writing %d bytes, %d written at %d\n",n,nWritten,ipos));
772         if(nWritten > 0)
773         {
774                 ipos += nWritten;
775                 *pos = ipos;
776                 if(ipos > inode->i_size)
777                 {
778                         inode->i_size = ipos;
779                         inode->i_blocks = (ipos + 511)>>9;
780                         
781                         T(YAFFS_TRACE_OS,("yaffs_file_write size updated to %d bytes, %d blocks\n",ipos,(int)(inode->i_blocks)));
782                 }
783                 
784         }
785         yaffs_GrossUnlock(dev);
786         
787         return nWritten != n ? -ENOSPC : nWritten;
788 }
789
790
791 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
792 {
793         yaffs_Object *obj;
794         yaffs_Device *dev;
795         struct inode *inode = f->f_dentry->d_inode;
796         unsigned long offset, curoffs;
797         struct list_head *i;    
798         yaffs_Object *l;
799         
800         char name[YAFFS_MAX_NAME_LENGTH +1];
801                 
802         obj =  yaffs_DentryToObject(f->f_dentry);
803         dev = obj->myDev;
804         
805         yaffs_GrossLock(dev);
806         
807         offset = f->f_pos;
808         
809         T(YAFFS_TRACE_OS,("yaffs_readdir: starting at %d\n",(int)offset));
810         
811         if(offset == 0)
812         {
813         T(YAFFS_TRACE_OS,("yaffs_readdir: entry . ino %d \n",(int)inode->i_ino));
814                 if(filldir(dirent,".",1,offset,inode->i_ino,DT_DIR) < 0)
815                 {
816                         goto out;
817                 }
818                 offset++;
819                 f->f_pos++;
820         }
821         if(offset == 1)
822         {
823                 T(YAFFS_TRACE_OS,("yaffs_readdir: entry .. ino %d \n",(int)f->f_dentry->d_parent->d_inode->i_ino));
824                 if(filldir(dirent,"..",2,offset,f->f_dentry->d_parent->d_inode->i_ino,DT_DIR) < 0)
825                 {
826                         goto out;
827                 }
828                 offset++;
829                 f->f_pos++;
830         }
831         
832         curoffs = 1;
833         
834         list_for_each(i,&obj->variant.directoryVariant.children)
835         {
836                 curoffs++;
837                 if(curoffs >= offset)
838                 {               
839                         l = list_entry(i, yaffs_Object,siblings);
840                         
841                         yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1); 
842                         T(YAFFS_TRACE_OS,("yaffs_readdir: %s inode %d\n",name,yaffs_GetObjectInode(l)));
843                         
844                         if(filldir(dirent,
845                                            name,
846                                            strlen(name),
847                                            offset,
848                                            yaffs_GetObjectInode(l),
849                                            yaffs_GetObjectType(l))
850                                            < 0)
851                         {
852                                 goto up_and_out;
853                         }
854                         
855                         offset++;
856                         f->f_pos++;        
857                 }
858         }
859
860   up_and_out:
861   out:
862   
863     yaffs_GrossUnlock(dev);
864     
865         return 0;
866 }
867
868
869 /*
870  * File creation. Allocate an inode, and we're done..
871  */
872 //#if defined(CONFIG_KERNEL_2_5)
873 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
874 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
875 #else
876 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
877 #endif
878 {
879         struct inode *inode;
880         
881         yaffs_Object *obj = NULL;
882         yaffs_Device *dev;
883         
884         yaffs_Object *parent = yaffs_InodeToObject(dir);
885         
886         int error = -ENOSPC;
887
888         if(parent)
889         {
890                 T(YAFFS_TRACE_OS,("yaffs_mknod: parent object %d type %d\n",
891                                          parent->objectId,parent->variantType));
892         }
893         else
894         {
895                 T(YAFFS_TRACE_OS,("yaffs_mknod: could not get parent object\n"));
896                 return -EPERM;
897         }
898         
899         T(YAFFS_TRACE_OS,("yaffs_mknod: making oject for %s, mode %x dev %x\n",
900                                         dentry->d_name.name, mode,rdev));
901
902         dev = parent->myDev;
903         
904         yaffs_GrossLock(dev);
905
906         switch (mode & S_IFMT) 
907         {
908                 default:
909                         // Special (socket, fifo, device...)
910                         T(YAFFS_TRACE_OS,("yaffs_mknod: making special\n"));
911 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
912                         obj = yaffs_MknodSpecial(parent,dentry->d_name.name,mode,current->uid, current->gid,old_encode_dev(rdev));
913 #else
914                         obj = yaffs_MknodSpecial(parent,dentry->d_name.name,mode,current->uid, current->gid,rdev);
915 #endif
916                         break;
917                 case S_IFREG:   // file         
918                         T(YAFFS_TRACE_OS,("yaffs_mknod: making file\n"));
919                         obj = yaffs_MknodFile(parent,dentry->d_name.name,mode,current->uid, current->gid);
920                         break;
921                 case S_IFDIR:   // directory
922                         T(YAFFS_TRACE_OS,("yaffs_mknod: making directory\n"));
923                         obj = yaffs_MknodDirectory(parent,dentry->d_name.name,mode,current->uid, current->gid);
924                         break;
925                 case S_IFLNK:   // symlink
926                         T(YAFFS_TRACE_OS,("yaffs_mknod: making file\n"));
927                         obj = NULL; // Do we ever get here?
928                         break;
929         }
930         
931         if(obj)
932         {
933                 inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
934                 d_instantiate(dentry, inode);
935                 T(YAFFS_TRACE_OS,("yaffs_mknod created object %d count = %d\n",obj->objectId,atomic_read(&inode->i_count)));
936                 error = 0;
937         }
938         else
939         {
940                 T(YAFFS_TRACE_OS,("yaffs_mknod failed making object\n"));
941                 error = -ENOMEM;
942         }
943
944         yaffs_GrossUnlock(dev);
945
946         return error;
947 }
948
949 static int yaffs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
950 {
951         int retVal;
952         T(YAFFS_TRACE_OS,("yaffs_mkdir\n"));
953         retVal =  yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
954 #if 0
955  // attempt to fix dir bug - didn't work
956         if(!retVal)
957         {
958                 dget(dentry);
959         }
960 #endif
961         return retVal;
962 }
963
964 //#if defined(CONFIG_KERNEL_2_5)        /* Added NCB 185-8-2003 */
965 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
966 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *n)
967 #else
968 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
969 #endif
970 {
971         T(YAFFS_TRACE_OS,("yaffs_create\n"));
972         return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
973 }
974
975
976 static int yaffs_unlink(struct inode * dir, struct dentry *dentry)
977 {
978         int retVal;
979         
980         yaffs_Device *dev;
981         
982         
983         T(YAFFS_TRACE_OS,("yaffs_unlink %d:%s\n",(int)(dir->i_ino),dentry->d_name.name));
984         
985         dev = yaffs_InodeToObject(dir)->myDev;
986         
987         yaffs_GrossLock(dev);
988         
989         
990         retVal = yaffs_Unlink(yaffs_InodeToObject(dir),dentry->d_name.name);
991         
992         
993         yaffs_GrossUnlock(dev);
994         
995         if( retVal == YAFFS_OK)
996         {
997                 dentry->d_inode->i_nlink--;
998                 mark_inode_dirty(dentry->d_inode);
999                 return 0;
1000         }
1001         else
1002         {
1003                 return -ENOTEMPTY;
1004         }
1005 }
1006
1007
1008 /*
1009  * Create a link...
1010  */
1011 static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
1012 {
1013         struct inode *inode = old_dentry->d_inode;
1014         yaffs_Object *obj = NULL;
1015         yaffs_Object *link=NULL;
1016         yaffs_Device *dev;
1017         
1018         T(YAFFS_TRACE_OS,("yaffs_link\n"));
1019         
1020         obj = yaffs_InodeToObject(inode);
1021         dev = obj->myDev;
1022         
1023         yaffs_GrossLock(dev);
1024
1025         if (!S_ISDIR(inode->i_mode))    // Don't link directories
1026         {
1027                 link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj);
1028         }
1029         
1030
1031         if(link)
1032         {
1033                 old_dentry->d_inode->i_nlink =  yaffs_GetObjectLinkCount(obj);
1034                 d_instantiate(dentry, old_dentry->d_inode);
1035                 atomic_inc(&old_dentry->d_inode->i_count);
1036                 T(YAFFS_TRACE_OS,("yaffs_link link count %d i_count %d\n",      
1037                         old_dentry->d_inode->i_nlink,atomic_read(&old_dentry->d_inode->i_count)));
1038         
1039         }
1040         
1041         yaffs_GrossUnlock(dev);
1042         
1043
1044         if(link)
1045         {
1046         
1047                 return 0;
1048         }
1049         
1050         
1051         return -EPERM; 
1052 }
1053
1054
1055 static int yaffs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
1056 {
1057         yaffs_Object *obj;
1058         yaffs_Device *dev;
1059         
1060         T(YAFFS_TRACE_OS,("yaffs_symlink\n"));
1061         
1062         dev = yaffs_InodeToObject(dir)->myDev;
1063         yaffs_GrossLock(dev);
1064         obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, 
1065                                                          S_IFLNK | S_IRWXUGO, current->uid, current->gid,
1066                                                          symname);
1067         yaffs_GrossUnlock(dev);
1068
1069         if(obj)
1070         {
1071
1072                 struct inode* inode;
1073         
1074                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1075                 d_instantiate(dentry, inode);
1076                 T(YAFFS_TRACE_OS,("symlink created OK\n"));
1077                 return 0;
1078         }
1079         else
1080         {
1081                 T(YAFFS_TRACE_OS,("symlink not created\n"));
1082
1083         }
1084         
1085         return -ENOMEM;
1086 }
1087
1088 static int yaffs_sync_object(struct file * file, struct dentry *dentry, int datasync)
1089 {
1090
1091         yaffs_Object *obj;
1092         yaffs_Device *dev;
1093         
1094         obj = yaffs_DentryToObject(dentry);
1095
1096         dev = obj->myDev;
1097         
1098         T(YAFFS_TRACE_OS,("yaffs_sync_object\n"));
1099         yaffs_GrossLock(dev);
1100         yaffs_FlushFile(obj,1);
1101         yaffs_GrossUnlock(dev);
1102         return 0;
1103 }
1104
1105 /*
1106  * The VFS layer already does all the dentry stuff for rename.
1107  *
1108  * NB: POSIX says you can rename an object over an old object of the same name
1109  */
1110 static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
1111 {
1112         yaffs_Device *dev;
1113         int retVal = YAFFS_FAIL;
1114         int removed = 0;
1115         yaffs_Object *target;
1116         
1117         dev = yaffs_InodeToObject(old_dir)->myDev;
1118
1119         yaffs_GrossLock(dev);
1120         
1121         // Check if the target is an existing directory that is not empty.
1122         target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1123         
1124         if(target &&
1125            target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1126            !list_empty(&target->variant.directoryVariant.children))
1127         {
1128                 retVal = YAFFS_FAIL;
1129         }
1130         else
1131         {
1132            
1133                 // Unlink the target if it exists
1134                 removed = yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1135
1136         
1137                 retVal =  yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
1138                                                                         yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1139                                                                         
1140         }
1141         yaffs_GrossUnlock(dev);
1142         
1143         if(retVal == YAFFS_OK)
1144         {
1145                 if(removed == YAFFS_OK)
1146                 {
1147                         new_dentry->d_inode->i_nlink--;
1148                         mark_inode_dirty(new_dentry->d_inode);
1149                 }
1150                 
1151                 return 0;
1152         }
1153         else
1154         {
1155                 return -ENOTEMPTY;
1156         }
1157         
1158
1159 }
1160
1161 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1162 {
1163         struct inode *inode = dentry->d_inode;
1164         int error;
1165         yaffs_Device *dev;
1166         
1167         T(YAFFS_TRACE_OS,("yaffs_setattr of object %d\n",yaffs_InodeToObject(inode)->objectId));
1168         
1169         if((error = inode_change_ok(inode,attr)) == 0)
1170         {
1171         
1172                 dev = yaffs_InodeToObject(inode)->myDev;
1173                 yaffs_GrossLock(dev);
1174                 if(yaffs_SetAttributes(yaffs_InodeToObject(inode),attr) == YAFFS_OK)
1175                 {
1176                         error = 0;
1177                 }
1178                 else
1179                 {
1180                         error = -EPERM;
1181                 }
1182                 yaffs_GrossUnlock(dev);
1183                 error = inode_setattr(inode,attr);
1184         }
1185         return error;
1186 }
1187
1188 //#if defined(CONFIG_KERNEL_2_5)        /* Added NCB 185-8-2003 */
1189 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1190 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1191 #else
1192 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1193 #endif
1194 {
1195         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1196         T(YAFFS_TRACE_OS,("yaffs_statfs\n"));
1197
1198         yaffs_GrossLock(dev);
1199         
1200         buf->f_type = YAFFS_MAGIC;
1201         buf->f_bsize = sb->s_blocksize;
1202         buf->f_namelen = 255;
1203         buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * YAFFS_CHUNKS_PER_BLOCK/
1204                                                 (sb->s_blocksize/YAFFS_BYTES_PER_CHUNK);
1205         buf->f_files = 0;
1206         buf->f_ffree = 0;
1207         buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev)/
1208                                                 (sb->s_blocksize/YAFFS_BYTES_PER_CHUNK);
1209         buf->f_bavail =  buf->f_bfree;
1210         
1211         yaffs_GrossUnlock(dev);
1212         return 0;
1213 }
1214
1215 static void yaffs_read_inode (struct inode *inode)
1216 {
1217         // NB This is called as a side effect of other functions and
1218         // thus gross locking should always be in place already.
1219         
1220         yaffs_Object *obj ; 
1221         yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1222         
1223         T(YAFFS_TRACE_OS,("yaffs_read_inode for %d\n",(int)inode->i_ino));
1224
1225         obj  = yaffs_FindObjectByNumber(dev,inode->i_ino);
1226         
1227         yaffs_FillInodeFromObject(inode,obj);
1228
1229 }
1230
1231
1232
1233 static yaffs_Device *yaffs_dev;
1234 static yaffs_Device *yaffsram_dev;
1235
1236
1237
1238 static void yaffs_put_super(struct super_block *sb)
1239 {
1240         yaffs_Device *dev = yaffs_SuperToDevice(sb);
1241         
1242         yaffs_GrossLock(dev);
1243         if(dev->putSuperFunc)
1244         {
1245                  dev->putSuperFunc(sb);
1246         }
1247         yaffs_Deinitialise(dev);
1248         yaffs_GrossUnlock(dev);
1249
1250         if(dev == yaffs_dev) yaffs_dev = NULL;
1251         if(dev == yaffsram_dev) yaffsram_dev = NULL;
1252                 
1253         kfree(dev);
1254 }
1255
1256
1257 #ifdef CONFIG_YAFFS_MTD_ENABLED
1258
1259 static void  yaffs_MTDPutSuper(struct super_block *sb)
1260 {
1261         
1262         struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1263         
1264         if(mtd->sync)
1265         {
1266                 mtd->sync(mtd);
1267         }
1268         
1269         put_mtd_device(mtd);
1270 }
1271
1272 #endif
1273
1274
1275 static struct super_block *yaffs_internal_read_super(int useRam, struct super_block * sb, void * data, int silent)
1276 {
1277         int nBlocks;
1278         struct inode * inode;
1279         struct dentry * root;
1280         yaffs_Device *dev;
1281         
1282         sb->s_magic = YAFFS_MAGIC;
1283         sb->s_op = &yaffs_super_ops;
1284         
1285         if(!sb)
1286                 T(YAFFS_TRACE_OS,("yaffs: sb is NULL\n"));
1287         else if(!sb->s_dev)
1288                 T(YAFFS_TRACE_OS,("yaffs: sb->s_dev is NULL\n"));
1289         else if(! kdevname(sb->s_dev))
1290                 T(YAFFS_TRACE_OS,("yaffs: kdevname is NULL\n"));
1291         else
1292                 T(YAFFS_TRACE_OS,("yaffs: dev is %d name is \"%s\"\n", sb->s_dev, kdevname(sb->s_dev)));
1293
1294         
1295
1296 #ifdef CONFIG_YAFFS_USE_CHUNK_SIZE
1297         sb->s_blocksize = YAFFS_BYTES_PER_CHUNK;
1298         sb->s_blocksize_bits = YAFFS_CHUNK_SIZE_SHIFT;
1299 #else
1300         sb->s_blocksize = PAGE_CACHE_SIZE;
1301         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1302 #endif
1303         T(YAFFS_TRACE_OS,("yaffs_read_super: %s block size %d\n", useRam ? "RAM" : "MTD",(int)(sb->s_blocksize)));
1304
1305 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1306         T(YAFFS_TRACE_OS,("yaffs: Write verification disabled. All guarantees null and void\n"));
1307 #endif
1308
1309
1310         
1311         if(useRam)
1312         {
1313
1314 #ifdef CONFIG_YAFFS_RAM_ENABLED
1315                 // Set the yaffs_Device up for ram emulation
1316
1317                 sb->u.generic_sbp =     dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
1318                 if(!dev)
1319                 {
1320                         // Deep shit could not allocate device structure
1321                         T(YAFFS_TRACE_OS,("yaffs_read_super: Failed trying to allocate yaffs_Device. Terminating debug.\n"));
1322                         return NULL;
1323                 }
1324
1325                 memset(dev,0,sizeof(yaffs_Device));
1326                 dev->genericDevice = NULL; // Not used for RAM emulation.
1327
1328                 nBlocks = YAFFS_RAM_EMULATION_SIZE / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
1329                 dev->startBlock = 0;
1330                 dev->endBlock = nBlocks - 1;
1331                 dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
1332                 dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
1333                 dev->nReservedBlocks = 5;
1334                 dev->nShortOpCaches = 10; // Enable short op caching
1335
1336                 dev->writeChunkToNAND = nandemul_WriteChunkToNAND;
1337                 dev->readChunkFromNAND = nandemul_ReadChunkFromNAND;
1338                 dev->eraseBlockInNAND = nandemul_EraseBlockInNAND;
1339                 dev->initialiseNAND = nandemul_InitialiseNAND;
1340
1341                 yaffsram_dev = dev;
1342                 
1343 #endif
1344
1345         }
1346         else
1347         {       
1348 #ifdef CONFIG_YAFFS_MTD_ENABLED
1349                 struct mtd_info *mtd;
1350                 
1351                 T(YAFFS_TRACE_ALWAYS,( "yaffs: Attempting MTD mount on %u.%u, \"%s\"\n",
1352                  MAJOR(sb->s_dev),MINOR(sb->s_dev),kdevname(sb->s_dev)));
1353                         
1354                 // Check it's an mtd device.....
1355                 if(MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
1356                 {
1357                         return NULL; // This isn't an mtd device
1358                 } 
1359                 
1360                 // Get the device
1361                 mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1362                 if (!mtd) 
1363                 {
1364                         T(YAFFS_TRACE_ALWAYS,( "yaffs: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
1365                         return NULL;
1366                 }
1367                 
1368                 // Check it's NAND
1369                 if(mtd->type != MTD_NANDFLASH)
1370                 {
1371                         T(YAFFS_TRACE_ALWAYS,( "yaffs: MTD device is not NAND it's type %d\n", mtd->type));
1372                         return NULL;
1373                 }
1374
1375                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" erase %x\n",mtd->erase);
1376                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" read %x\n",mtd->read);
1377                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" write %x\n",mtd->write);
1378                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" readoob %x\n",mtd->read_oob);
1379                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" writeoob %x\n",mtd->write_oob);
1380                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" oobblock %x\n",mtd->oobblock);
1381                 //T(YAFFS_TRACE_OS,(KERN_DEBUG" oobsize %x\n",mtd->oobsize);
1382
1383
1384                 if(!mtd->erase ||
1385                    !mtd->read  ||
1386                    !mtd->write ||
1387 #ifndef CONFIG_YAFFS_USE_OLD_MTD
1388                    !mtd->write_ecc ||
1389                    !mtd->read_ecc ||
1390 #endif
1391                    !mtd->read_oob ||
1392                    !mtd->write_oob )
1393                 {
1394                         T(YAFFS_TRACE_ALWAYS,( "yaffs: MTD device does not support required functions\n"));
1395                         return NULL;
1396                 }
1397                 
1398                 if(mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
1399                    mtd->oobsize != YAFFS_BYTES_PER_SPARE)
1400                 {
1401                         T(YAFFS_TRACE_ALWAYS,( "yaffs: MTD device does not support have the right page sizes\n"));
1402                         return NULL;
1403                 }
1404                    
1405
1406                 // OK, so if we got here, we have an MTD that's NAND and looks 
1407                 // like it has the right capabilities
1408                 // Set the yaffs_Device up for ram emulation
1409
1410 //#if defined(CONFIG_KERNEL_2_5)
1411 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1412                 sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
1413 #else
1414                 sb->u.generic_sbp =     dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
1415 #endif
1416                 if(!dev)
1417                 {
1418                         // Deep shit could not allocate device structure
1419                         T(YAFFS_TRACE_ALWAYS,("yaffs_read_super: Failed trying to allocate yaffs_Device. Terminating debug.\n"));
1420                         return NULL;
1421                 }
1422
1423                 memset(dev,0,sizeof(yaffs_Device));
1424                 dev->genericDevice = mtd; 
1425
1426                 // Set up the memory size parameters....
1427                 
1428                 nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
1429                 dev->startBlock = 0;
1430                 dev->endBlock = nBlocks - 1;
1431                 dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
1432                 dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
1433                 dev->nReservedBlocks = 5;
1434                 dev->nShortOpCaches = 10; // Enable short op caching
1435                 
1436
1437                 // ... and the functions.
1438                 dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
1439                 dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
1440                 dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
1441                 dev->initialiseNAND = nandmtd_InitialiseNAND;
1442                                 
1443                 dev->putSuperFunc = yaffs_MTDPutSuper;
1444                 
1445 #ifdef CONFIG_YAFFS_USE_NANDECC
1446                 dev->useNANDECC = 1;
1447 #endif
1448
1449                 yaffs_dev = dev;
1450                 
1451 #endif
1452         }
1453
1454         init_MUTEX(&dev->grossLock);
1455         
1456         
1457         yaffs_GrossLock(dev);
1458         yaffs_GutsInitialise(yaffs_SuperToDevice(sb));
1459
1460         T(YAFFS_TRACE_OS,("yaffs_read_super: guts initialised\n"));
1461
1462         // Create root inode
1463         inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,yaffs_Root(yaffs_SuperToDevice(sb)));
1464
1465         yaffs_GrossUnlock(dev);
1466
1467         if (!inode)
1468                 return NULL;
1469                 
1470 // added NCB
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
1477         root = d_alloc_root(inode);
1478
1479         T(YAFFS_TRACE_OS,("yaffs_read_super: d_alloc_root done\n"));
1480
1481         if (!root) {
1482                 iput(inode);
1483                 return NULL;
1484         }
1485         sb->s_root = root;
1486
1487         T(YAFFS_TRACE_OS,("yaffs_read_super: done\n"));
1488         return sb;
1489 }
1490
1491 static int yaffs_internal_read_super_ram(struct super_block * sb, void * data, int silent)
1492 {
1493          return yaffs_internal_read_super(1,sb,data,silent) ? 0 : -1;
1494 }
1495 static int yaffs_internal_read_super_mtd(struct super_block * sb, void * data, int silent)
1496 {
1497          return yaffs_internal_read_super(0,sb,data,silent) ? 0 : -1;
1498 }
1499
1500
1501 #ifdef CONFIG_YAFFS_MTD_ENABLED
1502 //#if defined(CONFIG_KERNEL_2_5)
1503 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1504 static struct super_block *yaffs_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
1505 {
1506
1507     return get_sb_bdev(fs, flags, dev_name, data, yaffs_internal_read_super_mtd);
1508 }
1509
1510 /* changes NCB 2.5.70 */
1511 //static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, FS_REQUIRES_DEV);
1512 static struct file_system_type yaffs_fs_type = {
1513         .owner          = THIS_MODULE,
1514         .name           = "yaffs",
1515         .get_sb         = yaffs_read_super,
1516         .kill_sb        = kill_block_super,
1517 //      .kill_sb        = kill_litter_super,
1518         .fs_flags       = FS_REQUIRES_DEV,
1519 };
1520 #else
1521 static struct super_block *yaffs_read_super(struct super_block * sb, void * data, int silent)
1522 {
1523         return yaffs_internal_read_super(0,sb,data,silent);
1524 }
1525
1526 static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, FS_REQUIRES_DEV);
1527 #endif
1528 #endif
1529
1530 #ifdef CONFIG_YAFFS_RAM_ENABLED
1531
1532 //#if defined(CONFIG_KERNEL_2_5)
1533 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1534 static struct super_block *yaffs_ram_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
1535 {
1536
1537     return get_sb_bdev(fs, flags, dev_name, data, yaffs_internal_read_super_ram);
1538 }
1539
1540 /* changes NCB 2.5.70 */
1541 //static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, FS_REQUIRES_DEV);
1542 static struct file_system_type yaffs_fs_type = {
1543         .owner          = THIS_MODULE,
1544         .name           = "yaffsram",
1545         .get_sb         = yaffs_ram_read_super,
1546         .kill_sb        = kill_block_super,
1547 //      .kill_sb        = kill_litter_super,
1548         .fs_flags       = FS_SINGLE,
1549 };
1550 #else
1551 static struct super_block *yaffs_ram_read_super(struct super_block * sb, void * data, int silent)
1552 {
1553         return yaffs_internal_read_super(1,sb,data,silent);
1554 }
1555
1556 static DECLARE_FSTYPE(yaffs_ram_fs_type, "yaffsram", yaffs_ram_read_super, FS_SINGLE);
1557 #endif
1558 #endif // CONFIG_YAFFS_RAM_ENABLED
1559
1560
1561 static struct proc_dir_entry *my_proc_entry;
1562 static struct proc_dir_entry *my_proc_ram_write_entry;
1563
1564 static char * yaffs_dump_dev(char *buf,yaffs_Device *dev,char *name)
1565 {
1566         buf +=sprintf(buf,"\nDevice %s\n",name);
1567         buf +=sprintf(buf,"startBlock......... %d\n",dev->startBlock);
1568         buf +=sprintf(buf,"endBlock........... %d\n",dev->endBlock);
1569         buf +=sprintf(buf,"chunkGroupBits..... %d\n",dev->chunkGroupBits);
1570         buf +=sprintf(buf,"chunkGroupSize..... %d\n",dev->chunkGroupSize);
1571         buf +=sprintf(buf,"nErasedBlocks...... %d\n",dev->nErasedBlocks);
1572         buf +=sprintf(buf,"nTnodesCreated..... %d\n",dev->nTnodesCreated);
1573         buf +=sprintf(buf,"nFreeTnodes........ %d\n",dev->nFreeTnodes);
1574         buf +=sprintf(buf,"nObjectsCreated.... %d\n",dev->nObjectsCreated);
1575         buf +=sprintf(buf,"nFreeObjects....... %d\n",dev->nFreeObjects);
1576         buf +=sprintf(buf,"nFreeChunks........ %d\n",dev->nFreeChunks);
1577         buf +=sprintf(buf,"nPageWrites........ %d\n",dev->nPageWrites);
1578         buf +=sprintf(buf,"nPageReads......... %d\n",dev->nPageReads);
1579         buf +=sprintf(buf,"nBlockErasures..... %d\n",dev->nBlockErasures);
1580         buf +=sprintf(buf,"nGCCopies.......... %d\n",dev->nGCCopies);
1581         buf +=sprintf(buf,"garbageCollections. %d\n",dev->garbageCollections);
1582         buf +=sprintf(buf,"passiveGCs......... %d\n",dev->passiveGarbageCollections);
1583         buf +=sprintf(buf,"nRetriedWrites..... %d\n",dev->nRetriedWrites);
1584         buf +=sprintf(buf,"nRetireBlocks...... %d\n",dev->nRetiredBlocks);
1585         buf +=sprintf(buf,"eccFixed........... %d\n",dev->eccFixed);
1586         buf +=sprintf(buf,"eccUnfixed......... %d\n",dev->eccUnfixed);
1587         buf +=sprintf(buf,"tagsEccFixed....... %d\n",dev->tagsEccFixed);
1588         buf +=sprintf(buf,"tagsEccUnfixed..... %d\n",dev->tagsEccUnfixed);
1589         buf +=sprintf(buf,"cacheHits.......... %d\n",dev->cacheHits);
1590         buf +=sprintf(buf,"nDeletedFiles...... %d\n",dev->nDeletedFiles);
1591         buf +=sprintf(buf,"nUnlinkedFiles..... %d\n",dev->nUnlinkedFiles);
1592         buf +=sprintf(buf,"nBackgroudDeletions %d\n",dev->nBackgroundDeletions);
1593         buf +=sprintf(buf,"useNANDECC......... %d\n",dev->useNANDECC);
1594         buf +=sprintf(buf,"nShortOpCaches..... %d\n",dev->nShortOpCaches);
1595
1596         
1597         return buf;     
1598 }
1599
1600 static int  yaffs_proc_read(
1601         char *page,
1602         char **start,
1603         off_t offset,
1604         int count,
1605         int *eof,
1606         void *data
1607         )
1608 {
1609
1610         char my_buffer[3000];
1611         char *buf;
1612         buf = my_buffer;
1613
1614         if (offset > 0) return 0;
1615
1616         /* Fill the buffer and get its length */
1617         buf +=sprintf(buf,"YAFFS built:"__DATE__ " "__TIME__"\n%s\n%s\n", yaffs_fs_c_version,yaffs_guts_c_version);
1618         
1619         if(yaffs_dev) buf = yaffs_dump_dev(buf,yaffs_dev,"yaffs");
1620         if(yaffsram_dev) buf = yaffs_dump_dev(buf,yaffsram_dev,"yaffsram");
1621         
1622
1623         strcpy(page,my_buffer);
1624         return strlen(my_buffer);
1625 }
1626
1627
1628 static int  yaffs_proc_ram_write(
1629         char *page,
1630         char **start,
1631         off_t offset,
1632         int count,
1633         int *eof,
1634         void *data
1635         )
1636 {
1637
1638         T(YAFFS_TRACE_OS,( "yaffs write size %d\n",count));
1639         return count;
1640 }
1641
1642 static int __init init_yaffs_fs(void)
1643 {
1644         int error = 0;
1645         
1646         yaffs_dev = yaffsram_dev = NULL;
1647         
1648         T(YAFFS_TRACE_OS,( "yaffs " __DATE__ " " __TIME__ " Initialisation\n"));
1649 #ifdef CONFIG_YAFFS_USE_GENERIC_RW
1650         T(YAFFS_TRACE_OS,( "yaffs is using generic read/write (caching)\n"));
1651 #else
1652         T(YAFFS_TRACE_OS,( "yaffs is using direct read/write (uncached)\n"));
1653 #endif
1654
1655
1656     /* Install the proc_fs entry */
1657     my_proc_entry = create_proc_read_entry("yaffs",
1658                                            S_IRUGO | S_IFREG,
1659                                            &proc_root,
1660                                            yaffs_proc_read,
1661                                            NULL);
1662     if(!my_proc_entry)
1663     {
1664        return -ENOMEM;
1665     }
1666
1667 #ifdef CONFIG_YAFFS_RAM_ENABLED
1668 #if 0
1669     my_proc_ram_write_entry = create_proc_entry("yaffs_ram",
1670                                            S_IRUGO | S_IFREG,
1671                                            &proc_root);
1672  
1673     if(!my_proc_ram_write_entry)
1674     {
1675        return -ENOMEM;
1676     }
1677     else
1678     {
1679         my_proc_ram_write_entry->write_proc = yaffs_proc_ram_write;
1680     }
1681 #endif
1682
1683     error = register_filesystem(&yaffs_ram_fs_type);
1684     if(error)
1685     {
1686         return error;
1687     }
1688 #endif //CONFIG_YAFFS_RAM_ENABLED
1689
1690 #ifdef CONFIG_YAFFS_MTD_ENABLED
1691         error = register_filesystem(&yaffs_fs_type);
1692         if(error)
1693         {
1694 #ifdef CONFIG_YAFFS_RAM_ENABLED
1695                 unregister_filesystem(&yaffs_ram_fs_type);
1696 #endif //CONFIG_YAFFS_RAM_ENABLED
1697         }
1698 #endif // CONFIG_YAFFS_MTD_ENABLED
1699
1700         return error;
1701 }
1702
1703 static void __exit exit_yaffs_fs(void)
1704 {
1705         T(YAFFS_TRACE_OS,( "yaffs " __DATE__ " " __TIME__ " Clean up\n"));
1706
1707     remove_proc_entry("yaffs",&proc_root);
1708     
1709 #ifdef CONFIG_YAFFS_RAM_ENABLED
1710         unregister_filesystem(&yaffs_ram_fs_type);
1711 #endif
1712 #ifdef CONFIG_YAFFS_MTD_ENABLED
1713         unregister_filesystem(&yaffs_fs_type);
1714 #endif
1715
1716 }
1717
1718 module_init(init_yaffs_fs)
1719 module_exit(exit_yaffs_fs)
1720
1721 MODULE_DESCRIPTION("YAFFS - a NAND specific flash file system");
1722 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002");
1723 MODULE_LICENSE("GPL");
1724
1725