X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=d90e2915f71655d6163ff8f4de0e13d3e022b8bb;hp=2a631623f82eb2563d47c57bac8047360e0cd52b;hb=20488750f4e5df4cec34f2bd4db39ab7e075d0a9;hpb=dd2ede7911c7afa2d28cee19f2727a8ba03fc011 diff --git a/yaffs_fs.c b/yaffs_fs.c index 2a63162..d90e291 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -31,7 +31,7 @@ */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.37 2005-12-14 01:18:45 charles Exp $"; + "$Id: yaffs_fs.c,v 1.51 2006-07-25 21:03:22 charles Exp $"; extern const char *yaffs_guts_c_version; #include @@ -48,6 +48,7 @@ extern const char *yaffs_guts_c_version; #include #include #include +#include #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -65,6 +66,11 @@ extern const char *yaffs_guts_c_version; #define BDEVNAME_SIZE 0 #define yaffs_devname(sb, buf) kdevname(sb->s_dev) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ +#define __user +#endif + #endif #include @@ -72,7 +78,10 @@ extern const char *yaffs_guts_c_version; #include "yportenv.h" #include "yaffs_guts.h" -unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | YAFFS_TRACE_BAD_BLOCKS /* | 0xFFFFFFFF */; +unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | + YAFFS_TRACE_BAD_BLOCKS | + YAFFS_TRACE_CHECKPOINT + /* | 0xFFFFFFFF */; #include #include "yaffs_mtdif.h" @@ -128,6 +137,9 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); +static int yaffs_sync_fs(struct super_block *sb); +static int yaffs_write_super(struct super_block *sb); + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); #else @@ -171,6 +183,10 @@ static struct file_operations yaffs_file_operations = { .mmap = generic_file_mmap, .flush = yaffs_file_flush, .fsync = yaffs_sync_object, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + .sendfile = generic_file_sendfile, +#endif + }; static struct inode_operations yaffs_file_inode_operations = { @@ -209,6 +225,8 @@ static struct super_operations yaffs_super_ops = { .put_super = yaffs_put_super, .delete_inode = yaffs_delete_inode, .clear_inode = yaffs_clear_inode, + .sync_fs = yaffs_sync_fs, + .write_super = yaffs_write_super, }; static void yaffs_GrossLock(yaffs_Device * dev) @@ -624,15 +642,49 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_commit_write returning %d\n", - nWritten == nBytes ? 0 : -1)); + nWritten == nBytes ? 0 : nWritten)); - return nWritten == nBytes ? 0 : -1; + return nWritten == nBytes ? 0 : nWritten; } static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) { if (inode && obj) { + + + /* Check mode against the variant type and attempt to repair if broken. */ + __u32 mode = obj->yst_mode; + switch( obj->variantType ){ + case YAFFS_OBJECT_TYPE_FILE : + if( ! S_ISREG(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFREG; + } + + break; + case YAFFS_OBJECT_TYPE_SYMLINK : + if( ! S_ISLNK(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFLNK; + } + + break; + case YAFFS_OBJECT_TYPE_DIRECTORY : + if( ! S_ISDIR(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFDIR; + } + + break; + case YAFFS_OBJECT_TYPE_UNKNOWN : + case YAFFS_OBJECT_TYPE_HARDLINK : + case YAFFS_OBJECT_TYPE_SPECIAL : + default: + /* TODO? */ + break; + } + inode->i_ino = obj->objectId; inode->i_mode = obj->yst_mode; inode->i_uid = obj->yst_uid; @@ -784,8 +836,7 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, } yaffs_GrossUnlock(dev); - - return nWritten != n ? -ENOSPC : nWritten; + return nWritten == 0 ? -ENOSPC : nWritten; } static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) @@ -834,6 +885,15 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) curoffs = 1; + /* If the directory has changed since the open or last call to + readdir, rewind to after the 2 canned entries. */ + + if (f->f_version != inode->i_version) { + offset = 2; + f->f_pos = offset; + f->f_version = inode->i_version; + } + list_for_each(i, &obj->variant.directoryVariant.children) { curoffs++; if (curoffs >= offset) { @@ -889,6 +949,9 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int error = -ENOSPC; uid_t uid = current->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; + + if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) + mode |= S_ISGID; if (parent) { T(YAFFS_TRACE_OS, @@ -1002,15 +1065,15 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); - yaffs_GrossUnlock(dev); - if (retVal == YAFFS_OK) { dentry->d_inode->i_nlink--; + dir->i_version++; + yaffs_GrossUnlock(dev); mark_inode_dirty(dentry->d_inode); return 0; - } else { - return -ENOTEMPTY; } + yaffs_GrossUnlock(dev); + return -ENOTEMPTY; } /* @@ -1236,6 +1299,47 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) return 0; } + + +static int yaffs_do_sync_fs(struct super_block *sb) +{ + + yaffs_Device *dev = yaffs_SuperToDevice(sb); + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n")); + + if(sb->s_dirt) { + yaffs_GrossLock(dev); + + if(dev) + yaffs_CheckpointSave(dev); + + yaffs_GrossUnlock(dev); + + sb->s_dirt = 0; + } + return 0; +} + + +static int yaffs_write_super(struct super_block *sb) +{ + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n")); + return 0; /* yaffs_do_sync_fs(sb);*/ + +} + + +static int yaffs_sync_fs(struct super_block *sb) +{ + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); + + return 0; /* yaffs_do_sync_fs(sb);*/ + +} + + static void yaffs_read_inode(struct inode *inode) { /* NB This is called as a side effect of other functions, but @@ -1264,15 +1368,28 @@ static void yaffs_put_super(struct super_block *sb) { yaffs_Device *dev = yaffs_SuperToDevice(sb); + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); + yaffs_GrossLock(dev); + + yaffs_FlushEntireDeviceCache(dev); + if (dev->putSuperFunc) { dev->putSuperFunc(sb); } + + yaffs_CheckpointSave(dev); yaffs_Deinitialise(dev); + yaffs_GrossUnlock(dev); /* we assume this is protected by lock_kernel() in mount/umount */ list_del(&dev->devList); + + if(dev->spareBuffer){ + YFREE(dev->spareBuffer); + dev->spareBuffer = NULL; + } kfree(dev); } @@ -1291,6 +1408,15 @@ static void yaffs_MTDPutSuper(struct super_block *sb) } +static void yaffs_MarkSuperBlockDirty(void *vsb) +{ + struct super_block *sb = (struct super_block *)vsb; + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); +// if(sb) +// sb->s_dirt = 1; +} + static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct super_block *sb, void *data, int silent) @@ -1365,13 +1491,21 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); T(YAFFS_TRACE_OS, (" size %d\n", mtd->size)); -#if CONFIG_YAFFS_AUTO_YAFFS2 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2 if (yaffsVersion == 1 && mtd->oobblock >= 2048) { T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); yaffsVersion = 2; } + + /* Added NCB 26/5/2006 for completeness */ + if (yaffsVersion == 2 && + mtd->oobblock == 512) { + T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); + yaffsVersion = 1; + } + #endif if (yaffsVersion == 2) { @@ -1392,7 +1526,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE || mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) { T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support have the " + ("yaffs: MTD device does not have the " "right page sizes\n")); return NULL; } @@ -1463,6 +1597,8 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->nBytesPerChunk = mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; nBlocks = mtd->size / mtd->erasesize; + + dev->nCheckpointReservedBlocks = 10; dev->startBlock = 0; dev->endBlock = nBlocks - 1; } else { @@ -1475,6 +1611,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->initialiseNAND = nandmtd_InitialiseNAND; dev->putSuperFunc = yaffs_MTDPutSuper; + + dev->superBlock = (void *)sb; + dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; + #ifndef CONFIG_YAFFS_DOES_ECC dev->useNANDECC = 1; @@ -1684,6 +1824,118 @@ static int yaffs_proc_read(char *page, return buf - page < count ? buf - page : count; } +/** + * Set the verbosity of the warnings and error messages. + * + */ + +static struct { + char *mask_name; + unsigned mask_bitfield; +} mask_flags[] = { + {"allocate", YAFFS_TRACE_ALLOCATE}, + {"always", YAFFS_TRACE_ALWAYS}, + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, + {"buffers", YAFFS_TRACE_BUFFERS}, + {"bug", YAFFS_TRACE_BUG}, + {"deletion", YAFFS_TRACE_DELETION}, + {"erase", YAFFS_TRACE_ERASE}, + {"error", YAFFS_TRACE_ERROR}, + {"gc_detail", YAFFS_TRACE_GC_DETAIL}, + {"gc", YAFFS_TRACE_GC}, + {"mtd", YAFFS_TRACE_MTD}, + {"nandaccess", YAFFS_TRACE_NANDACCESS}, + {"os", YAFFS_TRACE_OS}, + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, + {"scan", YAFFS_TRACE_SCAN}, + {"tracing", YAFFS_TRACE_TRACING}, + {"write", YAFFS_TRACE_WRITE}, + {"all", 0xffffffff}, + {"none", 0}, + {NULL, 0}, +}; + +static int yaffs_proc_write(struct file *file, const char *buf, + unsigned long count, void *data) +{ + unsigned rg = 0, mask_bitfield; + char *end, *mask_name; + int i; + int done = 0; + int add, len; + int pos = 0; + + rg = yaffs_traceMask; + + while (!done && (pos < count)) { + done = 1; + while ((pos < count) && isspace(buf[pos])) { + pos++; + } + + switch (buf[pos]) { + case '+': + case '-': + case '=': + add = buf[pos]; + pos++; + break; + + default: + add = ' '; + break; + } + mask_name = NULL; + mask_bitfield = simple_strtoul(buf + pos, &end, 0); + if (end > buf + pos) { + mask_name = "numeral"; + len = end - (buf + pos); + done = 0; + } else { + + for (i = 0; mask_flags[i].mask_name != NULL; i++) { + len = strlen(mask_flags[i].mask_name); + if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) { + mask_name = mask_flags[i].mask_name; + mask_bitfield = mask_flags[i].mask_bitfield; + done = 0; + break; + } + } + } + + if (mask_name != NULL) { + pos += len; + done = 0; + switch(add) { + case '-': + rg &= ~mask_bitfield; + break; + case '+': + rg |= mask_bitfield; + break; + case '=': + rg = mask_bitfield; + break; + default: + rg |= mask_bitfield; + break; + } + } + } + + yaffs_traceMask = rg; + if (rg & YAFFS_TRACE_ALWAYS) { + for (i = 0; mask_flags[i].mask_name != NULL; i++) { + char flag; + flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; + printk("%c%s\n", flag, mask_flags[i].mask_name); + } + } + + return count; +} + /* Stuff to handle installation of file systems */ struct file_system_to_install { struct file_system_type *fst; @@ -1709,11 +1961,15 @@ static int __init init_yaffs_fs(void) ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); /* Install the proc_fs entry */ - my_proc_entry = create_proc_read_entry("yaffs", + my_proc_entry = create_proc_entry("yaffs", S_IRUGO | S_IFREG, - &proc_root, - yaffs_proc_read, NULL); - if (!my_proc_entry) { + &proc_root); + + if (my_proc_entry) { + my_proc_entry->write_proc = yaffs_proc_write; + my_proc_entry->read_proc = yaffs_proc_read; + my_proc_entry->data = NULL; + } else { return -ENOMEM; } @@ -1771,5 +2027,5 @@ module_init(init_yaffs_fs) module_exit(exit_yaffs_fs) MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002,2003,2004"); +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); MODULE_LICENSE("GPL");