Runtime disbale of lazy loading. Fix problem where resize was breading rename shadowing
[yaffs2.git] / yaffs_fs.c
index 376dbdf70abd2e9a51c962b291fb0b79a95b0de9..93236e403f08030074640f810fa3ec1cb827e422 100644 (file)
@@ -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 <charles@aleph1.co.uk>
@@ -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.85 2009-10-15 00:45:46 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 #include <linux/version.h>
@@ -57,7 +57,7 @@ extern const char *yaffs_guts_c_version;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
 
 #include <linux/statfs.h>      /* Added NCB 15-8-2003 */
-#include <asm/statfs.h>
+#include <linux/statfs.h>
 #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 <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #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,10 @@ typedef struct {
        int skip_checkpoint_read;
        int skip_checkpoint_write;
        int no_cache;
+       int tags_ecc_on;
+       int tags_ecc_overridden;
+       int lazy_load_enabled;
+       int lazy_load_overridden;
 } yaffs_options;
 
 #define MAX_OPT_LEN 20
@@ -1815,6 +1831,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 +1844,19 @@ 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, "lazy-load-off")){
+                       options->lazy_load_enabled = 0;
+                       options->lazy_load_overridden=1;
+               } else if (!strcmp(cur_opt, "lazy-load-on")){
+                       options->lazy_load_enabled = 1;
+                       options->lazy_load_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 +1936,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 +1972,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 +2072,18 @@ 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_LAZY_LOAD
+       dev->disableLazyLoad = 1;
+#endif
+       if(options.lazy_load_overridden)
+               dev->disableLazyLoad = !options.lazy_load_enabled;
+
+#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 +2320,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 +2427,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 +2445,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 +2531,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 +2540,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++;
        }