2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * Luc van OostenRyck for numerous patches.
10 * Nick Bane for numerous patches.
11 * Nick Bane for 2.5/2.6 integration.
12 * Andras Toth for mknod rdev issue.
13 * Michael Fischer for finding the problem with inode inconsistency.
14 * Some code bodily lifted from JFFS
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
23 * This is the file system front-end to YAFFS that hooks it up to
27 * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
29 * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
31 * >> inode->u.generic_ip points to the associated yaffs_Object.
34 const char *yaffs_fs_c_version
=
35 "$Id: yaffs_fs.c,v 1.66 2008-05-05 07:58:58 charles Exp $";
36 extern const char *yaffs_guts_c_version
;
38 #include <linux/version.h>
39 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
40 #include <linux/config.h>
42 #include <linux/kernel.h>
43 #include <linux/module.h>
44 #include <linux/slab.h>
45 #include <linux/init.h>
46 #include <linux/list.h>
48 #include <linux/proc_fs.h>
49 #include <linux/smp_lock.h>
50 #include <linux/pagemap.h>
51 #include <linux/mtd/mtd.h>
52 #include <linux/interrupt.h>
53 #include <linux/string.h>
54 #include <linux/ctype.h>
56 #include "asm/div64.h"
58 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
60 #include <linux/statfs.h> /* Added NCB 15-8-2003 */
61 #include <asm/statfs.h>
62 #define UnlockPage(p) unlock_page(p)
63 #define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
65 /* FIXME: use sb->s_id instead ? */
66 #define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
70 #include <linux/locks.h>
71 #define BDEVNAME_SIZE 0
72 #define yaffs_devname(sb, buf) kdevname(sb->s_dev)
74 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
75 /* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
81 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
82 #define WRITE_SIZE_STR "writesize"
83 #define WRITE_SIZE(mtd) (mtd)->writesize
85 #define WRITE_SIZE_STR "oobblock"
86 #define WRITE_SIZE(mtd) (mtd)->oobblock
89 #include <asm/uaccess.h>
92 #include "yaffs_guts.h"
94 #include <linux/mtd/mtd.h>
95 #include "yaffs_mtdif.h"
96 #include "yaffs_mtdif1.h"
97 #include "yaffs_mtdif2.h"
99 unsigned int yaffs_traceMask
= YAFFS_TRACE_BAD_BLOCKS
;
100 unsigned int yaffs_wr_attempts
= YAFFS_WR_ATTEMPTS
;
102 /* Module Parameters */
103 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
104 module_param(yaffs_traceMask
,uint
,0644);
105 module_param(yaffs_wr_attempts
,uint
,0644);
107 MODULE_PARM(yaffs_traceMask
,"i");
108 MODULE_PARM(yaffs_wr_attempts
,"i");
111 /*#define T(x) printk x */
113 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
114 #define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
116 #define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
119 #define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
120 #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
122 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
123 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
125 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
128 static void yaffs_put_super(struct super_block
*sb
);
130 static ssize_t
yaffs_file_write(struct file
*f
, const char *buf
, size_t n
,
133 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
134 static int yaffs_file_flush(struct file
*file
, fl_owner_t id
);
136 static int yaffs_file_flush(struct file
*file
);
139 static int yaffs_sync_object(struct file
*file
, struct dentry
*dentry
,
142 static int yaffs_readdir(struct file
*f
, void *dirent
, filldir_t filldir
);
144 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
145 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
146 struct nameidata
*n
);
147 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
,
148 struct nameidata
*n
);
150 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
);
151 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
);
153 static int yaffs_link(struct dentry
*old_dentry
, struct inode
*dir
,
154 struct dentry
*dentry
);
155 static int yaffs_unlink(struct inode
*dir
, struct dentry
*dentry
);
156 static int yaffs_symlink(struct inode
*dir
, struct dentry
*dentry
,
157 const char *symname
);
158 static int yaffs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
);
160 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
161 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
164 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
167 static int yaffs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
168 struct inode
*new_dir
, struct dentry
*new_dentry
);
169 static int yaffs_setattr(struct dentry
*dentry
, struct iattr
*attr
);
171 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
172 static int yaffs_sync_fs(struct super_block
*sb
, int wait
);
173 static void yaffs_write_super(struct super_block
*sb
);
175 static int yaffs_sync_fs(struct super_block
*sb
);
176 static int yaffs_write_super(struct super_block
*sb
);
179 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
180 static int yaffs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
);
181 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
182 static int yaffs_statfs(struct super_block
*sb
, struct kstatfs
*buf
);
184 static int yaffs_statfs(struct super_block
*sb
, struct statfs
*buf
);
186 static void yaffs_read_inode(struct inode
*inode
);
188 static void yaffs_put_inode(struct inode
*inode
);
189 static void yaffs_delete_inode(struct inode
*);
190 static void yaffs_clear_inode(struct inode
*);
192 static int yaffs_readpage(struct file
*file
, struct page
*page
);
193 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
194 static int yaffs_writepage(struct page
*page
, struct writeback_control
*wbc
);
196 static int yaffs_writepage(struct page
*page
);
198 static int yaffs_prepare_write(struct file
*f
, struct page
*pg
,
199 unsigned offset
, unsigned to
);
200 static int yaffs_commit_write(struct file
*f
, struct page
*pg
, unsigned offset
,
203 static int yaffs_readlink(struct dentry
*dentry
, char __user
* buffer
,
205 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
206 static void *yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
);
208 static int yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
);
211 static struct address_space_operations yaffs_file_address_operations
= {
212 .readpage
= yaffs_readpage
,
213 .writepage
= yaffs_writepage
,
214 .prepare_write
= yaffs_prepare_write
,
215 .commit_write
= yaffs_commit_write
,
218 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
219 static struct file_operations yaffs_file_operations
= {
220 .read
= do_sync_read
,
221 .write
= do_sync_write
,
222 .aio_read
= generic_file_aio_read
,
223 .aio_write
= generic_file_aio_write
,
224 .mmap
= generic_file_mmap
,
225 .flush
= yaffs_file_flush
,
226 .fsync
= yaffs_sync_object
,
227 .splice_read
= generic_file_splice_read
,
228 .splice_write
= generic_file_splice_write
,
231 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
233 static struct file_operations yaffs_file_operations
= {
234 .read
= do_sync_read
,
235 .write
= do_sync_write
,
236 .aio_read
= generic_file_aio_read
,
237 .aio_write
= generic_file_aio_write
,
238 .mmap
= generic_file_mmap
,
239 .flush
= yaffs_file_flush
,
240 .fsync
= yaffs_sync_object
,
241 .sendfile
= generic_file_sendfile
,
246 static struct file_operations yaffs_file_operations
= {
247 .read
= generic_file_read
,
248 .write
= generic_file_write
,
249 .mmap
= generic_file_mmap
,
250 .flush
= yaffs_file_flush
,
251 .fsync
= yaffs_sync_object
,
252 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
253 .sendfile
= generic_file_sendfile
,
258 static struct inode_operations yaffs_file_inode_operations
= {
259 .setattr
= yaffs_setattr
,
262 static struct inode_operations yaffs_symlink_inode_operations
= {
263 .readlink
= yaffs_readlink
,
264 .follow_link
= yaffs_follow_link
,
265 .setattr
= yaffs_setattr
,
268 static struct inode_operations yaffs_dir_inode_operations
= {
269 .create
= yaffs_create
,
270 .lookup
= yaffs_lookup
,
272 .unlink
= yaffs_unlink
,
273 .symlink
= yaffs_symlink
,
274 .mkdir
= yaffs_mkdir
,
275 .rmdir
= yaffs_unlink
,
276 .mknod
= yaffs_mknod
,
277 .rename
= yaffs_rename
,
278 .setattr
= yaffs_setattr
,
281 static struct file_operations yaffs_dir_operations
= {
282 .read
= generic_read_dir
,
283 .readdir
= yaffs_readdir
,
284 .fsync
= yaffs_sync_object
,
287 static struct super_operations yaffs_super_ops
= {
288 .statfs
= yaffs_statfs
,
289 .read_inode
= yaffs_read_inode
,
290 .put_inode
= yaffs_put_inode
,
291 .put_super
= yaffs_put_super
,
292 .delete_inode
= yaffs_delete_inode
,
293 .clear_inode
= yaffs_clear_inode
,
294 .sync_fs
= yaffs_sync_fs
,
295 .write_super
= yaffs_write_super
,
298 static void yaffs_GrossLock(yaffs_Device
* dev
)
300 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs locking\n"));
302 down(&dev
->grossLock
);
305 static void yaffs_GrossUnlock(yaffs_Device
* dev
)
307 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs unlocking\n"));
312 static int yaffs_readlink(struct dentry
*dentry
, char __user
* buffer
,
315 unsigned char *alias
;
318 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
320 yaffs_GrossLock(dev
);
322 alias
= yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry
));
324 yaffs_GrossUnlock(dev
);
329 ret
= vfs_readlink(dentry
, buffer
, buflen
, alias
);
334 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
335 static void *yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
)
337 static int yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
)
340 unsigned char *alias
;
342 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
344 yaffs_GrossLock(dev
);
346 alias
= yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry
));
348 yaffs_GrossUnlock(dev
);
356 ret
= vfs_follow_link(nd
, alias
);
359 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
360 return ERR_PTR (ret
);
366 struct inode
*yaffs_get_inode(struct super_block
*sb
, int mode
, int dev
,
370 * Lookup is used to find objects in the fs
372 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
374 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
,
377 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
)
381 struct inode
*inode
= NULL
; /* NCB 2.5/2.6 needs NULL here */
383 yaffs_Device
*dev
= yaffs_InodeToObject(dir
)->myDev
;
385 yaffs_GrossLock(dev
);
388 (KERN_DEBUG
"yaffs_lookup for %d:%s\n",
389 yaffs_InodeToObject(dir
)->objectId
, dentry
->d_name
.name
));
392 yaffs_FindObjectByName(yaffs_InodeToObject(dir
),
393 dentry
->d_name
.name
);
395 obj
= yaffs_GetEquivalentObject(obj
); /* in case it was a hardlink */
397 /* Can't hold gross lock when calling yaffs_get_inode() */
398 yaffs_GrossUnlock(dev
);
402 (KERN_DEBUG
"yaffs_lookup found %d\n", obj
->objectId
));
404 inode
= yaffs_get_inode(dir
->i_sb
, obj
->yst_mode
, 0, obj
);
408 (KERN_DEBUG
"yaffs_loookup dentry \n"));
409 /* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
410 * d_add even if NULL inode */
412 /*dget(dentry); // try to solve directory bug */
413 d_add(dentry
, inode
);
421 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_lookup not found\n"));
425 /* added NCB for 2.5/6 compatability - forces add even if inode is
426 * NULL which creates dentry hash */
427 d_add(dentry
, inode
);
430 /* return (ERR_PTR(-EIO)); */
434 /* For now put inode is just for debugging
435 * Put inode is called when the inode **structure** is put.
437 static void yaffs_put_inode(struct inode
*inode
)
440 ("yaffs_put_inode: ino %d, count %d\n", (int)inode
->i_ino
,
441 atomic_read(&inode
->i_count
)));
445 /* clear is called to tell the fs to release any per-inode data it holds */
446 static void yaffs_clear_inode(struct inode
*inode
)
451 obj
= yaffs_InodeToObject(inode
);
454 ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode
->i_ino
,
455 atomic_read(&inode
->i_count
),
456 obj
? "object exists" : "null object"));
460 yaffs_GrossLock(dev
);
462 /* Clear the association between the inode and
466 yaffs_InodeToObjectLV(inode
) = NULL
;
468 /* If the object freeing was deferred, then the real
470 * This should fix the inode inconsistency problem.
473 yaffs_HandleDeferedFree(obj
);
475 yaffs_GrossUnlock(dev
);
480 /* delete is called when the link count is zero and the inode
481 * is put (ie. nobody wants to know about it anymore, time to
483 * NB Must call clear_inode()
485 static void yaffs_delete_inode(struct inode
*inode
)
487 yaffs_Object
*obj
= yaffs_InodeToObject(inode
);
491 ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode
->i_ino
,
492 atomic_read(&inode
->i_count
),
493 obj
? "object exists" : "null object"));
497 yaffs_GrossLock(dev
);
498 yaffs_DeleteFile(obj
);
499 yaffs_GrossUnlock(dev
);
501 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
502 truncate_inode_pages (&inode
->i_data
, 0);
507 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
508 static int yaffs_file_flush(struct file
*file
, fl_owner_t id
)
510 static int yaffs_file_flush(struct file
*file
)
513 yaffs_Object
*obj
= yaffs_DentryToObject(file
->f_dentry
);
515 yaffs_Device
*dev
= obj
->myDev
;
518 (KERN_DEBUG
"yaffs_file_flush object %d (%s)\n", obj
->objectId
,
519 obj
->dirty
? "dirty" : "clean"));
521 yaffs_GrossLock(dev
);
523 yaffs_FlushFile(obj
, 1);
525 yaffs_GrossUnlock(dev
);
530 static int yaffs_readpage_nolock(struct file
*f
, struct page
*pg
)
532 /* Lifted from jffs2 */
535 unsigned char *pg_buf
;
540 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_readpage at %08x, size %08x\n",
541 (unsigned)(pg
->index
<< PAGE_CACHE_SHIFT
),
542 (unsigned)PAGE_CACHE_SIZE
));
544 obj
= yaffs_DentryToObject(f
->f_dentry
);
548 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
549 BUG_ON(!PageLocked(pg
));
556 /* FIXME: Can kmap fail? */
558 yaffs_GrossLock(dev
);
561 yaffs_ReadDataFromFile(obj
, pg_buf
, pg
->index
<< PAGE_CACHE_SHIFT
,
564 yaffs_GrossUnlock(dev
);
570 ClearPageUptodate(pg
);
577 flush_dcache_page(pg
);
580 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_readpage done\n"));
584 static int yaffs_readpage_unlock(struct file
*f
, struct page
*pg
)
586 int ret
= yaffs_readpage_nolock(f
, pg
);
591 static int yaffs_readpage(struct file
*f
, struct page
*pg
)
593 return yaffs_readpage_unlock(f
, pg
);
596 /* writepage inspired by/stolen from smbfs */
598 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
599 static int yaffs_writepage(struct page
*page
, struct writeback_control
*wbc
)
601 static int yaffs_writepage(struct page
*page
)
604 struct address_space
*mapping
= page
->mapping
;
605 loff_t offset
= (loff_t
) page
->index
<< PAGE_CACHE_SHIFT
;
607 unsigned long end_index
;
615 inode
= mapping
->host
;
619 if (offset
> inode
->i_size
) {
622 "yaffs_writepage at %08x, inode size = %08x!!!\n",
623 (unsigned)(page
->index
<< PAGE_CACHE_SHIFT
),
624 (unsigned)inode
->i_size
));
626 (KERN_DEBUG
" -> don't care!!\n"));
631 end_index
= inode
->i_size
>> PAGE_CACHE_SHIFT
;
634 if (page
->index
< end_index
) {
635 nBytes
= PAGE_CACHE_SIZE
;
637 nBytes
= inode
->i_size
& (PAGE_CACHE_SIZE
- 1);
644 obj
= yaffs_InodeToObject(inode
);
645 yaffs_GrossLock(obj
->myDev
);
648 (KERN_DEBUG
"yaffs_writepage at %08x, size %08x\n",
649 (unsigned)(page
->index
<< PAGE_CACHE_SHIFT
), nBytes
));
651 (KERN_DEBUG
"writepag0: obj = %05x, ino = %05x\n",
652 (int)obj
->variant
.fileVariant
.fileSize
, (int)inode
->i_size
));
655 yaffs_WriteDataToFile(obj
, buffer
, page
->index
<< PAGE_CACHE_SHIFT
,
659 (KERN_DEBUG
"writepag1: obj = %05x, ino = %05x\n",
660 (int)obj
->variant
.fileVariant
.fileSize
, (int)inode
->i_size
));
662 yaffs_GrossUnlock(obj
->myDev
);
665 SetPageUptodate(page
);
669 return (nWritten
== nBytes
) ? 0 : -ENOSPC
;
672 static int yaffs_prepare_write(struct file
*f
, struct page
*pg
,
673 unsigned offset
, unsigned to
)
676 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_prepair_write\n"));
677 if (!Page_Uptodate(pg
) && (offset
|| to
< PAGE_CACHE_SIZE
))
678 return yaffs_readpage_nolock(f
, pg
);
684 static int yaffs_commit_write(struct file
*f
, struct page
*pg
, unsigned offset
,
688 void *addr
= page_address(pg
) + offset
;
689 loff_t pos
= (((loff_t
) pg
->index
) << PAGE_CACHE_SHIFT
) + offset
;
690 int nBytes
= to
- offset
;
694 unsigned saddr
= (unsigned)addr
;
697 (KERN_DEBUG
"yaffs_commit_write addr %x pos %x nBytes %d\n", saddr
,
700 nWritten
= yaffs_file_write(f
, addr
, nBytes
, &pos
);
702 if (nWritten
!= nBytes
) {
705 "yaffs_commit_write not same size nWritten %d nBytes %d\n",
708 ClearPageUptodate(pg
);
714 (KERN_DEBUG
"yaffs_commit_write returning %d\n",
715 nWritten
== nBytes
? 0 : nWritten
));
717 return nWritten
== nBytes
? 0 : nWritten
;
721 static void yaffs_FillInodeFromObject(struct inode
*inode
, yaffs_Object
* obj
)
726 /* Check mode against the variant type and attempt to repair if broken. */
727 __u32 mode
= obj
->yst_mode
;
728 switch( obj
->variantType
){
729 case YAFFS_OBJECT_TYPE_FILE
:
730 if( ! S_ISREG(mode
) ){
731 obj
->yst_mode
&= ~S_IFMT
;
732 obj
->yst_mode
|= S_IFREG
;
736 case YAFFS_OBJECT_TYPE_SYMLINK
:
737 if( ! S_ISLNK(mode
) ){
738 obj
->yst_mode
&= ~S_IFMT
;
739 obj
->yst_mode
|= S_IFLNK
;
743 case YAFFS_OBJECT_TYPE_DIRECTORY
:
744 if( ! S_ISDIR(mode
) ){
745 obj
->yst_mode
&= ~S_IFMT
;
746 obj
->yst_mode
|= S_IFDIR
;
750 case YAFFS_OBJECT_TYPE_UNKNOWN
:
751 case YAFFS_OBJECT_TYPE_HARDLINK
:
752 case YAFFS_OBJECT_TYPE_SPECIAL
:
758 inode
->i_flags
|= S_NOATIME
;
760 inode
->i_ino
= obj
->objectId
;
761 inode
->i_mode
= obj
->yst_mode
;
762 inode
->i_uid
= obj
->yst_uid
;
763 inode
->i_gid
= obj
->yst_gid
;
764 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
765 inode
->i_blksize
= inode
->i_sb
->s_blocksize
;
767 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
769 inode
->i_rdev
= old_decode_dev(obj
->yst_rdev
);
770 inode
->i_atime
.tv_sec
= (time_t) (obj
->yst_atime
);
771 inode
->i_atime
.tv_nsec
= 0;
772 inode
->i_mtime
.tv_sec
= (time_t) obj
->yst_mtime
;
773 inode
->i_mtime
.tv_nsec
= 0;
774 inode
->i_ctime
.tv_sec
= (time_t) obj
->yst_ctime
;
775 inode
->i_ctime
.tv_nsec
= 0;
777 inode
->i_rdev
= obj
->yst_rdev
;
778 inode
->i_atime
= obj
->yst_atime
;
779 inode
->i_mtime
= obj
->yst_mtime
;
780 inode
->i_ctime
= obj
->yst_ctime
;
782 inode
->i_size
= yaffs_GetObjectFileLength(obj
);
783 inode
->i_blocks
= (inode
->i_size
+ 511) >> 9;
785 inode
->i_nlink
= yaffs_GetObjectLinkCount(obj
);
789 "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
790 inode
->i_mode
, inode
->i_uid
, inode
->i_gid
,
791 (int)inode
->i_size
, atomic_read(&inode
->i_count
)));
793 switch (obj
->yst_mode
& S_IFMT
) {
794 default: /* fifo, device or socket */
795 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
796 init_special_inode(inode
, obj
->yst_mode
,
797 old_decode_dev(obj
->yst_rdev
));
799 init_special_inode(inode
, obj
->yst_mode
,
800 (dev_t
) (obj
->yst_rdev
));
803 case S_IFREG
: /* file */
804 inode
->i_op
= &yaffs_file_inode_operations
;
805 inode
->i_fop
= &yaffs_file_operations
;
806 inode
->i_mapping
->a_ops
=
807 &yaffs_file_address_operations
;
809 case S_IFDIR
: /* directory */
810 inode
->i_op
= &yaffs_dir_inode_operations
;
811 inode
->i_fop
= &yaffs_dir_operations
;
813 case S_IFLNK
: /* symlink */
814 inode
->i_op
= &yaffs_symlink_inode_operations
;
818 yaffs_InodeToObjectLV(inode
) = obj
;
820 obj
->myInode
= inode
;
824 (KERN_DEBUG
"yaffs_FileInode invalid parameters\n"));
829 struct inode
*yaffs_get_inode(struct super_block
*sb
, int mode
, int dev
,
836 (KERN_DEBUG
"yaffs_get_inode for NULL super_block!!\n"));
843 (KERN_DEBUG
"yaffs_get_inode for NULL object!!\n"));
849 (KERN_DEBUG
"yaffs_get_inode for object %d\n", obj
->objectId
));
851 inode
= iget(sb
, obj
->objectId
);
853 /* NB Side effect: iget calls back to yaffs_read_inode(). */
854 /* iget also increments the inode's i_count */
855 /* NB You can't be holding grossLock or deadlock will happen! */
860 static ssize_t
yaffs_file_write(struct file
*f
, const char *buf
, size_t n
,
868 obj
= yaffs_DentryToObject(f
->f_dentry
);
872 yaffs_GrossLock(dev
);
874 inode
= f
->f_dentry
->d_inode
;
876 if (!S_ISBLK(inode
->i_mode
) && f
->f_flags
& O_APPEND
) {
877 ipos
= inode
->i_size
;
884 (KERN_DEBUG
"yaffs_file_write: hey obj is null!\n"));
888 "yaffs_file_write about to write writing %d bytes"
889 "to object %d at %d\n",
890 n
, obj
->objectId
, ipos
));
893 nWritten
= yaffs_WriteDataToFile(obj
, buf
, ipos
, n
, 0);
896 (KERN_DEBUG
"yaffs_file_write writing %d bytes, %d written at %d\n",
901 if (ipos
> inode
->i_size
) {
902 inode
->i_size
= ipos
;
903 inode
->i_blocks
= (ipos
+ 511) >> 9;
907 "yaffs_file_write size updated to %d bytes, "
909 ipos
, (int)(inode
->i_blocks
)));
913 yaffs_GrossUnlock(dev
);
914 return nWritten
== 0 ? -ENOSPC
: nWritten
;
917 static int yaffs_readdir(struct file
*f
, void *dirent
, filldir_t filldir
)
921 struct inode
*inode
= f
->f_dentry
->d_inode
;
922 unsigned long offset
, curoffs
;
926 char name
[YAFFS_MAX_NAME_LENGTH
+ 1];
928 obj
= yaffs_DentryToObject(f
->f_dentry
);
931 yaffs_GrossLock(dev
);
935 T(YAFFS_TRACE_OS
, ("yaffs_readdir: starting at %d\n", (int)offset
));
939 (KERN_DEBUG
"yaffs_readdir: entry . ino %d \n",
941 if (filldir(dirent
, ".", 1, offset
, inode
->i_ino
, DT_DIR
)
950 (KERN_DEBUG
"yaffs_readdir: entry .. ino %d \n",
951 (int)f
->f_dentry
->d_parent
->d_inode
->i_ino
));
953 (dirent
, "..", 2, offset
,
954 f
->f_dentry
->d_parent
->d_inode
->i_ino
, DT_DIR
) < 0) {
963 /* If the directory has changed since the open or last call to
964 readdir, rewind to after the 2 canned entries. */
966 if (f
->f_version
!= inode
->i_version
) {
969 f
->f_version
= inode
->i_version
;
972 list_for_each(i
, &obj
->variant
.directoryVariant
.children
) {
974 if (curoffs
>= offset
) {
975 l
= list_entry(i
, yaffs_Object
, siblings
);
977 yaffs_GetObjectName(l
, name
,
978 YAFFS_MAX_NAME_LENGTH
+ 1);
980 (KERN_DEBUG
"yaffs_readdir: %s inode %d\n", name
,
981 yaffs_GetObjectInode(l
)));
987 yaffs_GetObjectInode(l
),
988 yaffs_GetObjectType(l
))
1001 yaffs_GrossUnlock(dev
);
1007 * File creation. Allocate an inode, and we're done..
1009 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1010 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1013 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1017 struct inode
*inode
;
1019 yaffs_Object
*obj
= NULL
;
1022 yaffs_Object
*parent
= yaffs_InodeToObject(dir
);
1024 int error
= -ENOSPC
;
1025 uid_t uid
= current
->fsuid
;
1026 gid_t gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
1028 if((dir
->i_mode
& S_ISGID
) && S_ISDIR(mode
))
1033 (KERN_DEBUG
"yaffs_mknod: parent object %d type %d\n",
1034 parent
->objectId
, parent
->variantType
));
1037 (KERN_DEBUG
"yaffs_mknod: could not get parent object\n"));
1041 T(YAFFS_TRACE_OS
, ("yaffs_mknod: making oject for %s, "
1043 dentry
->d_name
.name
, mode
, rdev
));
1045 dev
= parent
->myDev
;
1047 yaffs_GrossLock(dev
);
1049 switch (mode
& S_IFMT
) {
1051 /* Special (socket, fifo, device...) */
1052 T(YAFFS_TRACE_OS
, (KERN_DEBUG
1053 "yaffs_mknod: making special\n"));
1054 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1056 yaffs_MknodSpecial(parent
, dentry
->d_name
.name
, mode
, uid
,
1057 gid
, old_encode_dev(rdev
));
1060 yaffs_MknodSpecial(parent
, dentry
->d_name
.name
, mode
, uid
,
1064 case S_IFREG
: /* file */
1065 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mknod: making file\n"));
1067 yaffs_MknodFile(parent
, dentry
->d_name
.name
, mode
, uid
,
1070 case S_IFDIR
: /* directory */
1072 (KERN_DEBUG
"yaffs_mknod: making directory\n"));
1074 yaffs_MknodDirectory(parent
, dentry
->d_name
.name
, mode
,
1077 case S_IFLNK
: /* symlink */
1078 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mknod: making file\n"));
1079 obj
= NULL
; /* Do we ever get here? */
1083 /* Can not call yaffs_get_inode() with gross lock held */
1084 yaffs_GrossUnlock(dev
);
1087 inode
= yaffs_get_inode(dir
->i_sb
, mode
, rdev
, obj
);
1088 d_instantiate(dentry
, inode
);
1090 (KERN_DEBUG
"yaffs_mknod created object %d count = %d\n",
1091 obj
->objectId
, atomic_read(&inode
->i_count
)));
1095 (KERN_DEBUG
"yaffs_mknod failed making object\n"));
1102 static int yaffs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
)
1105 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mkdir\n"));
1106 retVal
= yaffs_mknod(dir
, dentry
, mode
| S_IFDIR
, 0);
1108 /* attempt to fix dir bug - didn't work */
1116 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1117 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1118 struct nameidata
*n
)
1120 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
)
1123 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_create\n"));
1124 return yaffs_mknod(dir
, dentry
, mode
| S_IFREG
, 0);
1127 static int yaffs_unlink(struct inode
*dir
, struct dentry
*dentry
)
1134 (KERN_DEBUG
"yaffs_unlink %d:%s\n", (int)(dir
->i_ino
),
1135 dentry
->d_name
.name
));
1137 dev
= yaffs_InodeToObject(dir
)->myDev
;
1139 yaffs_GrossLock(dev
);
1141 retVal
= yaffs_Unlink(yaffs_InodeToObject(dir
), dentry
->d_name
.name
);
1143 if (retVal
== YAFFS_OK
) {
1144 dentry
->d_inode
->i_nlink
--;
1146 yaffs_GrossUnlock(dev
);
1147 mark_inode_dirty(dentry
->d_inode
);
1150 yaffs_GrossUnlock(dev
);
1157 static int yaffs_link(struct dentry
*old_dentry
, struct inode
*dir
,
1158 struct dentry
*dentry
)
1160 struct inode
*inode
= old_dentry
->d_inode
;
1161 yaffs_Object
*obj
= NULL
;
1162 yaffs_Object
*link
= NULL
;
1165 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_link\n"));
1167 obj
= yaffs_InodeToObject(inode
);
1170 yaffs_GrossLock(dev
);
1172 if (!S_ISDIR(inode
->i_mode
)) /* Don't link directories */
1175 yaffs_Link(yaffs_InodeToObject(dir
), dentry
->d_name
.name
,
1180 old_dentry
->d_inode
->i_nlink
= yaffs_GetObjectLinkCount(obj
);
1181 d_instantiate(dentry
, old_dentry
->d_inode
);
1182 atomic_inc(&old_dentry
->d_inode
->i_count
);
1184 (KERN_DEBUG
"yaffs_link link count %d i_count %d\n",
1185 old_dentry
->d_inode
->i_nlink
,
1186 atomic_read(&old_dentry
->d_inode
->i_count
)));
1190 yaffs_GrossUnlock(dev
);
1200 static int yaffs_symlink(struct inode
*dir
, struct dentry
*dentry
,
1201 const char *symname
)
1205 uid_t uid
= current
->fsuid
;
1206 gid_t gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
1208 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_symlink\n"));
1210 dev
= yaffs_InodeToObject(dir
)->myDev
;
1211 yaffs_GrossLock(dev
);
1212 obj
= yaffs_MknodSymLink(yaffs_InodeToObject(dir
), dentry
->d_name
.name
,
1213 S_IFLNK
| S_IRWXUGO
, uid
, gid
, symname
);
1214 yaffs_GrossUnlock(dev
);
1218 struct inode
*inode
;
1220 inode
= yaffs_get_inode(dir
->i_sb
, obj
->yst_mode
, 0, obj
);
1221 d_instantiate(dentry
, inode
);
1222 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"symlink created OK\n"));
1225 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"symlink not created\n"));
1232 static int yaffs_sync_object(struct file
*file
, struct dentry
*dentry
,
1239 obj
= yaffs_DentryToObject(dentry
);
1243 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_sync_object\n"));
1244 yaffs_GrossLock(dev
);
1245 yaffs_FlushFile(obj
, 1);
1246 yaffs_GrossUnlock(dev
);
1251 * The VFS layer already does all the dentry stuff for rename.
1253 * NB: POSIX says you can rename an object over an old object of the same name
1255 static int yaffs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
1256 struct inode
*new_dir
, struct dentry
*new_dentry
)
1259 int retVal
= YAFFS_FAIL
;
1260 yaffs_Object
*target
;
1262 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_rename\n"));
1263 dev
= yaffs_InodeToObject(old_dir
)->myDev
;
1265 yaffs_GrossLock(dev
);
1267 /* Check if the target is an existing directory that is not empty. */
1269 yaffs_FindObjectByName(yaffs_InodeToObject(new_dir
),
1270 new_dentry
->d_name
.name
);
1275 target
->variantType
== YAFFS_OBJECT_TYPE_DIRECTORY
&&
1276 !list_empty(&target
->variant
.directoryVariant
.children
)) {
1278 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"target is non-empty dir\n"));
1280 retVal
= YAFFS_FAIL
;
1283 /* Now does unlinking internally using shadowing mechanism */
1284 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"calling yaffs_RenameObject\n"));
1287 yaffs_RenameObject(yaffs_InodeToObject(old_dir
),
1288 old_dentry
->d_name
.name
,
1289 yaffs_InodeToObject(new_dir
),
1290 new_dentry
->d_name
.name
);
1293 yaffs_GrossUnlock(dev
);
1295 if (retVal
== YAFFS_OK
) {
1297 new_dentry
->d_inode
->i_nlink
--;
1298 mark_inode_dirty(new_dentry
->d_inode
);
1308 static int yaffs_setattr(struct dentry
*dentry
, struct iattr
*attr
)
1310 struct inode
*inode
= dentry
->d_inode
;
1315 (KERN_DEBUG
"yaffs_setattr of object %d\n",
1316 yaffs_InodeToObject(inode
)->objectId
));
1318 if ((error
= inode_change_ok(inode
, attr
)) == 0) {
1320 dev
= yaffs_InodeToObject(inode
)->myDev
;
1321 yaffs_GrossLock(dev
);
1322 if (yaffs_SetAttributes(yaffs_InodeToObject(inode
), attr
) ==
1328 yaffs_GrossUnlock(dev
);
1330 error
= inode_setattr(inode
, attr
);
1335 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1336 static int yaffs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
)
1338 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
1339 struct super_block
*sb
= dentry
->d_sb
;
1340 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1341 static int yaffs_statfs(struct super_block
*sb
, struct kstatfs
*buf
)
1343 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1345 static int yaffs_statfs(struct super_block
*sb
, struct statfs
*buf
)
1347 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1350 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_statfs\n"));
1352 yaffs_GrossLock(dev
);
1354 buf
->f_type
= YAFFS_MAGIC
;
1355 buf
->f_bsize
= sb
->s_blocksize
;
1356 buf
->f_namelen
= 255;
1358 if(dev
->nDataBytesPerChunk
& (dev
->nDataBytesPerChunk
- 1)){
1359 /* Do this if chunk size is not a power of 2 */
1361 uint64_t bytesInDev
;
1364 bytesInDev
= ((uint64_t)((dev
->endBlock
- dev
->startBlock
+1))) *
1365 ((uint64_t)(dev
->nChunksPerBlock
* dev
->nDataBytesPerChunk
));
1367 do_div(bytesInDev
,sb
->s_blocksize
); /* bytesInDev becomes the number of blocks */
1368 buf
->f_blocks
= bytesInDev
;
1370 bytesFree
= ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev
))) *
1371 ((uint64_t)(dev
->nDataBytesPerChunk
));
1373 do_div(bytesFree
,sb
->s_blocksize
);
1375 buf
->f_bfree
= bytesFree
;
1377 } else if (sb
->s_blocksize
> dev
->nDataBytesPerChunk
) {
1380 (dev
->endBlock
- dev
->startBlock
+ 1) *
1381 dev
->nChunksPerBlock
/
1382 (sb
->s_blocksize
/ dev
->nDataBytesPerChunk
);
1384 yaffs_GetNumberOfFreeChunks(dev
) /
1385 (sb
->s_blocksize
/ dev
->nDataBytesPerChunk
);
1388 (dev
->endBlock
- dev
->startBlock
+ 1) *
1389 dev
->nChunksPerBlock
*
1390 (dev
->nDataBytesPerChunk
/ sb
->s_blocksize
);
1393 yaffs_GetNumberOfFreeChunks(dev
) *
1394 (dev
->nDataBytesPerChunk
/ sb
->s_blocksize
);
1400 buf
->f_bavail
= buf
->f_bfree
;
1402 yaffs_GrossUnlock(dev
);
1408 static int yaffs_do_sync_fs(struct super_block *sb)
1411 yaffs_Device *dev = yaffs_SuperToDevice(sb);
1412 T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
1415 yaffs_GrossLock(dev);
1418 yaffs_CheckpointSave(dev);
1420 yaffs_GrossUnlock(dev);
1428 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1429 static void yaffs_write_super(struct super_block
*sb
)
1431 static int yaffs_write_super(struct super_block
*sb
)
1435 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_write_super\n"));
1436 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
1437 return 0; /* yaffs_do_sync_fs(sb);*/
1442 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1443 static int yaffs_sync_fs(struct super_block
*sb
, int wait
)
1445 static int yaffs_sync_fs(struct super_block
*sb
)
1449 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_sync_fs\n"));
1451 return 0; /* yaffs_do_sync_fs(sb);*/
1456 static void yaffs_read_inode(struct inode
*inode
)
1458 /* NB This is called as a side effect of other functions, but
1459 * we had to release the lock to prevent deadlocks, so
1460 * need to lock again.
1464 yaffs_Device
*dev
= yaffs_SuperToDevice(inode
->i_sb
);
1467 (KERN_DEBUG
"yaffs_read_inode for %d\n", (int)inode
->i_ino
));
1469 yaffs_GrossLock(dev
);
1471 obj
= yaffs_FindObjectByNumber(dev
, inode
->i_ino
);
1473 yaffs_FillInodeFromObject(inode
, obj
);
1475 yaffs_GrossUnlock(dev
);
1478 static LIST_HEAD(yaffs_dev_list
);
1481 static int yaffs_remount_fs(struct super_block
*sb
, int *flags
, char *data
)
1483 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1485 if( *flags
& MS_RDONLY
) {
1486 struct mtd_info
*mtd
= yaffs_SuperToDevice(sb
)->genericDevice
;
1489 (KERN_DEBUG
"yaffs_remount_fs: %s: RO\n", dev
->name
));
1491 yaffs_GrossLock(dev
);
1493 yaffs_FlushEntireDeviceCache(dev
);
1495 yaffs_CheckpointSave(dev
);
1500 yaffs_GrossUnlock(dev
);
1504 (KERN_DEBUG
"yaffs_remount_fs: %s: RW\n", dev
->name
));
1511 static void yaffs_put_super(struct super_block
*sb
)
1513 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1515 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_put_super\n"));
1517 yaffs_GrossLock(dev
);
1519 yaffs_FlushEntireDeviceCache(dev
);
1521 yaffs_CheckpointSave(dev
);
1523 if (dev
->putSuperFunc
) {
1524 dev
->putSuperFunc(sb
);
1527 yaffs_Deinitialise(dev
);
1529 yaffs_GrossUnlock(dev
);
1531 /* we assume this is protected by lock_kernel() in mount/umount */
1532 list_del(&dev
->devList
);
1534 if(dev
->spareBuffer
){
1535 YFREE(dev
->spareBuffer
);
1536 dev
->spareBuffer
= NULL
;
1543 static void yaffs_MTDPutSuper(struct super_block
*sb
)
1546 struct mtd_info
*mtd
= yaffs_SuperToDevice(sb
)->genericDevice
;
1552 put_mtd_device(mtd
);
1556 static void yaffs_MarkSuperBlockDirty(void *vsb
)
1558 struct super_block
*sb
= (struct super_block
*)vsb
;
1560 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_MarkSuperBlockDirty() sb = %p\n",sb
));
1567 int skip_checkpoint_read
;
1568 int skip_checkpoint_write
;
1572 #define MAX_OPT_LEN 20
1573 static int yaffs_parse_options(yaffs_options
*options
, const char *options_str
)
1575 char cur_opt
[MAX_OPT_LEN
+1];
1579 /* Parse through the options which is a comma seperated list */
1581 while(options_str
&& *options_str
&& !error
){
1582 memset(cur_opt
,0,MAX_OPT_LEN
+1);
1585 while(*options_str
&& *options_str
!= ','){
1586 if(p
< MAX_OPT_LEN
){
1587 cur_opt
[p
] = *options_str
;
1593 if(!strcmp(cur_opt
,"inband-tags"))
1594 options
->inband_tags
= 1;
1595 else if(!strcmp(cur_opt
,"no-cache"))
1596 options
->no_cache
= 1;
1597 else if(!strcmp(cur_opt
,"no-checkpoint-read"))
1598 options
->skip_checkpoint_read
= 1;
1599 else if(!strcmp(cur_opt
,"no-checkpoint-write"))
1600 options
->skip_checkpoint_write
= 1;
1601 else if(!strcmp(cur_opt
,"no-checkpoint")){
1602 options
->skip_checkpoint_read
= 1;
1603 options
->skip_checkpoint_write
= 1;
1605 printk(KERN_INFO
"yaffs: Bad mount option \"%s\"\n",cur_opt
);
1614 static struct super_block
*yaffs_internal_read_super(int yaffsVersion
,
1615 struct super_block
*sb
,
1616 void *data
, int silent
)
1619 struct inode
*inode
= NULL
;
1620 struct dentry
*root
;
1621 yaffs_Device
*dev
= 0;
1622 char devname_buf
[BDEVNAME_SIZE
+ 1];
1623 struct mtd_info
*mtd
;
1625 char *data_str
= (char *)data
;
1627 yaffs_options options
;
1629 sb
->s_magic
= YAFFS_MAGIC
;
1630 sb
->s_op
= &yaffs_super_ops
;
1631 sb
->s_flags
|= MS_NOATIME
;
1634 printk(KERN_INFO
"yaffs: sb is NULL\n");
1635 else if (!sb
->s_dev
)
1636 printk(KERN_INFO
"yaffs: sb->s_dev is NULL\n");
1637 else if (!yaffs_devname(sb
, devname_buf
))
1638 printk(KERN_INFO
"yaffs: devname is NULL\n");
1640 printk(KERN_INFO
"yaffs: dev is %d name is \"%s\"\n",
1642 yaffs_devname(sb
, devname_buf
));
1647 printk(KERN_INFO
"yaffs: passed flags \"%s\"\n",data_str
);
1649 memset(&options
,0,sizeof(options
));
1651 if(yaffs_parse_options(&options
,data_str
)){
1652 /* Option parsing failed */
1657 sb
->s_blocksize
= PAGE_CACHE_SIZE
;
1658 sb
->s_blocksize_bits
= PAGE_CACHE_SHIFT
;
1659 T(YAFFS_TRACE_OS
, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion
));
1661 ("yaffs_read_super: block size %d\n", (int)(sb
->s_blocksize
)));
1663 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1665 ("yaffs: Write verification disabled. All guarantees "
1666 "null and void\n"));
1669 T(YAFFS_TRACE_ALWAYS
, ("yaffs: Attempting MTD mount on %u.%u, "
1671 MAJOR(sb
->s_dev
), MINOR(sb
->s_dev
),
1672 yaffs_devname(sb
, devname_buf
)));
1674 /* Check it's an mtd device..... */
1675 if (MAJOR(sb
->s_dev
) != MTD_BLOCK_MAJOR
) {
1676 return NULL
; /* This isn't an mtd device */
1678 /* Get the device */
1679 mtd
= get_mtd_device(NULL
, MINOR(sb
->s_dev
));
1681 T(YAFFS_TRACE_ALWAYS
,
1682 ("yaffs: MTD device #%u doesn't appear to exist\n",
1686 /* Check it's NAND */
1687 if (mtd
->type
!= MTD_NANDFLASH
) {
1688 T(YAFFS_TRACE_ALWAYS
,
1689 ("yaffs: MTD device is not NAND it's type %d\n", mtd
->type
));
1693 T(YAFFS_TRACE_OS
, (" erase %p\n", mtd
->erase
));
1694 T(YAFFS_TRACE_OS
, (" read %p\n", mtd
->read
));
1695 T(YAFFS_TRACE_OS
, (" write %p\n", mtd
->write
));
1696 T(YAFFS_TRACE_OS
, (" readoob %p\n", mtd
->read_oob
));
1697 T(YAFFS_TRACE_OS
, (" writeoob %p\n", mtd
->write_oob
));
1698 T(YAFFS_TRACE_OS
, (" block_isbad %p\n", mtd
->block_isbad
));
1699 T(YAFFS_TRACE_OS
, (" block_markbad %p\n", mtd
->block_markbad
));
1700 T(YAFFS_TRACE_OS
, (" %s %d\n", WRITE_SIZE_STR
, WRITE_SIZE(mtd
)));
1701 T(YAFFS_TRACE_OS
, (" oobsize %d\n", mtd
->oobsize
));
1702 T(YAFFS_TRACE_OS
, (" erasesize %d\n", mtd
->erasesize
));
1703 T(YAFFS_TRACE_OS
, (" size %d\n", mtd
->size
));
1705 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
1707 if (yaffsVersion
== 1 &&
1708 WRITE_SIZE(mtd
) >= 2048) {
1709 T(YAFFS_TRACE_ALWAYS
,("yaffs: auto selecting yaffs2\n"));
1713 /* Added NCB 26/5/2006 for completeness */
1714 if (yaffsVersion
== 2 &&
1715 !options
.inband_tags
&&
1716 WRITE_SIZE(mtd
) == 512){
1717 T(YAFFS_TRACE_ALWAYS
,("yaffs: auto selecting yaffs1\n"));
1723 if (yaffsVersion
== 2) {
1724 /* Check for version 2 style functions */
1726 !mtd
->block_isbad
||
1727 !mtd
->block_markbad
||
1730 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1731 !mtd
->read_oob
|| !mtd
->write_oob
) {
1734 !mtd
->read_ecc
|| !mtd
->read_oob
|| !mtd
->write_oob
) {
1736 T(YAFFS_TRACE_ALWAYS
,
1737 ("yaffs: MTD device does not support required "
1742 if ((WRITE_SIZE(mtd
) < YAFFS_MIN_YAFFS2_CHUNK_SIZE
||
1743 mtd
->oobsize
< YAFFS_MIN_YAFFS2_SPARE_SIZE
) &&
1744 !options
.inband_tags
) {
1745 T(YAFFS_TRACE_ALWAYS
,
1746 ("yaffs: MTD device does not have the "
1747 "right page sizes\n"));
1751 /* Check for V1 style functions */
1755 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1756 !mtd
->read_oob
|| !mtd
->write_oob
) {
1759 !mtd
->read_ecc
|| !mtd
->read_oob
|| !mtd
->write_oob
) {
1761 T(YAFFS_TRACE_ALWAYS
,
1762 ("yaffs: MTD device does not support required "
1767 if (WRITE_SIZE(mtd
) < YAFFS_BYTES_PER_CHUNK
||
1768 mtd
->oobsize
!= YAFFS_BYTES_PER_SPARE
) {
1769 T(YAFFS_TRACE_ALWAYS
,
1770 ("yaffs: MTD device does not support have the "
1771 "right page sizes\n"));
1776 /* OK, so if we got here, we have an MTD that's NAND and looks
1777 * like it has the right capabilities
1778 * Set the yaffs_Device up for mtd
1781 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1782 sb
->s_fs_info
= dev
= kmalloc(sizeof(yaffs_Device
), GFP_KERNEL
);
1784 sb
->u
.generic_sbp
= dev
= kmalloc(sizeof(yaffs_Device
), GFP_KERNEL
);
1787 /* Deep shit could not allocate device structure */
1788 T(YAFFS_TRACE_ALWAYS
,
1789 ("yaffs_read_super: Failed trying to allocate "
1790 "yaffs_Device. \n"));
1794 memset(dev
, 0, sizeof(yaffs_Device
));
1795 dev
->genericDevice
= mtd
;
1796 dev
->name
= mtd
->name
;
1798 /* Set up the memory size parameters.... */
1800 nBlocks
= mtd
->size
/ (YAFFS_CHUNKS_PER_BLOCK
* YAFFS_BYTES_PER_CHUNK
);
1801 dev
->startBlock
= 0;
1802 dev
->endBlock
= nBlocks
- 1;
1803 dev
->nChunksPerBlock
= YAFFS_CHUNKS_PER_BLOCK
;
1804 dev
->totalBytesPerChunk
= YAFFS_BYTES_PER_CHUNK
;
1805 dev
->nReservedBlocks
= 5;
1806 dev
->nShortOpCaches
= (options
.no_cache
) ? 0 : 10;
1807 dev
->inbandTags
= options
.inband_tags
;
1809 /* ... and the functions. */
1810 if (yaffsVersion
== 2) {
1811 dev
->writeChunkWithTagsToNAND
=
1812 nandmtd2_WriteChunkWithTagsToNAND
;
1813 dev
->readChunkWithTagsFromNAND
=
1814 nandmtd2_ReadChunkWithTagsFromNAND
;
1815 dev
->markNANDBlockBad
= nandmtd2_MarkNANDBlockBad
;
1816 dev
->queryNANDBlock
= nandmtd2_QueryNANDBlock
;
1817 dev
->spareBuffer
= YMALLOC(mtd
->oobsize
);
1819 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1820 dev
->totalBytesPerChunk
= mtd
->writesize
;
1821 dev
->nChunksPerBlock
= mtd
->erasesize
/ mtd
->writesize
;
1823 dev
->totalBytesPerChunk
= mtd
->oobblock
;
1824 dev
->nChunksPerBlock
= mtd
->erasesize
/ mtd
->oobblock
;
1826 nBlocks
= mtd
->size
/ mtd
->erasesize
;
1828 dev
->startBlock
= 0;
1829 dev
->endBlock
= nBlocks
- 1;
1831 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1832 /* use the MTD interface in yaffs_mtdif1.c */
1833 dev
->writeChunkWithTagsToNAND
=
1834 nandmtd1_WriteChunkWithTagsToNAND
;
1835 dev
->readChunkWithTagsFromNAND
=
1836 nandmtd1_ReadChunkWithTagsFromNAND
;
1837 dev
->markNANDBlockBad
= nandmtd1_MarkNANDBlockBad
;
1838 dev
->queryNANDBlock
= nandmtd1_QueryNANDBlock
;
1840 dev
->writeChunkToNAND
= nandmtd_WriteChunkToNAND
;
1841 dev
->readChunkFromNAND
= nandmtd_ReadChunkFromNAND
;
1845 /* ... and common functions */
1846 dev
->eraseBlockInNAND
= nandmtd_EraseBlockInNAND
;
1847 dev
->initialiseNAND
= nandmtd_InitialiseNAND
;
1849 dev
->putSuperFunc
= yaffs_MTDPutSuper
;
1851 dev
->superBlock
= (void *)sb
;
1852 dev
->markSuperBlockDirty
= yaffs_MarkSuperBlockDirty
;
1855 #ifndef CONFIG_YAFFS_DOES_ECC
1856 dev
->useNANDECC
= 1;
1859 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
1860 dev
->wideTnodesDisabled
= 1;
1863 dev
->skipCheckpointRead
= options
.skip_checkpoint_read
;
1864 dev
->skipCheckpointWrite
= options
.skip_checkpoint_write
;
1866 /* we assume this is protected by lock_kernel() in mount/umount */
1867 list_add_tail(&dev
->devList
, &yaffs_dev_list
);
1869 init_MUTEX(&dev
->grossLock
);
1871 yaffs_GrossLock(dev
);
1873 err
= yaffs_GutsInitialise(dev
);
1876 ("yaffs_read_super: guts initialised %s\n",
1877 (err
== YAFFS_OK
) ? "OK" : "FAILED"));
1879 /* Release lock before yaffs_get_inode() */
1880 yaffs_GrossUnlock(dev
);
1882 /* Create root inode */
1883 if (err
== YAFFS_OK
)
1884 inode
= yaffs_get_inode(sb
, S_IFDIR
| 0755, 0,
1890 inode
->i_op
= &yaffs_dir_inode_operations
;
1891 inode
->i_fop
= &yaffs_dir_operations
;
1893 T(YAFFS_TRACE_OS
, ("yaffs_read_super: got root inode\n"));
1895 root
= d_alloc_root(inode
);
1897 T(YAFFS_TRACE_OS
, ("yaffs_read_super: d_alloc_root done\n"));
1905 T(YAFFS_TRACE_OS
, ("yaffs_read_super: done\n"));
1910 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1911 static int yaffs_internal_read_super_mtd(struct super_block
*sb
, void *data
,
1914 return yaffs_internal_read_super(1, sb
, data
, silent
) ? 0 : -EINVAL
;
1917 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1918 static int yaffs_read_super(struct file_system_type
*fs
,
1919 int flags
, const char *dev_name
,
1920 void *data
, struct vfsmount
*mnt
)
1923 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1924 yaffs_internal_read_super_mtd
, mnt
);
1927 static struct super_block
*yaffs_read_super(struct file_system_type
*fs
,
1928 int flags
, const char *dev_name
,
1932 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1933 yaffs_internal_read_super_mtd
);
1937 static struct file_system_type yaffs_fs_type
= {
1938 .owner
= THIS_MODULE
,
1940 .get_sb
= yaffs_read_super
,
1941 .kill_sb
= kill_block_super
,
1942 .fs_flags
= FS_REQUIRES_DEV
,
1945 static struct super_block
*yaffs_read_super(struct super_block
*sb
, void *data
,
1948 return yaffs_internal_read_super(1, sb
, data
, silent
);
1951 static DECLARE_FSTYPE(yaffs_fs_type
, "yaffs", yaffs_read_super
,
1956 #ifdef CONFIG_YAFFS_YAFFS2
1958 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1959 static int yaffs2_internal_read_super_mtd(struct super_block
*sb
, void *data
,
1962 return yaffs_internal_read_super(2, sb
, data
, silent
) ? 0 : -EINVAL
;
1965 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1966 static int yaffs2_read_super(struct file_system_type
*fs
,
1967 int flags
, const char *dev_name
, void *data
,
1968 struct vfsmount
*mnt
)
1970 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1971 yaffs2_internal_read_super_mtd
, mnt
);
1974 static struct super_block
*yaffs2_read_super(struct file_system_type
*fs
,
1975 int flags
, const char *dev_name
,
1979 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1980 yaffs2_internal_read_super_mtd
);
1984 static struct file_system_type yaffs2_fs_type
= {
1985 .owner
= THIS_MODULE
,
1987 .get_sb
= yaffs2_read_super
,
1988 .kill_sb
= kill_block_super
,
1989 .fs_flags
= FS_REQUIRES_DEV
,
1992 static struct super_block
*yaffs2_read_super(struct super_block
*sb
,
1993 void *data
, int silent
)
1995 return yaffs_internal_read_super(2, sb
, data
, silent
);
1998 static DECLARE_FSTYPE(yaffs2_fs_type
, "yaffs2", yaffs2_read_super
,
2002 #endif /* CONFIG_YAFFS_YAFFS2 */
2004 static struct proc_dir_entry
*my_proc_entry
;
2006 static char *yaffs_dump_dev(char *buf
, yaffs_Device
* dev
)
2008 buf
+= sprintf(buf
, "startBlock......... %d\n", dev
->startBlock
);
2009 buf
+= sprintf(buf
, "endBlock........... %d\n", dev
->endBlock
);
2010 buf
+= sprintf(buf
, "totalBytesPerChunk. %d\n", dev
->totalBytesPerChunk
);
2011 buf
+= sprintf(buf
, "nDataBytesPerChunk. %d\n", dev
->nDataBytesPerChunk
);
2012 buf
+= sprintf(buf
, "chunkGroupBits..... %d\n", dev
->chunkGroupBits
);
2013 buf
+= sprintf(buf
, "chunkGroupSize..... %d\n", dev
->chunkGroupSize
);
2014 buf
+= sprintf(buf
, "nErasedBlocks...... %d\n", dev
->nErasedBlocks
);
2015 buf
+= sprintf(buf
, "nReservedBlocks.... %d\n", dev
->nReservedBlocks
);
2016 buf
+= sprintf(buf
, "blocksInCheckpoint. %d\n", dev
->blocksInCheckpoint
);
2017 buf
+= sprintf(buf
, "nTnodesCreated..... %d\n", dev
->nTnodesCreated
);
2018 buf
+= sprintf(buf
, "nFreeTnodes........ %d\n", dev
->nFreeTnodes
);
2019 buf
+= sprintf(buf
, "nObjectsCreated.... %d\n", dev
->nObjectsCreated
);
2020 buf
+= sprintf(buf
, "nFreeObjects....... %d\n", dev
->nFreeObjects
);
2021 buf
+= sprintf(buf
, "nFreeChunks........ %d\n", dev
->nFreeChunks
);
2022 buf
+= sprintf(buf
, "nPageWrites........ %d\n", dev
->nPageWrites
);
2023 buf
+= sprintf(buf
, "nPageReads......... %d\n", dev
->nPageReads
);
2024 buf
+= sprintf(buf
, "nBlockErasures..... %d\n", dev
->nBlockErasures
);
2025 buf
+= sprintf(buf
, "nGCCopies.......... %d\n", dev
->nGCCopies
);
2026 buf
+= sprintf(buf
, "garbageCollections. %d\n", dev
->garbageCollections
);
2027 buf
+= sprintf(buf
, "passiveGCs......... %d\n",
2028 dev
->passiveGarbageCollections
);
2029 buf
+= sprintf(buf
, "nRetriedWrites..... %d\n", dev
->nRetriedWrites
);
2030 buf
+= sprintf(buf
, "nShortOpCaches..... %d\n", dev
->nShortOpCaches
);
2031 buf
+= sprintf(buf
, "nRetireBlocks...... %d\n", dev
->nRetiredBlocks
);
2032 buf
+= sprintf(buf
, "eccFixed........... %d\n", dev
->eccFixed
);
2033 buf
+= sprintf(buf
, "eccUnfixed......... %d\n", dev
->eccUnfixed
);
2034 buf
+= sprintf(buf
, "tagsEccFixed....... %d\n", dev
->tagsEccFixed
);
2035 buf
+= sprintf(buf
, "tagsEccUnfixed..... %d\n", dev
->tagsEccUnfixed
);
2036 buf
+= sprintf(buf
, "cacheHits.......... %d\n", dev
->cacheHits
);
2037 buf
+= sprintf(buf
, "nDeletedFiles...... %d\n", dev
->nDeletedFiles
);
2038 buf
+= sprintf(buf
, "nUnlinkedFiles..... %d\n", dev
->nUnlinkedFiles
);
2040 sprintf(buf
, "nBackgroudDeletions %d\n", dev
->nBackgroundDeletions
);
2041 buf
+= sprintf(buf
, "useNANDECC......... %d\n", dev
->useNANDECC
);
2042 buf
+= sprintf(buf
, "isYaffs2........... %d\n", dev
->isYaffs2
);
2043 buf
+= sprintf(buf
, "inbandTags......... %d\n", dev
->inbandTags
);
2048 static int yaffs_proc_read(char *page
,
2050 off_t offset
, int count
, int *eof
, void *data
)
2052 struct list_head
*item
;
2057 /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2058 * We use 'offset' (*ppos) to indicate where we are in devList.
2059 * This also assumes the user has posted a read buffer large
2060 * enough to hold the complete output; but that's life in /proc.
2065 /* Print header first */
2067 buf
+= sprintf(buf
, "YAFFS built:" __DATE__
" " __TIME__
2068 "\n%s\n%s\n", yaffs_fs_c_version
,
2069 yaffs_guts_c_version
);
2072 /* hold lock_kernel while traversing yaffs_dev_list */
2075 /* Locate and print the Nth entry. Order N-squared but N is small. */
2076 list_for_each(item
, &yaffs_dev_list
) {
2077 yaffs_Device
*dev
= list_entry(item
, yaffs_Device
, devList
);
2082 buf
+= sprintf(buf
, "\nDevice %d \"%s\"\n", n
, dev
->name
);
2083 buf
= yaffs_dump_dev(buf
, dev
);
2088 return buf
- page
< count
? buf
- page
: count
;
2092 * Set the verbosity of the warnings and error messages.
2094 * Note that the names can only be a..z or _ with the current code.
2099 unsigned mask_bitfield
;
2101 {"allocate", YAFFS_TRACE_ALLOCATE
},
2102 {"always", YAFFS_TRACE_ALWAYS
},
2103 {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS
},
2104 {"buffers", YAFFS_TRACE_BUFFERS
},
2105 {"bug", YAFFS_TRACE_BUG
},
2106 {"checkpt", YAFFS_TRACE_CHECKPOINT
},
2107 {"deletion", YAFFS_TRACE_DELETION
},
2108 {"erase", YAFFS_TRACE_ERASE
},
2109 {"error", YAFFS_TRACE_ERROR
},
2110 {"gc_detail", YAFFS_TRACE_GC_DETAIL
},
2111 {"gc", YAFFS_TRACE_GC
},
2112 {"mtd", YAFFS_TRACE_MTD
},
2113 {"nandaccess", YAFFS_TRACE_NANDACCESS
},
2114 {"os", YAFFS_TRACE_OS
},
2115 {"scan_debug", YAFFS_TRACE_SCAN_DEBUG
},
2116 {"scan", YAFFS_TRACE_SCAN
},
2117 {"tracing", YAFFS_TRACE_TRACING
},
2119 {"verify", YAFFS_TRACE_VERIFY
},
2120 {"verify_nand", YAFFS_TRACE_VERIFY_NAND
},
2121 {"verify_full", YAFFS_TRACE_VERIFY_FULL
},
2122 {"verify_all", YAFFS_TRACE_VERIFY_ALL
},
2124 {"write", YAFFS_TRACE_WRITE
},
2125 {"all", 0xffffffff},
2130 #define MAX_MASK_NAME_LENGTH 40
2131 static int yaffs_proc_write(struct file
*file
, const char *buf
,
2132 unsigned long count
, void *data
)
2134 unsigned rg
= 0, mask_bitfield
;
2138 char substring
[MAX_MASK_NAME_LENGTH
+1];
2144 rg
= yaffs_traceMask
;
2146 while (!done
&& (pos
< count
)) {
2148 while ((pos
< count
) && isspace(buf
[pos
])) {
2166 mask_bitfield
= simple_strtoul(buf
+ pos
, &end
, 0);
2167 if (end
> buf
+ pos
) {
2168 mask_name
= "numeral";
2169 len
= end
- (buf
+ pos
);
2173 for(x
= buf
+ pos
, i
= 0;
2174 (*x
== '_' || (*x
>='a' && *x
<= 'z')) &&
2175 i
<MAX_MASK_NAME_LENGTH
; x
++, i
++, pos
++)
2177 substring
[i
] = '\0';
2179 for (i
= 0; mask_flags
[i
].mask_name
!= NULL
; i
++) {
2180 if(strcmp(substring
,mask_flags
[i
].mask_name
) == 0){
2181 mask_name
= mask_flags
[i
].mask_name
;
2182 mask_bitfield
= mask_flags
[i
].mask_bitfield
;
2189 if (mask_name
!= NULL
) {
2193 rg
&= ~mask_bitfield
;
2196 rg
|= mask_bitfield
;
2202 rg
|= mask_bitfield
;
2208 yaffs_traceMask
= rg
| YAFFS_TRACE_ALWAYS
;
2210 printk("new trace = 0x%08X\n",yaffs_traceMask
);
2212 if (rg
& YAFFS_TRACE_ALWAYS
) {
2213 for (i
= 0; mask_flags
[i
].mask_name
!= NULL
; i
++) {
2215 flag
= ((rg
& mask_flags
[i
].mask_bitfield
) == mask_flags
[i
].mask_bitfield
) ? '+' : '-';
2216 printk("%c%s\n", flag
, mask_flags
[i
].mask_name
);
2223 /* Stuff to handle installation of file systems */
2224 struct file_system_to_install
{
2225 struct file_system_type
*fst
;
2229 static struct file_system_to_install fs_to_install
[] = {
2230 //#ifdef CONFIG_YAFFS_YAFFS1
2231 {&yaffs_fs_type
, 0},
2233 //#ifdef CONFIG_YAFFS_YAFFS2
2234 {&yaffs2_fs_type
, 0},
2239 static int __init
init_yaffs_fs(void)
2242 struct file_system_to_install
*fsinst
;
2244 T(YAFFS_TRACE_ALWAYS
,
2245 ("yaffs " __DATE__
" " __TIME__
" Installing. \n"));
2247 /* Install the proc_fs entry */
2248 my_proc_entry
= create_proc_entry("yaffs",
2252 if (my_proc_entry
) {
2253 my_proc_entry
->write_proc
= yaffs_proc_write
;
2254 my_proc_entry
->read_proc
= yaffs_proc_read
;
2255 my_proc_entry
->data
= NULL
;
2260 /* Now add the file system entries */
2262 fsinst
= fs_to_install
;
2264 while (fsinst
->fst
&& !error
) {
2265 error
= register_filesystem(fsinst
->fst
);
2267 fsinst
->installed
= 1;
2272 /* Any errors? uninstall */
2274 fsinst
= fs_to_install
;
2276 while (fsinst
->fst
) {
2277 if (fsinst
->installed
) {
2278 unregister_filesystem(fsinst
->fst
);
2279 fsinst
->installed
= 0;
2288 static void __exit
exit_yaffs_fs(void)
2291 struct file_system_to_install
*fsinst
;
2293 T(YAFFS_TRACE_ALWAYS
, ("yaffs " __DATE__
" " __TIME__
2296 remove_proc_entry("yaffs", &proc_root
);
2298 fsinst
= fs_to_install
;
2300 while (fsinst
->fst
) {
2301 if (fsinst
->installed
) {
2302 unregister_filesystem(fsinst
->fst
);
2303 fsinst
->installed
= 0;
2310 module_init(init_yaffs_fs
)
2311 module_exit(exit_yaffs_fs
)
2313 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2314 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2315 MODULE_LICENSE("GPL");