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