X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=a51dc20de633f900f25cf4ba5c8d993142956012;hp=376dbdf70abd2e9a51c962b291fb0b79a95b0de9;hb=1ffa02489a63129109b66774681c94fe0a8a946a;hpb=3e5718ec7f0df7b76837d10583419b745cb27474 diff --git a/yaffs_fs.c b/yaffs_fs.c index 376dbdf..a51dc20 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2007 Aleph One Ltd. + * Copyright (C) 2002-2009 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -32,7 +32,7 @@ */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.76 2009-03-06 17:20:51 wookey Exp $"; + "$Id: yaffs_fs.c,v 1.84 2009-10-14 00:01:56 charles Exp $"; extern const char *yaffs_guts_c_version; #include @@ -57,7 +57,7 @@ extern const char *yaffs_guts_c_version; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) #include /* Added NCB 15-8-2003 */ -#include +#include #define UnlockPage(p) unlock_page(p) #define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) @@ -108,7 +108,7 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) #define YCALCBLOCKS(s, b) ((s)/(b)) #endif -#include +#include #include "yportenv.h" #include "yaffs_guts.h" @@ -163,6 +163,11 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) #endif + +#define update_dir_time(dir) do {\ + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ + } while(0) + static void yaffs_put_super(struct super_block *sb); static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, @@ -275,7 +280,7 @@ static struct address_space_operations yaffs_file_address_operations = { }; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) -static struct file_operations yaffs_file_operations = { +static const struct file_operations yaffs_file_operations = { .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, @@ -290,7 +295,7 @@ static struct file_operations yaffs_file_operations = { #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) -static struct file_operations yaffs_file_operations = { +static const struct file_operations yaffs_file_operations = { .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, @@ -303,7 +308,7 @@ static struct file_operations yaffs_file_operations = { #else -static struct file_operations yaffs_file_operations = { +static const struct file_operations yaffs_file_operations = { .read = generic_file_read, .write = generic_file_write, .mmap = generic_file_mmap, @@ -315,17 +320,17 @@ static struct file_operations yaffs_file_operations = { }; #endif -static struct inode_operations yaffs_file_inode_operations = { +static const struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, }; -static struct inode_operations yaffs_symlink_inode_operations = { +static const struct inode_operations yaffs_symlink_inode_operations = { .readlink = yaffs_readlink, .follow_link = yaffs_follow_link, .setattr = yaffs_setattr, }; -static struct inode_operations yaffs_dir_inode_operations = { +static const struct inode_operations yaffs_dir_inode_operations = { .create = yaffs_create, .lookup = yaffs_lookup, .link = yaffs_link, @@ -338,13 +343,13 @@ static struct inode_operations yaffs_dir_inode_operations = { .setattr = yaffs_setattr, }; -static struct file_operations yaffs_dir_operations = { +static const struct file_operations yaffs_dir_operations = { .read = generic_read_dir, .readdir = yaffs_readdir, .fsync = yaffs_sync_object, }; -static struct super_operations yaffs_super_ops = { +static const struct super_operations yaffs_super_ops = { .statfs = yaffs_statfs, #ifndef YAFFS_USE_OWN_IGET @@ -420,7 +425,7 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) kfree(alias); out: #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) - return ERR_PTR (ret); + return ERR_PTR(ret); #else return ret; #endif @@ -489,8 +494,6 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) d_add(dentry, inode); return NULL; - /* return (ERR_PTR(-EIO)); */ - } @@ -565,7 +568,7 @@ static void yaffs_delete_inode(struct inode *inode) yaffs_GrossUnlock(dev); } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) - truncate_inode_pages (&inode->i_data, 0); + truncate_inode_pages(&inode->i_data, 0); #endif clear_inode(inode); } @@ -586,7 +589,7 @@ static int yaffs_file_flush(struct file *file) yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1,0); yaffs_GrossUnlock(dev); @@ -623,8 +626,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) yaffs_GrossLock(dev); - ret = - yaffs_ReadDataFromFile(obj, pg_buf, + ret = yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE); @@ -697,11 +699,10 @@ static int yaffs_writepage(struct page *page) end_index = inode->i_size >> PAGE_CACHE_SHIFT; /* easy case */ - if (page->index < end_index) { + if (page->index < end_index) nBytes = PAGE_CACHE_SIZE; - } else { + else nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); - } get_page(page); @@ -750,7 +751,7 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); /* Get a page */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) pg = grab_cache_page_write_begin(mapping, index, flags); #else pg = __grab_cache_page(mapping, index); @@ -784,9 +785,8 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, out: T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); - if (space_held) { + if (space_held) yaffs_release_space(filp); - } if (pg) { unlock_page(pg); page_cache_release(pg); @@ -1045,27 +1045,26 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, inode = f->f_dentry->d_inode; - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) { + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) ipos = inode->i_size; - } else { + else ipos = *pos; - } - if (!obj) { + if (!obj) T(YAFFS_TRACE_OS, ("yaffs_file_write: hey obj is null!\n")); - } else { + else T(YAFFS_TRACE_OS, ("yaffs_file_write about to write writing %zu bytes" "to object %d at %d\n", n, obj->objectId, ipos)); - } nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); T(YAFFS_TRACE_OS, ("yaffs_file_write writing %zu bytes, %d written at %d\n", n, nWritten, ipos)); + if (nWritten > 0) { ipos += nWritten; *pos = ipos; @@ -1081,7 +1080,7 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, } yaffs_GrossUnlock(dev); - return nWritten == 0 ? -ENOSPC : nWritten; + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten; } /* Space holding and freeing is done to ensure we have space available for write_begin/end */ @@ -1149,9 +1148,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) T(YAFFS_TRACE_OS, ("yaffs_readdir: entry . ino %d \n", (int)inode->i_ino)); - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) goto out; - } offset++; f->f_pos++; } @@ -1160,9 +1158,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ("yaffs_readdir: entry .. ino %d \n", (int)f->f_dentry->d_parent->d_inode->i_ino)); if (filldir(dirent, "..", 2, offset, - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) goto out; - } offset++; f->f_pos++; } @@ -1194,9 +1191,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) strlen(name), offset, yaffs_GetObjectInode(l), - yaffs_GetObjectType(l)) < 0) { + yaffs_GetObjectType(l)) < 0) goto up_and_out; - } offset++; f->f_pos++; @@ -1295,6 +1291,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, if (obj) { inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); d_instantiate(dentry, inode); + update_dir_time(dir); T(YAFFS_TRACE_OS, ("yaffs_mknod created object %d count = %d\n", obj->objectId, atomic_read(&inode->i_count))); @@ -1313,12 +1310,6 @@ static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) int retVal; T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); -#if 0 - /* attempt to fix dir bug - didn't work */ - if (!retVal) { - dget(dentry); - } -#endif return retVal; } @@ -1354,6 +1345,7 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) dir->i_version++; yaffs_GrossUnlock(dev); mark_inode_dirty(dentry->d_inode); + update_dir_time(dir); return 0; } yaffs_GrossUnlock(dev); @@ -1378,10 +1370,9 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, yaffs_GrossLock(dev); - if (!S_ISDIR(inode->i_mode)) { /* Don't link directories */ + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, obj); - } if (link) { old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); @@ -1395,7 +1386,8 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, yaffs_GrossUnlock(dev); - if (link) { + if (link){ + update_dir_time(dir); return 0; } @@ -1423,6 +1415,7 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry, inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); d_instantiate(dentry, inode); + update_dir_time(dir); T(YAFFS_TRACE_OS, ("symlink created OK\n")); return 0; } else { @@ -1445,7 +1438,7 @@ static int yaffs_sync_object(struct file *file, struct dentry *dentry, T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1, datasync); yaffs_GrossUnlock(dev); return 0; } @@ -1495,7 +1488,10 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dentry->d_inode->i_nlink--; mark_inode_dirty(new_dentry->d_inode); } - + + update_dir_time(old_dir); + if(old_dir != new_dir) + update_dir_time(new_dir); return 0; } else { return -ENOTEMPTY; @@ -1600,6 +1596,21 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) } + +static void yaffs_flush_sb_inodes(struct super_block *sb) +{ + struct inode *iptr; + yaffs_Object *obj; + + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){ + obj = yaffs_InodeToObject(iptr); + if(obj){ + T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId)); + yaffs_FlushFile(obj,1,0); + } + } +} + static int yaffs_do_sync_fs(struct super_block *sb) { @@ -1611,6 +1622,7 @@ static int yaffs_do_sync_fs(struct super_block *sb) if (dev) { yaffs_FlushEntireDeviceCache(dev); + yaffs_flush_sb_inodes(sb); yaffs_CheckpointSave(dev); } @@ -1800,6 +1812,8 @@ typedef struct { int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; + int tags_ecc_on; + int tags_ecc_overridden; } yaffs_options; #define MAX_OPT_LEN 20 @@ -1815,6 +1829,9 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) memset(cur_opt, 0, MAX_OPT_LEN + 1); p = 0; + while(*options_str == ',') + options_str++; + while (*options_str && *options_str != ',') { if (p < MAX_OPT_LEN) { cur_opt[p] = *options_str; @@ -1825,7 +1842,13 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) if (!strcmp(cur_opt, "inband-tags")) options->inband_tags = 1; - else if (!strcmp(cur_opt, "no-cache")) + else if (!strcmp(cur_opt, "tags-ecc-off")){ + options->tags_ecc_on = 0; + options->tags_ecc_overridden=1; + } else if (!strcmp(cur_opt, "tags-ecc-on")){ + options->tags_ecc_on = 1; + options->tags_ecc_overridden = 1; + } else if (!strcmp(cur_opt, "no-cache")) options->no_cache = 1; else if (!strcmp(cur_opt, "no-checkpoint-read")) options->skip_checkpoint_read = 1; @@ -1905,9 +1928,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, yaffs_devname(sb, devname_buf))); /* Check it's an mtd device..... */ - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) return NULL; /* This isn't an mtd device */ - } + /* Get the device */ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); if (!mtd) { @@ -1941,18 +1964,15 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, #ifdef CONFIG_YAFFS_AUTO_YAFFS2 - if (yaffsVersion == 1 && - WRITE_SIZE(mtd) >= 2048) { - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); - yaffsVersion = 2; + if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { + T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); + yaffsVersion = 2; } /* Added NCB 26/5/2006 for completeness */ - if (yaffsVersion == 2 && - !options.inband_tags && - WRITE_SIZE(mtd) == 512) { - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); - yaffsVersion = 1; + if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { + T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); + yaffsVersion = 1; } #endif @@ -2044,6 +2064,12 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->inbandTags = options.inband_tags; +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC + dev->noTagsECC = 1; +#endif + if(options.tags_ecc_overridden) + dev->noTagsECC = !options.tags_ecc_on; + /* ... and the functions. */ if (yaffsVersion == 2) { dev->writeChunkWithTagsToNAND = @@ -2280,6 +2306,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) buf += sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC); buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); @@ -2386,9 +2413,8 @@ static int yaffs_proc_write(struct file *file, const char *buf, while (!done && (pos < count)) { done = 1; - while ((pos < count) && isspace(buf[pos])) { + while ((pos < count) && isspace(buf[pos])) pos++; - } switch (buf[pos]) { case '+': @@ -2405,6 +2431,7 @@ static int yaffs_proc_write(struct file *file, const char *buf, mask_name = NULL; mask_bitfield = simple_strtoul(buf + pos, &end, 0); + if (end > buf + pos) { mask_name = "numeral"; len = end - (buf + pos); @@ -2490,9 +2517,8 @@ static int __init init_yaffs_fs(void) my_proc_entry->write_proc = yaffs_proc_write; my_proc_entry->read_proc = yaffs_proc_read; my_proc_entry->data = NULL; - } else { + } else return -ENOMEM; - } /* Now add the file system entries */ @@ -2500,9 +2526,8 @@ static int __init init_yaffs_fs(void) while (fsinst->fst && !error) { error = register_filesystem(fsinst->fst); - if (!error) { + if (!error) fsinst->installed = 1; - } fsinst++; }