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 extern const char *yaffs_guts_c_version
;
37 #include <linux/version.h>
38 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
39 #include <linux/config.h>
41 #include <linux/kernel.h>
42 #include <linux/module.h>
43 #include <linux/slab.h>
44 #include <linux/init.h>
45 #include <linux/list.h>
47 #include <linux/proc_fs.h>
48 #include <linux/smp_lock.h>
49 #include <linux/pagemap.h>
50 #include <linux/mtd/mtd.h>
51 #include <linux/interrupt.h>
52 #include <linux/string.h>
53 #include <linux/ctype.h>
55 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
57 #include <linux/statfs.h> /* Added NCB 15-8-2003 */
58 #include <asm/statfs.h>
59 #define UnlockPage(p) unlock_page(p)
60 #define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
62 /* FIXME: use sb->s_id instead ? */
63 #define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
67 #include <linux/locks.h>
68 #define BDEVNAME_SIZE 0
69 #define yaffs_devname(sb, buf) kdevname(sb->s_dev)
71 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
72 /* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
78 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
79 #define WRITE_SIZE_STR "writesize"
80 #define WRITE_SIZE(mtd) (mtd)->writesize
82 #define WRITE_SIZE_STR "oobblock"
83 #define WRITE_SIZE(mtd) (mtd)->oobblock
86 #include <asm/uaccess.h>
89 #include "yaffs_guts.h"
91 #include <linux/mtd/mtd.h>
92 #include "yaffs_mtdif.h"
93 #include "yaffs_mtdif1.h"
94 #include "yaffs_mtdif2.h"
96 unsigned int yaffs_traceMask
= YAFFS_TRACE_BAD_BLOCKS
;
97 unsigned int yaffs_wr_attempts
= YAFFS_WR_ATTEMPTS
;
99 /* Module Parameters */
100 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
101 module_param(yaffs_traceMask
,uint
,0644);
102 module_param(yaffs_wr_attempts
,uint
,0644);
104 MODULE_PARM(yaffs_traceMask
,"i");
105 MODULE_PARM(yaffs_wr_attempts
,"i");
108 /*#define T(x) printk x */
110 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
111 #define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
113 #define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
116 #define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
117 #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
119 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
120 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
122 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
125 static void yaffs_put_super(struct super_block
*sb
);
127 static ssize_t
yaffs_file_write(struct file
*f
, const char *buf
, size_t n
,
130 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
131 static int yaffs_file_flush(struct file
*file
, fl_owner_t id
);
133 static int yaffs_file_flush(struct file
*file
);
136 static int yaffs_sync_object(struct file
*file
, struct dentry
*dentry
,
139 static int yaffs_readdir(struct file
*f
, void *dirent
, filldir_t filldir
);
141 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
142 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
143 struct nameidata
*n
);
144 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
,
145 struct nameidata
*n
);
147 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
);
148 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
);
150 static int yaffs_link(struct dentry
*old_dentry
, struct inode
*dir
,
151 struct dentry
*dentry
);
152 static int yaffs_unlink(struct inode
*dir
, struct dentry
*dentry
);
153 static int yaffs_symlink(struct inode
*dir
, struct dentry
*dentry
,
154 const char *symname
);
155 static int yaffs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
);
157 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
158 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
161 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
164 static int yaffs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
165 struct inode
*new_dir
, struct dentry
*new_dentry
);
166 static int yaffs_setattr(struct dentry
*dentry
, struct iattr
*attr
);
168 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
169 static int yaffs_sync_fs(struct super_block
*sb
, int wait
);
170 static void yaffs_write_super(struct super_block
*sb
);
172 static int yaffs_sync_fs(struct super_block
*sb
);
173 static int yaffs_write_super(struct super_block
*sb
);
176 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
177 static int yaffs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
);
178 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
179 static int yaffs_statfs(struct super_block
*sb
, struct kstatfs
*buf
);
181 static int yaffs_statfs(struct super_block
*sb
, struct statfs
*buf
);
183 static void yaffs_read_inode(struct inode
*inode
);
185 static void yaffs_put_inode(struct inode
*inode
);
186 static void yaffs_delete_inode(struct inode
*);
187 static void yaffs_clear_inode(struct inode
*);
189 static int yaffs_readpage(struct file
*file
, struct page
*page
);
190 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
191 static int yaffs_writepage(struct page
*page
, struct writeback_control
*wbc
);
193 static int yaffs_writepage(struct page
*page
);
195 static int yaffs_prepare_write(struct file
*f
, struct page
*pg
,
196 unsigned offset
, unsigned to
);
197 static int yaffs_commit_write(struct file
*f
, struct page
*pg
, unsigned offset
,
200 static int yaffs_readlink(struct dentry
*dentry
, char __user
* buffer
,
202 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
203 static void *yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
);
205 static int yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
);
208 static struct address_space_operations yaffs_file_address_operations
= {
209 .readpage
= yaffs_readpage
,
210 .writepage
= yaffs_writepage
,
211 .prepare_write
= yaffs_prepare_write
,
212 .commit_write
= yaffs_commit_write
,
215 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
216 static struct file_operations yaffs_file_operations
= {
217 .read
= do_sync_read
,
218 .write
= do_sync_write
,
219 .aio_read
= generic_file_aio_read
,
220 .aio_write
= generic_file_aio_write
,
221 .mmap
= generic_file_mmap
,
222 .flush
= yaffs_file_flush
,
223 .fsync
= yaffs_sync_object
,
224 .splice_read
= generic_file_splice_read
,
225 .splice_write
= generic_file_splice_write
,
228 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
230 static struct file_operations yaffs_file_operations
= {
231 .read
= do_sync_read
,
232 .write
= do_sync_write
,
233 .aio_read
= generic_file_aio_read
,
234 .aio_write
= generic_file_aio_write
,
235 .mmap
= generic_file_mmap
,
236 .flush
= yaffs_file_flush
,
237 .fsync
= yaffs_sync_object
,
238 .sendfile
= generic_file_sendfile
,
243 static struct file_operations yaffs_file_operations
= {
244 .read
= generic_file_read
,
245 .write
= generic_file_write
,
246 .mmap
= generic_file_mmap
,
247 .flush
= yaffs_file_flush
,
248 .fsync
= yaffs_sync_object
,
249 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
250 .sendfile
= generic_file_sendfile
,
255 static struct inode_operations yaffs_file_inode_operations
= {
256 .setattr
= yaffs_setattr
,
259 static struct inode_operations yaffs_symlink_inode_operations
= {
260 .readlink
= yaffs_readlink
,
261 .follow_link
= yaffs_follow_link
,
262 .setattr
= yaffs_setattr
,
265 static struct inode_operations yaffs_dir_inode_operations
= {
266 .create
= yaffs_create
,
267 .lookup
= yaffs_lookup
,
269 .unlink
= yaffs_unlink
,
270 .symlink
= yaffs_symlink
,
271 .mkdir
= yaffs_mkdir
,
272 .rmdir
= yaffs_unlink
,
273 .mknod
= yaffs_mknod
,
274 .rename
= yaffs_rename
,
275 .setattr
= yaffs_setattr
,
278 static struct file_operations yaffs_dir_operations
= {
279 .read
= generic_read_dir
,
280 .readdir
= yaffs_readdir
,
281 .fsync
= yaffs_sync_object
,
284 static struct super_operations yaffs_super_ops
= {
285 .statfs
= yaffs_statfs
,
286 .read_inode
= yaffs_read_inode
,
287 .put_inode
= yaffs_put_inode
,
288 .put_super
= yaffs_put_super
,
289 .delete_inode
= yaffs_delete_inode
,
290 .clear_inode
= yaffs_clear_inode
,
291 .sync_fs
= yaffs_sync_fs
,
292 .write_super
= yaffs_write_super
,
295 static void yaffs_GrossLock(yaffs_Device
* dev
)
297 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs locking\n"));
299 down(&dev
->grossLock
);
302 static void yaffs_GrossUnlock(yaffs_Device
* dev
)
304 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs unlocking\n"));
309 static int yaffs_readlink(struct dentry
*dentry
, char __user
* buffer
,
312 unsigned char *alias
;
315 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
317 yaffs_GrossLock(dev
);
319 alias
= yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry
));
321 yaffs_GrossUnlock(dev
);
326 ret
= vfs_readlink(dentry
, buffer
, buflen
, alias
);
331 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
332 static void *yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
)
334 static int yaffs_follow_link(struct dentry
*dentry
, struct nameidata
*nd
)
337 unsigned char *alias
;
339 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
341 yaffs_GrossLock(dev
);
343 alias
= yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry
));
345 yaffs_GrossUnlock(dev
);
353 ret
= vfs_follow_link(nd
, alias
);
356 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
357 return ERR_PTR (ret
);
363 struct inode
*yaffs_get_inode(struct super_block
*sb
, int mode
, int dev
,
367 * Lookup is used to find objects in the fs
369 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
371 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
,
374 static struct dentry
*yaffs_lookup(struct inode
*dir
, struct dentry
*dentry
)
378 struct inode
*inode
= NULL
; /* NCB 2.5/2.6 needs NULL here */
380 yaffs_Device
*dev
= yaffs_InodeToObject(dir
)->myDev
;
382 yaffs_GrossLock(dev
);
385 (KERN_DEBUG
"yaffs_lookup for %d:%s\n",
386 yaffs_InodeToObject(dir
)->objectId
, dentry
->d_name
.name
));
389 yaffs_FindObjectByName(yaffs_InodeToObject(dir
),
390 dentry
->d_name
.name
);
392 obj
= yaffs_GetEquivalentObject(obj
); /* in case it was a hardlink */
394 /* Can't hold gross lock when calling yaffs_get_inode() */
395 yaffs_GrossUnlock(dev
);
399 (KERN_DEBUG
"yaffs_lookup found %d\n", obj
->objectId
));
401 inode
= yaffs_get_inode(dir
->i_sb
, obj
->yst_mode
, 0, obj
);
405 (KERN_DEBUG
"yaffs_loookup dentry \n"));
406 /* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
407 * d_add even if NULL inode */
409 /*dget(dentry); // try to solve directory bug */
410 d_add(dentry
, inode
);
418 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_lookup not found\n"));
422 /* added NCB for 2.5/6 compatability - forces add even if inode is
423 * NULL which creates dentry hash */
424 d_add(dentry
, inode
);
427 /* return (ERR_PTR(-EIO)); */
431 /* For now put inode is just for debugging
432 * Put inode is called when the inode **structure** is put.
434 static void yaffs_put_inode(struct inode
*inode
)
437 ("yaffs_put_inode: ino %d, count %d\n", (int)inode
->i_ino
,
438 atomic_read(&inode
->i_count
)));
442 /* clear is called to tell the fs to release any per-inode data it holds */
443 static void yaffs_clear_inode(struct inode
*inode
)
448 obj
= yaffs_InodeToObject(inode
);
451 ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode
->i_ino
,
452 atomic_read(&inode
->i_count
),
453 obj
? "object exists" : "null object"));
457 yaffs_GrossLock(dev
);
459 /* Clear the association between the inode and
463 yaffs_InodeToObjectLV(inode
) = NULL
;
465 /* If the object freeing was deferred, then the real
467 * This should fix the inode inconsistency problem.
470 yaffs_HandleDeferedFree(obj
);
472 yaffs_GrossUnlock(dev
);
477 /* delete is called when the link count is zero and the inode
478 * is put (ie. nobody wants to know about it anymore, time to
480 * NB Must call clear_inode()
482 static void yaffs_delete_inode(struct inode
*inode
)
484 yaffs_Object
*obj
= yaffs_InodeToObject(inode
);
488 ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode
->i_ino
,
489 atomic_read(&inode
->i_count
),
490 obj
? "object exists" : "null object"));
494 yaffs_GrossLock(dev
);
495 yaffs_DeleteFile(obj
);
496 yaffs_GrossUnlock(dev
);
498 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
499 truncate_inode_pages (&inode
->i_data
, 0);
504 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
505 static int yaffs_file_flush(struct file
*file
, fl_owner_t id
)
507 static int yaffs_file_flush(struct file
*file
)
510 yaffs_Object
*obj
= yaffs_DentryToObject(file
->f_dentry
);
512 yaffs_Device
*dev
= obj
->myDev
;
515 (KERN_DEBUG
"yaffs_file_flush object %d (%s)\n", obj
->objectId
,
516 obj
->dirty
? "dirty" : "clean"));
518 yaffs_GrossLock(dev
);
520 yaffs_FlushFile(obj
, 1);
522 yaffs_GrossUnlock(dev
);
527 static int yaffs_readpage_nolock(struct file
*f
, struct page
*pg
)
529 /* Lifted from jffs2 */
532 unsigned char *pg_buf
;
537 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_readpage at %08x, size %08x\n",
538 (unsigned)(pg
->index
<< PAGE_CACHE_SHIFT
),
539 (unsigned)PAGE_CACHE_SIZE
));
541 obj
= yaffs_DentryToObject(f
->f_dentry
);
545 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
546 BUG_ON(!PageLocked(pg
));
553 /* FIXME: Can kmap fail? */
555 yaffs_GrossLock(dev
);
558 yaffs_ReadDataFromFile(obj
, pg_buf
, pg
->index
<< PAGE_CACHE_SHIFT
,
561 yaffs_GrossUnlock(dev
);
567 ClearPageUptodate(pg
);
574 flush_dcache_page(pg
);
577 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_readpage done\n"));
581 static int yaffs_readpage_unlock(struct file
*f
, struct page
*pg
)
583 int ret
= yaffs_readpage_nolock(f
, pg
);
588 static int yaffs_readpage(struct file
*f
, struct page
*pg
)
590 return yaffs_readpage_unlock(f
, pg
);
593 /* writepage inspired by/stolen from smbfs */
595 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
596 static int yaffs_writepage(struct page
*page
, struct writeback_control
*wbc
)
598 static int yaffs_writepage(struct page
*page
)
601 struct address_space
*mapping
= page
->mapping
;
602 loff_t offset
= (loff_t
) page
->index
<< PAGE_CACHE_SHIFT
;
604 unsigned long end_index
;
612 inode
= mapping
->host
;
616 if (offset
> inode
->i_size
) {
619 "yaffs_writepage at %08x, inode size = %08x!!!\n",
620 (unsigned)(page
->index
<< PAGE_CACHE_SHIFT
),
621 (unsigned)inode
->i_size
));
623 (KERN_DEBUG
" -> don't care!!\n"));
628 end_index
= inode
->i_size
>> PAGE_CACHE_SHIFT
;
631 if (page
->index
< end_index
) {
632 nBytes
= PAGE_CACHE_SIZE
;
634 nBytes
= inode
->i_size
& (PAGE_CACHE_SIZE
- 1);
641 obj
= yaffs_InodeToObject(inode
);
642 yaffs_GrossLock(obj
->myDev
);
645 (KERN_DEBUG
"yaffs_writepage at %08x, size %08x\n",
646 (unsigned)(page
->index
<< PAGE_CACHE_SHIFT
), nBytes
));
648 (KERN_DEBUG
"writepag0: obj = %05x, ino = %05x\n",
649 (int)obj
->variant
.fileVariant
.fileSize
, (int)inode
->i_size
));
652 yaffs_WriteDataToFile(obj
, buffer
, page
->index
<< PAGE_CACHE_SHIFT
,
656 (KERN_DEBUG
"writepag1: obj = %05x, ino = %05x\n",
657 (int)obj
->variant
.fileVariant
.fileSize
, (int)inode
->i_size
));
659 yaffs_GrossUnlock(obj
->myDev
);
662 SetPageUptodate(page
);
666 return (nWritten
== nBytes
) ? 0 : -ENOSPC
;
669 static int yaffs_prepare_write(struct file
*f
, struct page
*pg
,
670 unsigned offset
, unsigned to
)
673 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_prepair_write\n"));
674 if (!Page_Uptodate(pg
) && (offset
|| to
< PAGE_CACHE_SIZE
))
675 return yaffs_readpage_nolock(f
, pg
);
681 static int yaffs_commit_write(struct file
*f
, struct page
*pg
, unsigned offset
,
685 void *addr
= page_address(pg
) + offset
;
686 loff_t pos
= (((loff_t
) pg
->index
) << PAGE_CACHE_SHIFT
) + offset
;
687 int nBytes
= to
- offset
;
691 unsigned saddr
= (unsigned)addr
;
694 (KERN_DEBUG
"yaffs_commit_write addr %x pos %x nBytes %d\n", saddr
,
697 nWritten
= yaffs_file_write(f
, addr
, nBytes
, &pos
);
699 if (nWritten
!= nBytes
) {
702 "yaffs_commit_write not same size nWritten %d nBytes %d\n",
705 ClearPageUptodate(pg
);
711 (KERN_DEBUG
"yaffs_commit_write returning %d\n",
712 nWritten
== nBytes
? 0 : nWritten
));
714 return nWritten
== nBytes
? 0 : nWritten
;
718 static void yaffs_FillInodeFromObject(struct inode
*inode
, yaffs_Object
* obj
)
723 /* Check mode against the variant type and attempt to repair if broken. */
724 __u32 mode
= obj
->yst_mode
;
725 switch( obj
->variantType
){
726 case YAFFS_OBJECT_TYPE_FILE
:
727 if( ! S_ISREG(mode
) ){
728 obj
->yst_mode
&= ~S_IFMT
;
729 obj
->yst_mode
|= S_IFREG
;
733 case YAFFS_OBJECT_TYPE_SYMLINK
:
734 if( ! S_ISLNK(mode
) ){
735 obj
->yst_mode
&= ~S_IFMT
;
736 obj
->yst_mode
|= S_IFLNK
;
740 case YAFFS_OBJECT_TYPE_DIRECTORY
:
741 if( ! S_ISDIR(mode
) ){
742 obj
->yst_mode
&= ~S_IFMT
;
743 obj
->yst_mode
|= S_IFDIR
;
747 case YAFFS_OBJECT_TYPE_UNKNOWN
:
748 case YAFFS_OBJECT_TYPE_HARDLINK
:
749 case YAFFS_OBJECT_TYPE_SPECIAL
:
755 inode
->i_ino
= obj
->objectId
;
756 inode
->i_mode
= obj
->yst_mode
;
757 inode
->i_uid
= obj
->yst_uid
;
758 inode
->i_gid
= obj
->yst_gid
;
759 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
760 inode
->i_blksize
= inode
->i_sb
->s_blocksize
;
762 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
764 inode
->i_rdev
= old_decode_dev(obj
->yst_rdev
);
765 inode
->i_atime
.tv_sec
= (time_t) (obj
->yst_atime
);
766 inode
->i_atime
.tv_nsec
= 0;
767 inode
->i_mtime
.tv_sec
= (time_t) obj
->yst_mtime
;
768 inode
->i_mtime
.tv_nsec
= 0;
769 inode
->i_ctime
.tv_sec
= (time_t) obj
->yst_ctime
;
770 inode
->i_ctime
.tv_nsec
= 0;
772 inode
->i_rdev
= obj
->yst_rdev
;
773 inode
->i_atime
= obj
->yst_atime
;
774 inode
->i_mtime
= obj
->yst_mtime
;
775 inode
->i_ctime
= obj
->yst_ctime
;
777 inode
->i_size
= yaffs_GetObjectFileLength(obj
);
778 inode
->i_blocks
= (inode
->i_size
+ 511) >> 9;
780 inode
->i_nlink
= yaffs_GetObjectLinkCount(obj
);
784 "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
785 inode
->i_mode
, inode
->i_uid
, inode
->i_gid
,
786 (int)inode
->i_size
, atomic_read(&inode
->i_count
)));
788 switch (obj
->yst_mode
& S_IFMT
) {
789 default: /* fifo, device or socket */
790 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
791 init_special_inode(inode
, obj
->yst_mode
,
792 old_decode_dev(obj
->yst_rdev
));
794 init_special_inode(inode
, obj
->yst_mode
,
795 (dev_t
) (obj
->yst_rdev
));
798 case S_IFREG
: /* file */
799 inode
->i_op
= &yaffs_file_inode_operations
;
800 inode
->i_fop
= &yaffs_file_operations
;
801 inode
->i_mapping
->a_ops
=
802 &yaffs_file_address_operations
;
804 case S_IFDIR
: /* directory */
805 inode
->i_op
= &yaffs_dir_inode_operations
;
806 inode
->i_fop
= &yaffs_dir_operations
;
808 case S_IFLNK
: /* symlink */
809 inode
->i_op
= &yaffs_symlink_inode_operations
;
813 yaffs_InodeToObjectLV(inode
) = obj
;
815 obj
->myInode
= inode
;
819 (KERN_DEBUG
"yaffs_FileInode invalid parameters\n"));
824 struct inode
*yaffs_get_inode(struct super_block
*sb
, int mode
, int dev
,
831 (KERN_DEBUG
"yaffs_get_inode for NULL super_block!!\n"));
838 (KERN_DEBUG
"yaffs_get_inode for NULL object!!\n"));
844 (KERN_DEBUG
"yaffs_get_inode for object %d\n", obj
->objectId
));
846 inode
= iget(sb
, obj
->objectId
);
848 /* NB Side effect: iget calls back to yaffs_read_inode(). */
849 /* iget also increments the inode's i_count */
850 /* NB You can't be holding grossLock or deadlock will happen! */
855 static ssize_t
yaffs_file_write(struct file
*f
, const char *buf
, size_t n
,
863 obj
= yaffs_DentryToObject(f
->f_dentry
);
867 yaffs_GrossLock(dev
);
869 inode
= f
->f_dentry
->d_inode
;
871 if (!S_ISBLK(inode
->i_mode
) && f
->f_flags
& O_APPEND
) {
872 ipos
= inode
->i_size
;
879 (KERN_DEBUG
"yaffs_file_write: hey obj is null!\n"));
883 "yaffs_file_write about to write writing %d bytes"
884 "to object %d at %d\n",
885 n
, obj
->objectId
, ipos
));
888 nWritten
= yaffs_WriteDataToFile(obj
, buf
, ipos
, n
, 0);
891 (KERN_DEBUG
"yaffs_file_write writing %d bytes, %d written at %d\n",
896 if (ipos
> inode
->i_size
) {
897 inode
->i_size
= ipos
;
898 inode
->i_blocks
= (ipos
+ 511) >> 9;
902 "yaffs_file_write size updated to %d bytes, "
904 ipos
, (int)(inode
->i_blocks
)));
908 yaffs_GrossUnlock(dev
);
909 return nWritten
== 0 ? -ENOSPC
: nWritten
;
912 static int yaffs_readdir(struct file
*f
, void *dirent
, filldir_t filldir
)
916 struct inode
*inode
= f
->f_dentry
->d_inode
;
917 unsigned long offset
, curoffs
;
921 char name
[YAFFS_MAX_NAME_LENGTH
+ 1];
923 obj
= yaffs_DentryToObject(f
->f_dentry
);
926 yaffs_GrossLock(dev
);
930 T(YAFFS_TRACE_OS
, ("yaffs_readdir: starting at %d\n", (int)offset
));
934 (KERN_DEBUG
"yaffs_readdir: entry . ino %d \n",
936 if (filldir(dirent
, ".", 1, offset
, inode
->i_ino
, DT_DIR
)
945 (KERN_DEBUG
"yaffs_readdir: entry .. ino %d \n",
946 (int)f
->f_dentry
->d_parent
->d_inode
->i_ino
));
948 (dirent
, "..", 2, offset
,
949 f
->f_dentry
->d_parent
->d_inode
->i_ino
, DT_DIR
) < 0) {
958 /* If the directory has changed since the open or last call to
959 readdir, rewind to after the 2 canned entries. */
961 if (f
->f_version
!= inode
->i_version
) {
964 f
->f_version
= inode
->i_version
;
967 list_for_each(i
, &obj
->variant
.directoryVariant
.children
) {
969 if (curoffs
>= offset
) {
970 l
= list_entry(i
, yaffs_Object
, siblings
);
972 yaffs_GetObjectName(l
, name
,
973 YAFFS_MAX_NAME_LENGTH
+ 1);
975 (KERN_DEBUG
"yaffs_readdir: %s inode %d\n", name
,
976 yaffs_GetObjectInode(l
)));
982 yaffs_GetObjectInode(l
),
983 yaffs_GetObjectType(l
))
996 yaffs_GrossUnlock(dev
);
1002 * File creation. Allocate an inode, and we're done..
1004 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1005 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1008 static int yaffs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1012 struct inode
*inode
;
1014 yaffs_Object
*obj
= NULL
;
1017 yaffs_Object
*parent
= yaffs_InodeToObject(dir
);
1019 int error
= -ENOSPC
;
1020 uid_t uid
= current
->fsuid
;
1021 gid_t gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
1023 if((dir
->i_mode
& S_ISGID
) && S_ISDIR(mode
))
1028 (KERN_DEBUG
"yaffs_mknod: parent object %d type %d\n",
1029 parent
->objectId
, parent
->variantType
));
1032 (KERN_DEBUG
"yaffs_mknod: could not get parent object\n"));
1036 T(YAFFS_TRACE_OS
, ("yaffs_mknod: making oject for %s, "
1038 dentry
->d_name
.name
, mode
, rdev
));
1040 dev
= parent
->myDev
;
1042 yaffs_GrossLock(dev
);
1044 switch (mode
& S_IFMT
) {
1046 /* Special (socket, fifo, device...) */
1047 T(YAFFS_TRACE_OS
, (KERN_DEBUG
1048 "yaffs_mknod: making special\n"));
1049 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1051 yaffs_MknodSpecial(parent
, dentry
->d_name
.name
, mode
, uid
,
1052 gid
, old_encode_dev(rdev
));
1055 yaffs_MknodSpecial(parent
, dentry
->d_name
.name
, mode
, uid
,
1059 case S_IFREG
: /* file */
1060 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mknod: making file\n"));
1062 yaffs_MknodFile(parent
, dentry
->d_name
.name
, mode
, uid
,
1065 case S_IFDIR
: /* directory */
1067 (KERN_DEBUG
"yaffs_mknod: making directory\n"));
1069 yaffs_MknodDirectory(parent
, dentry
->d_name
.name
, mode
,
1072 case S_IFLNK
: /* symlink */
1073 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mknod: making file\n"));
1074 obj
= NULL
; /* Do we ever get here? */
1078 /* Can not call yaffs_get_inode() with gross lock held */
1079 yaffs_GrossUnlock(dev
);
1082 inode
= yaffs_get_inode(dir
->i_sb
, mode
, rdev
, obj
);
1083 d_instantiate(dentry
, inode
);
1085 (KERN_DEBUG
"yaffs_mknod created object %d count = %d\n",
1086 obj
->objectId
, atomic_read(&inode
->i_count
)));
1090 (KERN_DEBUG
"yaffs_mknod failed making object\n"));
1097 static int yaffs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
)
1100 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_mkdir\n"));
1101 retVal
= yaffs_mknod(dir
, dentry
, mode
| S_IFDIR
, 0);
1103 /* attempt to fix dir bug - didn't work */
1111 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1112 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
1113 struct nameidata
*n
)
1115 static int yaffs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
)
1118 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_create\n"));
1119 return yaffs_mknod(dir
, dentry
, mode
| S_IFREG
, 0);
1122 static int yaffs_unlink(struct inode
*dir
, struct dentry
*dentry
)
1129 (KERN_DEBUG
"yaffs_unlink %d:%s\n", (int)(dir
->i_ino
),
1130 dentry
->d_name
.name
));
1132 dev
= yaffs_InodeToObject(dir
)->myDev
;
1134 yaffs_GrossLock(dev
);
1136 retVal
= yaffs_Unlink(yaffs_InodeToObject(dir
), dentry
->d_name
.name
);
1138 if (retVal
== YAFFS_OK
) {
1139 dentry
->d_inode
->i_nlink
--;
1141 yaffs_GrossUnlock(dev
);
1142 mark_inode_dirty(dentry
->d_inode
);
1145 yaffs_GrossUnlock(dev
);
1152 static int yaffs_link(struct dentry
*old_dentry
, struct inode
*dir
,
1153 struct dentry
*dentry
)
1155 struct inode
*inode
= old_dentry
->d_inode
;
1156 yaffs_Object
*obj
= NULL
;
1157 yaffs_Object
*link
= NULL
;
1160 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_link\n"));
1162 obj
= yaffs_InodeToObject(inode
);
1165 yaffs_GrossLock(dev
);
1167 if (!S_ISDIR(inode
->i_mode
)) /* Don't link directories */
1170 yaffs_Link(yaffs_InodeToObject(dir
), dentry
->d_name
.name
,
1175 old_dentry
->d_inode
->i_nlink
= yaffs_GetObjectLinkCount(obj
);
1176 d_instantiate(dentry
, old_dentry
->d_inode
);
1177 atomic_inc(&old_dentry
->d_inode
->i_count
);
1179 (KERN_DEBUG
"yaffs_link link count %d i_count %d\n",
1180 old_dentry
->d_inode
->i_nlink
,
1181 atomic_read(&old_dentry
->d_inode
->i_count
)));
1185 yaffs_GrossUnlock(dev
);
1195 static int yaffs_symlink(struct inode
*dir
, struct dentry
*dentry
,
1196 const char *symname
)
1200 uid_t uid
= current
->fsuid
;
1201 gid_t gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
1203 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_symlink\n"));
1205 dev
= yaffs_InodeToObject(dir
)->myDev
;
1206 yaffs_GrossLock(dev
);
1207 obj
= yaffs_MknodSymLink(yaffs_InodeToObject(dir
), dentry
->d_name
.name
,
1208 S_IFLNK
| S_IRWXUGO
, uid
, gid
, symname
);
1209 yaffs_GrossUnlock(dev
);
1213 struct inode
*inode
;
1215 inode
= yaffs_get_inode(dir
->i_sb
, obj
->yst_mode
, 0, obj
);
1216 d_instantiate(dentry
, inode
);
1217 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"symlink created OK\n"));
1220 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"symlink not created\n"));
1227 static int yaffs_sync_object(struct file
*file
, struct dentry
*dentry
,
1234 obj
= yaffs_DentryToObject(dentry
);
1238 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_sync_object\n"));
1239 yaffs_GrossLock(dev
);
1240 yaffs_FlushFile(obj
, 1);
1241 yaffs_GrossUnlock(dev
);
1246 * The VFS layer already does all the dentry stuff for rename.
1248 * NB: POSIX says you can rename an object over an old object of the same name
1250 static int yaffs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
1251 struct inode
*new_dir
, struct dentry
*new_dentry
)
1254 int retVal
= YAFFS_FAIL
;
1255 yaffs_Object
*target
;
1257 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_rename\n"));
1258 dev
= yaffs_InodeToObject(old_dir
)->myDev
;
1260 yaffs_GrossLock(dev
);
1262 /* Check if the target is an existing directory that is not empty. */
1264 yaffs_FindObjectByName(yaffs_InodeToObject(new_dir
),
1265 new_dentry
->d_name
.name
);
1270 target
->variantType
== YAFFS_OBJECT_TYPE_DIRECTORY
&&
1271 !list_empty(&target
->variant
.directoryVariant
.children
)) {
1273 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"target is non-empty dir\n"));
1275 retVal
= YAFFS_FAIL
;
1278 /* Now does unlinking internally using shadowing mechanism */
1279 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"calling yaffs_RenameObject\n"));
1282 yaffs_RenameObject(yaffs_InodeToObject(old_dir
),
1283 old_dentry
->d_name
.name
,
1284 yaffs_InodeToObject(new_dir
),
1285 new_dentry
->d_name
.name
);
1288 yaffs_GrossUnlock(dev
);
1290 if (retVal
== YAFFS_OK
) {
1292 new_dentry
->d_inode
->i_nlink
--;
1293 mark_inode_dirty(new_dentry
->d_inode
);
1303 static int yaffs_setattr(struct dentry
*dentry
, struct iattr
*attr
)
1305 struct inode
*inode
= dentry
->d_inode
;
1310 (KERN_DEBUG
"yaffs_setattr of object %d\n",
1311 yaffs_InodeToObject(inode
)->objectId
));
1313 if ((error
= inode_change_ok(inode
, attr
)) == 0) {
1315 dev
= yaffs_InodeToObject(inode
)->myDev
;
1316 yaffs_GrossLock(dev
);
1317 if (yaffs_SetAttributes(yaffs_InodeToObject(inode
), attr
) ==
1323 yaffs_GrossUnlock(dev
);
1325 error
= inode_setattr(inode
, attr
);
1330 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1331 static int yaffs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
)
1333 yaffs_Device
*dev
= yaffs_DentryToObject(dentry
)->myDev
;
1334 struct super_block
*sb
= dentry
->d_sb
;
1335 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1336 static int yaffs_statfs(struct super_block
*sb
, struct kstatfs
*buf
)
1338 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1340 static int yaffs_statfs(struct super_block
*sb
, struct statfs
*buf
)
1342 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1345 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_statfs\n"));
1347 yaffs_GrossLock(dev
);
1349 buf
->f_type
= YAFFS_MAGIC
;
1350 buf
->f_bsize
= sb
->s_blocksize
;
1351 buf
->f_namelen
= 255;
1352 if (sb
->s_blocksize
> dev
->nDataBytesPerChunk
) {
1355 (dev
->endBlock
- dev
->startBlock
+
1356 1) * dev
->nChunksPerBlock
/ (sb
->s_blocksize
/
1357 dev
->nDataBytesPerChunk
);
1359 yaffs_GetNumberOfFreeChunks(dev
) / (sb
->s_blocksize
/
1360 dev
->nDataBytesPerChunk
);
1364 (dev
->endBlock
- dev
->startBlock
+
1365 1) * dev
->nChunksPerBlock
* (dev
->nDataBytesPerChunk
/
1368 yaffs_GetNumberOfFreeChunks(dev
) * (dev
->nDataBytesPerChunk
/
1373 buf
->f_bavail
= buf
->f_bfree
;
1375 yaffs_GrossUnlock(dev
);
1381 static int yaffs_do_sync_fs(struct super_block *sb)
1384 yaffs_Device *dev = yaffs_SuperToDevice(sb);
1385 T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
1388 yaffs_GrossLock(dev);
1391 yaffs_CheckpointSave(dev);
1393 yaffs_GrossUnlock(dev);
1401 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1402 static void yaffs_write_super(struct super_block
*sb
)
1404 static int yaffs_write_super(struct super_block
*sb
)
1408 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_write_super\n"));
1409 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
1410 return 0; /* yaffs_do_sync_fs(sb);*/
1415 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1416 static int yaffs_sync_fs(struct super_block
*sb
, int wait
)
1418 static int yaffs_sync_fs(struct super_block
*sb
)
1422 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_sync_fs\n"));
1424 return 0; /* yaffs_do_sync_fs(sb);*/
1429 static void yaffs_read_inode(struct inode
*inode
)
1431 /* NB This is called as a side effect of other functions, but
1432 * we had to release the lock to prevent deadlocks, so
1433 * need to lock again.
1437 yaffs_Device
*dev
= yaffs_SuperToDevice(inode
->i_sb
);
1440 (KERN_DEBUG
"yaffs_read_inode for %d\n", (int)inode
->i_ino
));
1442 yaffs_GrossLock(dev
);
1444 obj
= yaffs_FindObjectByNumber(dev
, inode
->i_ino
);
1446 yaffs_FillInodeFromObject(inode
, obj
);
1448 yaffs_GrossUnlock(dev
);
1451 static LIST_HEAD(yaffs_dev_list
);
1454 static int yaffs_remount_fs(struct super_block
*sb
, int *flags
, char *data
)
1456 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1458 if( *flags
& MS_RDONLY
) {
1459 struct mtd_info
*mtd
= yaffs_SuperToDevice(sb
)->genericDevice
;
1462 (KERN_DEBUG
"yaffs_remount_fs: %s: RO\n", dev
->name
));
1464 yaffs_GrossLock(dev
);
1466 yaffs_FlushEntireDeviceCache(dev
);
1468 yaffs_CheckpointSave(dev
);
1473 yaffs_GrossUnlock(dev
);
1477 (KERN_DEBUG
"yaffs_remount_fs: %s: RW\n", dev
->name
));
1484 static void yaffs_put_super(struct super_block
*sb
)
1486 yaffs_Device
*dev
= yaffs_SuperToDevice(sb
);
1488 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_put_super\n"));
1490 yaffs_GrossLock(dev
);
1492 yaffs_FlushEntireDeviceCache(dev
);
1494 yaffs_CheckpointSave(dev
);
1496 if (dev
->putSuperFunc
) {
1497 dev
->putSuperFunc(sb
);
1500 yaffs_Deinitialise(dev
);
1502 yaffs_GrossUnlock(dev
);
1504 /* we assume this is protected by lock_kernel() in mount/umount */
1505 list_del(&dev
->devList
);
1507 if(dev
->spareBuffer
){
1508 YFREE(dev
->spareBuffer
);
1509 dev
->spareBuffer
= NULL
;
1516 static void yaffs_MTDPutSuper(struct super_block
*sb
)
1519 struct mtd_info
*mtd
= yaffs_SuperToDevice(sb
)->genericDevice
;
1525 put_mtd_device(mtd
);
1529 static void yaffs_MarkSuperBlockDirty(void *vsb
)
1531 struct super_block
*sb
= (struct super_block
*)vsb
;
1533 T(YAFFS_TRACE_OS
, (KERN_DEBUG
"yaffs_MarkSuperBlockDirty() sb = %p\n",sb
));
1540 int skip_checkpoint_read
;
1541 int skip_checkpoint_write
;
1545 #define MAX_OPT_LEN 20
1546 static int yaffs_parse_options(yaffs_options
*options
, const char *options_str
)
1548 char cur_opt
[MAX_OPT_LEN
+1];
1552 /* Parse through the options which is a comma seperated list */
1554 while(options_str
&& *options_str
&& !error
){
1555 memset(cur_opt
,0,MAX_OPT_LEN
+1);
1558 while(*options_str
&& *options_str
!= ','){
1559 if(p
< MAX_OPT_LEN
){
1560 cur_opt
[p
] = *options_str
;
1566 if(!strcmp(cur_opt
,"inband-tags"))
1567 options
->inband_tags
= 1;
1568 else if(!strcmp(cur_opt
,"no-cache"))
1569 options
->no_cache
= 1;
1570 else if(!strcmp(cur_opt
,"no-checkpoint-read"))
1571 options
->skip_checkpoint_read
= 1;
1572 else if(!strcmp(cur_opt
,"no-checkpoint-write"))
1573 options
->skip_checkpoint_write
= 1;
1574 else if(!strcmp(cur_opt
,"no-checkpoint")){
1575 options
->skip_checkpoint_read
= 1;
1576 options
->skip_checkpoint_write
= 1;
1578 printk(KERN_INFO
"yaffs: Bad mount option \"%s\"\n",cur_opt
);
1587 static struct super_block
*yaffs_internal_read_super(int yaffsVersion
,
1588 struct super_block
*sb
,
1589 void *data
, int silent
)
1592 struct inode
*inode
= NULL
;
1593 struct dentry
*root
;
1594 yaffs_Device
*dev
= 0;
1595 char devname_buf
[BDEVNAME_SIZE
+ 1];
1596 struct mtd_info
*mtd
;
1598 char *data_str
= (char *)data
;
1600 yaffs_options options
;
1602 sb
->s_magic
= YAFFS_MAGIC
;
1603 sb
->s_op
= &yaffs_super_ops
;
1606 printk(KERN_INFO
"yaffs: sb is NULL\n");
1607 else if (!sb
->s_dev
)
1608 printk(KERN_INFO
"yaffs: sb->s_dev is NULL\n");
1609 else if (!yaffs_devname(sb
, devname_buf
))
1610 printk(KERN_INFO
"yaffs: devname is NULL\n");
1612 printk(KERN_INFO
"yaffs: dev is %d name is \"%s\"\n",
1614 yaffs_devname(sb
, devname_buf
));
1619 printk(KERN_INFO
"yaffs: passed flags \"%s\"\n",data_str
);
1621 memset(&options
,0,sizeof(options
));
1623 if(yaffs_parse_options(&options
,data_str
)){
1624 /* Option parsing failed */
1629 sb
->s_blocksize
= PAGE_CACHE_SIZE
;
1630 sb
->s_blocksize_bits
= PAGE_CACHE_SHIFT
;
1631 T(YAFFS_TRACE_OS
, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion
));
1633 ("yaffs_read_super: block size %d\n", (int)(sb
->s_blocksize
)));
1635 #ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1637 ("yaffs: Write verification disabled. All guarantees "
1638 "null and void\n"));
1641 T(YAFFS_TRACE_ALWAYS
, ("yaffs: Attempting MTD mount on %u.%u, "
1643 MAJOR(sb
->s_dev
), MINOR(sb
->s_dev
),
1644 yaffs_devname(sb
, devname_buf
)));
1646 /* Check it's an mtd device..... */
1647 if (MAJOR(sb
->s_dev
) != MTD_BLOCK_MAJOR
) {
1648 return NULL
; /* This isn't an mtd device */
1650 /* Get the device */
1651 mtd
= get_mtd_device(NULL
, MINOR(sb
->s_dev
));
1653 T(YAFFS_TRACE_ALWAYS
,
1654 ("yaffs: MTD device #%u doesn't appear to exist\n",
1658 /* Check it's NAND */
1659 if (mtd
->type
!= MTD_NANDFLASH
) {
1660 T(YAFFS_TRACE_ALWAYS
,
1661 ("yaffs: MTD device is not NAND it's type %d\n", mtd
->type
));
1665 T(YAFFS_TRACE_OS
, (" erase %p\n", mtd
->erase
));
1666 T(YAFFS_TRACE_OS
, (" read %p\n", mtd
->read
));
1667 T(YAFFS_TRACE_OS
, (" write %p\n", mtd
->write
));
1668 T(YAFFS_TRACE_OS
, (" readoob %p\n", mtd
->read_oob
));
1669 T(YAFFS_TRACE_OS
, (" writeoob %p\n", mtd
->write_oob
));
1670 T(YAFFS_TRACE_OS
, (" block_isbad %p\n", mtd
->block_isbad
));
1671 T(YAFFS_TRACE_OS
, (" block_markbad %p\n", mtd
->block_markbad
));
1672 T(YAFFS_TRACE_OS
, (" %s %d\n", WRITE_SIZE_STR
, WRITE_SIZE(mtd
)));
1673 T(YAFFS_TRACE_OS
, (" oobsize %d\n", mtd
->oobsize
));
1674 T(YAFFS_TRACE_OS
, (" erasesize %d\n", mtd
->erasesize
));
1675 T(YAFFS_TRACE_OS
, (" size %d\n", mtd
->size
));
1677 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
1679 if (yaffsVersion
== 1 &&
1680 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1681 mtd
->writesize
>= 2048) {
1683 mtd
->oobblock
>= 2048) {
1685 T(YAFFS_TRACE_ALWAYS
,("yaffs: auto selecting yaffs2\n"));
1689 /* Added NCB 26/5/2006 for completeness */
1690 if (yaffsVersion
== 2 &&
1691 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1692 mtd
->writesize
== 512) {
1694 mtd
->oobblock
== 512) {
1696 T(YAFFS_TRACE_ALWAYS
,("yaffs: auto selecting yaffs1\n"));
1702 if (yaffsVersion
== 2) {
1703 /* Check for version 2 style functions */
1705 !mtd
->block_isbad
||
1706 !mtd
->block_markbad
||
1709 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1710 !mtd
->read_oob
|| !mtd
->write_oob
) {
1713 !mtd
->read_ecc
|| !mtd
->read_oob
|| !mtd
->write_oob
) {
1715 T(YAFFS_TRACE_ALWAYS
,
1716 ("yaffs: MTD device does not support required "
1721 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1722 if (mtd
->writesize
< YAFFS_MIN_YAFFS2_CHUNK_SIZE
||
1724 if (mtd
->oobblock
< YAFFS_MIN_YAFFS2_CHUNK_SIZE
||
1726 mtd
->oobsize
< YAFFS_MIN_YAFFS2_SPARE_SIZE
) {
1727 T(YAFFS_TRACE_ALWAYS
,
1728 ("yaffs: MTD device does not have the "
1729 "right page sizes\n"));
1733 /* Check for V1 style functions */
1737 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1738 !mtd
->read_oob
|| !mtd
->write_oob
) {
1741 !mtd
->read_ecc
|| !mtd
->read_oob
|| !mtd
->write_oob
) {
1743 T(YAFFS_TRACE_ALWAYS
,
1744 ("yaffs: MTD device does not support required "
1749 if (WRITE_SIZE(mtd
) < YAFFS_BYTES_PER_CHUNK
||
1750 mtd
->oobsize
!= YAFFS_BYTES_PER_SPARE
) {
1751 T(YAFFS_TRACE_ALWAYS
,
1752 ("yaffs: MTD device does not support have the "
1753 "right page sizes\n"));
1758 /* OK, so if we got here, we have an MTD that's NAND and looks
1759 * like it has the right capabilities
1760 * Set the yaffs_Device up for mtd
1763 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1764 sb
->s_fs_info
= dev
= kmalloc(sizeof(yaffs_Device
), GFP_KERNEL
);
1766 sb
->u
.generic_sbp
= dev
= kmalloc(sizeof(yaffs_Device
), GFP_KERNEL
);
1769 /* Deep shit could not allocate device structure */
1770 T(YAFFS_TRACE_ALWAYS
,
1771 ("yaffs_read_super: Failed trying to allocate "
1772 "yaffs_Device. \n"));
1776 memset(dev
, 0, sizeof(yaffs_Device
));
1777 dev
->genericDevice
= mtd
;
1778 dev
->name
= mtd
->name
;
1780 /* Set up the memory size parameters.... */
1782 nBlocks
= mtd
->size
/ (YAFFS_CHUNKS_PER_BLOCK
* YAFFS_BYTES_PER_CHUNK
);
1783 dev
->startBlock
= 0;
1784 dev
->endBlock
= nBlocks
- 1;
1785 dev
->nChunksPerBlock
= YAFFS_CHUNKS_PER_BLOCK
;
1786 dev
->nDataBytesPerChunk
= YAFFS_BYTES_PER_CHUNK
;
1787 dev
->nReservedBlocks
= 5;
1788 dev
->nShortOpCaches
= (options
.no_cache
) ? 0 : 10;
1790 /* ... and the functions. */
1791 if (yaffsVersion
== 2) {
1792 dev
->writeChunkWithTagsToNAND
=
1793 nandmtd2_WriteChunkWithTagsToNAND
;
1794 dev
->readChunkWithTagsFromNAND
=
1795 nandmtd2_ReadChunkWithTagsFromNAND
;
1796 dev
->markNANDBlockBad
= nandmtd2_MarkNANDBlockBad
;
1797 dev
->queryNANDBlock
= nandmtd2_QueryNANDBlock
;
1798 dev
->spareBuffer
= YMALLOC(mtd
->oobsize
);
1800 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1801 dev
->nDataBytesPerChunk
= mtd
->writesize
;
1802 dev
->nChunksPerBlock
= mtd
->erasesize
/ mtd
->writesize
;
1804 dev
->nDataBytesPerChunk
= mtd
->oobblock
;
1805 dev
->nChunksPerBlock
= mtd
->erasesize
/ mtd
->oobblock
;
1807 nBlocks
= mtd
->size
/ mtd
->erasesize
;
1809 dev
->nCheckpointReservedBlocks
= CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS
;
1810 dev
->startBlock
= 0;
1811 dev
->endBlock
= nBlocks
- 1;
1813 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1814 /* use the MTD interface in yaffs_mtdif1.c */
1815 dev
->writeChunkWithTagsToNAND
=
1816 nandmtd1_WriteChunkWithTagsToNAND
;
1817 dev
->readChunkWithTagsFromNAND
=
1818 nandmtd1_ReadChunkWithTagsFromNAND
;
1819 dev
->markNANDBlockBad
= nandmtd1_MarkNANDBlockBad
;
1820 dev
->queryNANDBlock
= nandmtd1_QueryNANDBlock
;
1822 dev
->writeChunkToNAND
= nandmtd_WriteChunkToNAND
;
1823 dev
->readChunkFromNAND
= nandmtd_ReadChunkFromNAND
;
1827 /* ... and common functions */
1828 dev
->eraseBlockInNAND
= nandmtd_EraseBlockInNAND
;
1829 dev
->initialiseNAND
= nandmtd_InitialiseNAND
;
1831 dev
->putSuperFunc
= yaffs_MTDPutSuper
;
1833 dev
->superBlock
= (void *)sb
;
1834 dev
->markSuperBlockDirty
= yaffs_MarkSuperBlockDirty
;
1837 #ifndef CONFIG_YAFFS_DOES_ECC
1838 dev
->useNANDECC
= 1;
1841 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
1842 dev
->wideTnodesDisabled
= 1;
1845 dev
->skipCheckpointRead
= options
.skip_checkpoint_read
;
1846 dev
->skipCheckpointWrite
= options
.skip_checkpoint_write
;
1848 /* we assume this is protected by lock_kernel() in mount/umount */
1849 list_add_tail(&dev
->devList
, &yaffs_dev_list
);
1851 init_MUTEX(&dev
->grossLock
);
1853 yaffs_GrossLock(dev
);
1855 err
= yaffs_GutsInitialise(dev
);
1858 ("yaffs_read_super: guts initialised %s\n",
1859 (err
== YAFFS_OK
) ? "OK" : "FAILED"));
1861 /* Release lock before yaffs_get_inode() */
1862 yaffs_GrossUnlock(dev
);
1864 /* Create root inode */
1865 if (err
== YAFFS_OK
)
1866 inode
= yaffs_get_inode(sb
, S_IFDIR
| 0755, 0,
1872 inode
->i_op
= &yaffs_dir_inode_operations
;
1873 inode
->i_fop
= &yaffs_dir_operations
;
1875 T(YAFFS_TRACE_OS
, ("yaffs_read_super: got root inode\n"));
1877 root
= d_alloc_root(inode
);
1879 T(YAFFS_TRACE_OS
, ("yaffs_read_super: d_alloc_root done\n"));
1887 T(YAFFS_TRACE_OS
, ("yaffs_read_super: done\n"));
1892 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1893 static int yaffs_internal_read_super_mtd(struct super_block
*sb
, void *data
,
1896 return yaffs_internal_read_super(1, sb
, data
, silent
) ? 0 : -EINVAL
;
1899 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1900 static int yaffs_read_super(struct file_system_type
*fs
,
1901 int flags
, const char *dev_name
,
1902 void *data
, struct vfsmount
*mnt
)
1905 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1906 yaffs_internal_read_super_mtd
, mnt
);
1909 static struct super_block
*yaffs_read_super(struct file_system_type
*fs
,
1910 int flags
, const char *dev_name
,
1914 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1915 yaffs_internal_read_super_mtd
);
1919 static struct file_system_type yaffs_fs_type
= {
1920 .owner
= THIS_MODULE
,
1922 .get_sb
= yaffs_read_super
,
1923 .kill_sb
= kill_block_super
,
1924 .fs_flags
= FS_REQUIRES_DEV
,
1927 static struct super_block
*yaffs_read_super(struct super_block
*sb
, void *data
,
1930 return yaffs_internal_read_super(1, sb
, data
, silent
);
1933 static DECLARE_FSTYPE(yaffs_fs_type
, "yaffs", yaffs_read_super
,
1938 #ifdef CONFIG_YAFFS_YAFFS2
1940 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1941 static int yaffs2_internal_read_super_mtd(struct super_block
*sb
, void *data
,
1944 return yaffs_internal_read_super(2, sb
, data
, silent
) ? 0 : -EINVAL
;
1947 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1948 static int yaffs2_read_super(struct file_system_type
*fs
,
1949 int flags
, const char *dev_name
, void *data
,
1950 struct vfsmount
*mnt
)
1952 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1953 yaffs2_internal_read_super_mtd
, mnt
);
1956 static struct super_block
*yaffs2_read_super(struct file_system_type
*fs
,
1957 int flags
, const char *dev_name
,
1961 return get_sb_bdev(fs
, flags
, dev_name
, data
,
1962 yaffs2_internal_read_super_mtd
);
1966 static struct file_system_type yaffs2_fs_type
= {
1967 .owner
= THIS_MODULE
,
1969 .get_sb
= yaffs2_read_super
,
1970 .kill_sb
= kill_block_super
,
1971 .fs_flags
= FS_REQUIRES_DEV
,
1974 static struct super_block
*yaffs2_read_super(struct super_block
*sb
,
1975 void *data
, int silent
)
1977 return yaffs_internal_read_super(2, sb
, data
, silent
);
1980 static DECLARE_FSTYPE(yaffs2_fs_type
, "yaffs2", yaffs2_read_super
,
1984 #endif /* CONFIG_YAFFS_YAFFS2 */
1986 static struct proc_dir_entry
*my_proc_entry
;
1988 static char *yaffs_dump_dev(char *buf
, yaffs_Device
* dev
)
1990 buf
+= sprintf(buf
, "startBlock......... %d\n", dev
->startBlock
);
1991 buf
+= sprintf(buf
, "endBlock........... %d\n", dev
->endBlock
);
1992 buf
+= sprintf(buf
, "nDataBytesPerChunk. %d\n", dev
->nDataBytesPerChunk
);
1993 buf
+= sprintf(buf
, "chunkGroupBits..... %d\n", dev
->chunkGroupBits
);
1994 buf
+= sprintf(buf
, "chunkGroupSize..... %d\n", dev
->chunkGroupSize
);
1995 buf
+= sprintf(buf
, "nErasedBlocks...... %d\n", dev
->nErasedBlocks
);
1996 buf
+= sprintf(buf
, "nReservedBlocks.... %d\n", dev
->nReservedBlocks
);
1997 buf
+= sprintf(buf
, "nCheckptResBlocks.. %d\n", dev
->nCheckpointReservedBlocks
);
1998 buf
+= sprintf(buf
, "blocksInCheckpoint. %d\n", dev
->blocksInCheckpoint
);
1999 buf
+= sprintf(buf
, "nTnodesCreated..... %d\n", dev
->nTnodesCreated
);
2000 buf
+= sprintf(buf
, "nFreeTnodes........ %d\n", dev
->nFreeTnodes
);
2001 buf
+= sprintf(buf
, "nObjectsCreated.... %d\n", dev
->nObjectsCreated
);
2002 buf
+= sprintf(buf
, "nFreeObjects....... %d\n", dev
->nFreeObjects
);
2003 buf
+= sprintf(buf
, "nFreeChunks........ %d\n", dev
->nFreeChunks
);
2004 buf
+= sprintf(buf
, "nPageWrites........ %d\n", dev
->nPageWrites
);
2005 buf
+= sprintf(buf
, "nPageReads......... %d\n", dev
->nPageReads
);
2006 buf
+= sprintf(buf
, "nBlockErasures..... %d\n", dev
->nBlockErasures
);
2007 buf
+= sprintf(buf
, "nGCCopies.......... %d\n", dev
->nGCCopies
);
2009 sprintf(buf
, "garbageCollections. %d\n", dev
->garbageCollections
);
2011 sprintf(buf
, "passiveGCs......... %d\n",
2012 dev
->passiveGarbageCollections
);
2013 buf
+= sprintf(buf
, "nRetriedWrites..... %d\n", dev
->nRetriedWrites
);
2014 buf
+= sprintf(buf
, "nShortOpCaches..... %d\n", dev
->nShortOpCaches
);
2015 buf
+= sprintf(buf
, "nRetireBlocks...... %d\n", dev
->nRetiredBlocks
);
2016 buf
+= sprintf(buf
, "eccFixed........... %d\n", dev
->eccFixed
);
2017 buf
+= sprintf(buf
, "eccUnfixed......... %d\n", dev
->eccUnfixed
);
2018 buf
+= sprintf(buf
, "tagsEccFixed....... %d\n", dev
->tagsEccFixed
);
2019 buf
+= sprintf(buf
, "tagsEccUnfixed..... %d\n", dev
->tagsEccUnfixed
);
2020 buf
+= sprintf(buf
, "cacheHits.......... %d\n", dev
->cacheHits
);
2021 buf
+= sprintf(buf
, "nDeletedFiles...... %d\n", dev
->nDeletedFiles
);
2022 buf
+= sprintf(buf
, "nUnlinkedFiles..... %d\n", dev
->nUnlinkedFiles
);
2024 sprintf(buf
, "nBackgroudDeletions %d\n", dev
->nBackgroundDeletions
);
2025 buf
+= sprintf(buf
, "useNANDECC......... %d\n", dev
->useNANDECC
);
2026 buf
+= sprintf(buf
, "isYaffs2........... %d\n", dev
->isYaffs2
);
2031 static int yaffs_proc_read(char *page
,
2033 off_t offset
, int count
, int *eof
, void *data
)
2035 struct list_head
*item
;
2040 /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2041 * We use 'offset' (*ppos) to indicate where we are in devList.
2042 * This also assumes the user has posted a read buffer large
2043 * enough to hold the complete output; but that's life in /proc.
2048 /* Print header first */
2050 buf
+= sprintf(buf
, "YAFFS built:" __DATE__
" " __TIME__
2051 "\n%s\n%s\n", yaffs_fs_c_version
,
2052 yaffs_guts_c_version
);
2055 /* hold lock_kernel while traversing yaffs_dev_list */
2058 /* Locate and print the Nth entry. Order N-squared but N is small. */
2059 list_for_each(item
, &yaffs_dev_list
) {
2060 yaffs_Device
*dev
= list_entry(item
, yaffs_Device
, devList
);
2065 buf
+= sprintf(buf
, "\nDevice %d \"%s\"\n", n
, dev
->name
);
2066 buf
= yaffs_dump_dev(buf
, dev
);
2071 return buf
- page
< count
? buf
- page
: count
;
2075 * Set the verbosity of the warnings and error messages.
2077 * Note that the names can only be a..z or _ with the current code.
2082 unsigned mask_bitfield
;
2084 {"allocate", YAFFS_TRACE_ALLOCATE
},
2085 {"always", YAFFS_TRACE_ALWAYS
},
2086 {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS
},
2087 {"buffers", YAFFS_TRACE_BUFFERS
},
2088 {"bug", YAFFS_TRACE_BUG
},
2089 {"checkpt", YAFFS_TRACE_CHECKPOINT
},
2090 {"deletion", YAFFS_TRACE_DELETION
},
2091 {"erase", YAFFS_TRACE_ERASE
},
2092 {"error", YAFFS_TRACE_ERROR
},
2093 {"gc_detail", YAFFS_TRACE_GC_DETAIL
},
2094 {"gc", YAFFS_TRACE_GC
},
2095 {"mtd", YAFFS_TRACE_MTD
},
2096 {"nandaccess", YAFFS_TRACE_NANDACCESS
},
2097 {"os", YAFFS_TRACE_OS
},
2098 {"scan_debug", YAFFS_TRACE_SCAN_DEBUG
},
2099 {"scan", YAFFS_TRACE_SCAN
},
2100 {"tracing", YAFFS_TRACE_TRACING
},
2102 {"verify", YAFFS_TRACE_VERIFY
},
2103 {"verify_nand", YAFFS_TRACE_VERIFY_NAND
},
2104 {"verify_full", YAFFS_TRACE_VERIFY_FULL
},
2105 {"verify_all", YAFFS_TRACE_VERIFY_ALL
},
2107 {"write", YAFFS_TRACE_WRITE
},
2108 {"all", 0xffffffff},
2113 #define MAX_MASK_NAME_LENGTH 40
2114 static int yaffs_proc_write(struct file
*file
, const char *buf
,
2115 unsigned long count
, void *data
)
2117 unsigned rg
= 0, mask_bitfield
;
2121 char substring
[MAX_MASK_NAME_LENGTH
+1];
2127 rg
= yaffs_traceMask
;
2129 while (!done
&& (pos
< count
)) {
2131 while ((pos
< count
) && isspace(buf
[pos
])) {
2149 mask_bitfield
= simple_strtoul(buf
+ pos
, &end
, 0);
2150 if (end
> buf
+ pos
) {
2151 mask_name
= "numeral";
2152 len
= end
- (buf
+ pos
);
2156 for(x
= buf
+ pos
, i
= 0;
2157 (*x
== '_' || (*x
>='a' && *x
<= 'z')) &&
2158 i
<MAX_MASK_NAME_LENGTH
; x
++, i
++, pos
++)
2160 substring
[i
] = '\0';
2162 for (i
= 0; mask_flags
[i
].mask_name
!= NULL
; i
++) {
2163 if(strcmp(substring
,mask_flags
[i
].mask_name
) == 0){
2164 mask_name
= mask_flags
[i
].mask_name
;
2165 mask_bitfield
= mask_flags
[i
].mask_bitfield
;
2172 if (mask_name
!= NULL
) {
2176 rg
&= ~mask_bitfield
;
2179 rg
|= mask_bitfield
;
2185 rg
|= mask_bitfield
;
2191 yaffs_traceMask
= rg
| YAFFS_TRACE_ALWAYS
;
2193 printk("new trace = 0x%08X\n",yaffs_traceMask
);
2195 if (rg
& YAFFS_TRACE_ALWAYS
) {
2196 for (i
= 0; mask_flags
[i
].mask_name
!= NULL
; i
++) {
2198 flag
= ((rg
& mask_flags
[i
].mask_bitfield
) == mask_flags
[i
].mask_bitfield
) ? '+' : '-';
2199 printk("%c%s\n", flag
, mask_flags
[i
].mask_name
);
2206 /* Stuff to handle installation of file systems */
2207 struct file_system_to_install
{
2208 struct file_system_type
*fst
;
2212 static struct file_system_to_install fs_to_install
[] = {
2213 //#ifdef CONFIG_YAFFS_YAFFS1
2214 {&yaffs_fs_type
, 0},
2216 //#ifdef CONFIG_YAFFS_YAFFS2
2217 {&yaffs2_fs_type
, 0},
2222 static int __init
init_yaffs_fs(void)
2225 struct file_system_to_install
*fsinst
;
2227 T(YAFFS_TRACE_ALWAYS
,
2228 ("yaffs " __DATE__
" " __TIME__
" Installing. \n"));
2230 /* Install the proc_fs entry */
2231 my_proc_entry
= create_proc_entry("yaffs",
2235 if (my_proc_entry
) {
2236 my_proc_entry
->write_proc
= yaffs_proc_write
;
2237 my_proc_entry
->read_proc
= yaffs_proc_read
;
2238 my_proc_entry
->data
= NULL
;
2243 /* Now add the file system entries */
2245 fsinst
= fs_to_install
;
2247 while (fsinst
->fst
&& !error
) {
2248 error
= register_filesystem(fsinst
->fst
);
2250 fsinst
->installed
= 1;
2255 /* Any errors? uninstall */
2257 fsinst
= fs_to_install
;
2259 while (fsinst
->fst
) {
2260 if (fsinst
->installed
) {
2261 unregister_filesystem(fsinst
->fst
);
2262 fsinst
->installed
= 0;
2271 static void __exit
exit_yaffs_fs(void)
2274 struct file_system_to_install
*fsinst
;
2276 T(YAFFS_TRACE_ALWAYS
, ("yaffs " __DATE__
" " __TIME__
2279 remove_proc_entry("yaffs", &proc_root
);
2281 fsinst
= fs_to_install
;
2283 while (fsinst
->fst
) {
2284 if (fsinst
->installed
) {
2285 unregister_filesystem(fsinst
->fst
);
2286 fsinst
->installed
= 0;
2293 module_init(init_yaffs_fs
)
2294 module_exit(exit_yaffs_fs
)
2296 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2297 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2298 MODULE_LICENSE("GPL");