yaffs Mark superblock dirty on writes
[yaffs2.git] / yaffs_fs.c
index f0c2771ece0b0339cc6eb27c549a7310041b9ebb..8e39ce251d5513557cb93130c760a11fa2e5040c 100644 (file)
 #define YAFFS_COMPILE_EXPORTFS
 #endif
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+#define YAFFS_NEW_FOLLOW_LINK 1
+#else
+#define YAFFS_NEW_FOLLOW_LINK 0
+#endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
 #include <linux/config.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+#include <linux/namei.h>
+#endif
+
 #ifdef YAFFS_COMPILE_EXPORTFS
 #include <linux/exportfs.h>
 #endif
@@ -295,11 +304,15 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
 
 static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
                                int buflen);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
 #else
 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
 #endif
+
+static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
+
 static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
 
 static struct address_space_operations yaffs_file_address_operations = {
@@ -379,6 +392,9 @@ static const struct inode_operations yaffs_file_inode_operations = {
 static const struct inode_operations yaffs_symlink_inode_operations = {
        .readlink = yaffs_readlink,
        .follow_link = yaffs_follow_link,
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+       .put_link = yaffs_put_link,
+#endif
        .setattr = yaffs_setattr,
 #ifdef CONFIG_YAFFS_XATTR
        .setxattr = yaffs_setxattr,
@@ -438,14 +454,14 @@ static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
 static void yaffs_GrossLock(yaffs_Device *dev)
 {
        T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
-       down(&(yaffs_DeviceToContext(dev)->grossLock));
+       down(&(yaffs_DeviceToLC(dev)->grossLock));
        T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
 }
 
 static void yaffs_GrossUnlock(yaffs_Device *dev)
 {
        T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
-       up(&(yaffs_DeviceToContext(dev)->grossLock));
+       up(&(yaffs_DeviceToLC(dev)->grossLock));
 }
 
 #ifdef YAFFS_COMPILE_EXPORTFS
@@ -560,7 +576,7 @@ static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
                                 dir->variant.directoryVariant.children.next,
                                yaffs_Object,siblings);
                YINIT_LIST_HEAD(&sc->others);
-               ylist_add(&sc->others,&(yaffs_DeviceToContext(dev)->searchContexts));
+               ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
        }
        return sc;
 }
@@ -609,7 +625,7 @@ static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
 
         struct ylist_head *i;
         struct yaffs_SearchContext *sc;
-        struct ylist_head *search_contexts = &(yaffs_DeviceToContext(obj->myDev)->searchContexts);
+        struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
 
 
         /* Iterate through the directory search contexts.
@@ -651,7 +667,7 @@ static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
        return ret;
 }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
 #else
 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
@@ -664,7 +680,6 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
        yaffs_GrossLock(dev);
 
        alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
-
        yaffs_GrossUnlock(dev);
 
        if (!alias) {
@@ -672,16 +687,25 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
                goto out;
        }
 
-       ret = vfs_follow_link(nd, alias);
-       kfree(alias);
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+       nd_set_link(nd, alias);
+       ret = (int)alias;
 out:
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
        return ERR_PTR(ret);
 #else
+       ret = vfs_follow_link(nd, alias);
+       kfree(alias);
+out:
        return ret;
 #endif
 }
 
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
+       kfree(alias);
+}
+#endif
+
 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
                                yaffs_Object *obj);
 
@@ -701,7 +725,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
 
        yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
 
-       if(current != yaffs_DeviceToContext(dev)->readdirProcess)
+       if(current != yaffs_DeviceToLC(dev)->readdirProcess)
                yaffs_GrossLock(dev);
 
        T(YAFFS_TRACE_OS,
@@ -714,7 +738,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
        obj = yaffs_GetEquivalentObject(obj);   /* in case it was a hardlink */
 
        /* Can't hold gross lock when calling yaffs_get_inode() */
-       if(current != yaffs_DeviceToContext(dev)->readdirProcess)
+       if(current != yaffs_DeviceToLC(dev)->readdirProcess)
                yaffs_GrossUnlock(dev);
 
        if (obj) {
@@ -929,6 +953,7 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
 static int yaffs_writepage(struct page *page)
 #endif
 {
+       yaffs_Device *dev;
        struct address_space *mapping = page->mapping;
        struct inode *inode;
        unsigned long end_index;
@@ -976,7 +1001,8 @@ static int yaffs_writepage(struct page *page)
        buffer = kmap(page);
 
        obj = yaffs_InodeToObject(inode);
-       yaffs_GrossLock(obj->myDev);
+       dev = obj->myDev;
+       yaffs_GrossLock(dev);
 
        T(YAFFS_TRACE_OS,
                (TSTR("yaffs_writepage at %08x, size %08x\n"),
@@ -988,11 +1014,13 @@ static int yaffs_writepage(struct page *page)
        nWritten = yaffs_WriteDataToFile(obj, buffer,
                        page->index << PAGE_CACHE_SHIFT, nBytes, 0);
 
+       yaffs_MarkSuperBlockDirty(dev);
+
        T(YAFFS_TRACE_OS,
                (TSTR("writepag1: obj = %05x, ino = %05x\n"),
                (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
 
-       yaffs_GrossUnlock(obj->myDev);
+       yaffs_GrossUnlock(dev);
 
        kunmap(page);
        set_page_writeback(page);
@@ -1328,6 +1356,8 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
 
        nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
 
+       yaffs_MarkSuperBlockDirty(dev);
+
        T(YAFFS_TRACE_OS,
                (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
                (unsigned )n,(unsigned)n));
@@ -1435,7 +1465,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 
        yaffs_GrossLock(dev);
 
-       yaffs_DeviceToContext(dev)->readdirProcess = current;
+       yaffs_DeviceToLC(dev)->readdirProcess = current;
 
        offset = f->f_pos;
 
@@ -1520,7 +1550,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 
 out:
        yaffs_EndSearch(sc);
-       yaffs_DeviceToContext(dev)->readdirProcess = NULL;
+       yaffs_DeviceToLC(dev)->readdirProcess = NULL;
        yaffs_GrossUnlock(dev);
 
        return retVal;
@@ -2100,7 +2130,7 @@ static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
 static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
 {
        unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
-       struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev);
+       struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
        unsigned scatteredFree = 0; /* Free chunks not in an erased block */
 
        if(erasedChunks < dev->nFreeChunks)
@@ -2172,7 +2202,7 @@ void yaffs_background_waker(unsigned long data)
 static int yaffs_BackgroundThread(void *data)
 {
        yaffs_Device *dev = (yaffs_Device *)data;
-       struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev);
+       struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
        unsigned long now = jiffies;
        unsigned long next_dir_update = now;
        unsigned long next_gc = now;
@@ -2251,7 +2281,10 @@ static int yaffs_BackgroundThread(void *data)
 static int yaffs_BackgroundStart(yaffs_Device *dev)
 {
        int retval = 0;
-       struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev);
+       struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
+
+       if(dev->readOnly)
+               return -1;
 
        context->bgRunning = 1;
 
@@ -2268,7 +2301,7 @@ static int yaffs_BackgroundStart(yaffs_Device *dev)
 
 static void yaffs_BackgroundStop(yaffs_Device *dev)
 {
-       struct yaffs_LinuxContext *ctxt = yaffs_DeviceToContext(dev);
+       struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
 
        ctxt->bgRunning = 0;
 
@@ -2380,14 +2413,14 @@ static void yaffs_read_inode(struct inode *inode)
        T(YAFFS_TRACE_OS,
                (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
 
-       if(current != yaffs_DeviceToContext(dev)->readdirProcess)
+       if(current != yaffs_DeviceToLC(dev)->readdirProcess)
                yaffs_GrossLock(dev);
 
        obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
 
        yaffs_FillInodeFromObject(inode, obj);
 
-       if(current != yaffs_DeviceToContext(dev)->readdirProcess)
+       if(current != yaffs_DeviceToLC(dev)->readdirProcess)
                yaffs_GrossUnlock(dev);
 }
 
@@ -2396,34 +2429,6 @@ static void yaffs_read_inode(struct inode *inode)
 static YLIST_HEAD(yaffs_context_list);
 struct semaphore yaffs_context_lock;
 
-#if 0 /* not used */
-static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
-{
-       yaffs_Device    *dev = yaffs_SuperToDevice(sb);
-
-       if (*flags & MS_RDONLY) {
-               struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
-
-               T(YAFFS_TRACE_OS,
-                       (TSTR("yaffs_remount_fs: %s: RO\n"), dev->name));
-
-               yaffs_GrossLock(dev);
-
-               yaffs_FlushSuperBlock(sb,1);
-
-               if (mtd->sync)
-                       mtd->sync(mtd);
-
-               yaffs_GrossUnlock(dev);
-       } else {
-               T(YAFFS_TRACE_OS,
-                       (TSTR("yaffs_remount_fs: %s: RW\n"), dev->name));
-       }
-
-       return 0;
-}
-#endif
-
 static void yaffs_put_super(struct super_block *sb)
 {
        yaffs_Device *dev = yaffs_SuperToDevice(sb);
@@ -2440,8 +2445,8 @@ static void yaffs_put_super(struct super_block *sb)
 
        yaffs_FlushSuperBlock(sb,1);
 
-       if (yaffs_DeviceToContext(dev)->putSuperFunc)
-               yaffs_DeviceToContext(dev)->putSuperFunc(sb);
+       if (yaffs_DeviceToLC(dev)->putSuperFunc)
+               yaffs_DeviceToLC(dev)->putSuperFunc(sb);
 
 
        yaffs_Deinitialise(dev);
@@ -2449,12 +2454,12 @@ static void yaffs_put_super(struct super_block *sb)
        yaffs_GrossUnlock(dev);
 
        down(&yaffs_context_lock);
-       ylist_del_init(&(yaffs_DeviceToContext(dev)->contextList));
+       ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
        up(&yaffs_context_lock);
 
-       if (yaffs_DeviceToContext(dev)->spareBuffer) {
-               YFREE(yaffs_DeviceToContext(dev)->spareBuffer);
-               yaffs_DeviceToContext(dev)->spareBuffer = NULL;
+       if (yaffs_DeviceToLC(dev)->spareBuffer) {
+               YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
+               yaffs_DeviceToLC(dev)->spareBuffer = NULL;
        }
 
        kfree(dev);
@@ -2463,7 +2468,7 @@ static void yaffs_put_super(struct super_block *sb)
 
 static void yaffs_MTDPutSuper(struct super_block *sb)
 {
-       struct mtd_info *mtd = yaffs_DeviceToContext(yaffs_SuperToDevice(sb))->mtd;
+       struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
 
        if (mtd->sync)
                mtd->sync(mtd);
@@ -2474,7 +2479,7 @@ static void yaffs_MTDPutSuper(struct super_block *sb)
 
 static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
 {
-       struct super_block *sb = yaffs_DeviceToContext(dev)->superBlock;
+       struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
 
        T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
        if (sb)
@@ -2572,6 +2577,8 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        struct yaffs_LinuxContext *context = NULL;
        yaffs_DeviceParam *param;
 
+       int readOnly = 0;
+
        yaffs_options options;
 
        unsigned mount_id;
@@ -2583,6 +2590,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        sb->s_op = &yaffs_super_ops;
        sb->s_flags |= MS_NOATIME;
 
+       readOnly =((sb->s_flags & MS_RDONLY) != 0);
+
+
 #ifdef YAFFS_COMPILE_EXPORTFS
        sb->s_export_op = &yaffs_export_ops;
 #endif
@@ -2594,9 +2604,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        else if (!yaffs_devname(sb, devname_buf))
                printk(KERN_INFO "yaffs: devname is NULL\n");
        else
-               printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
+               printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
                       sb->s_dev,
-                      yaffs_devname(sb, devname_buf));
+                      yaffs_devname(sb, devname_buf),
+                      readOnly ? "ro" : "rw");
 
        if (!data_str)
                data_str = "";
@@ -2736,6 +2747,12 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
         * Set the yaffs_Device up for mtd
         */
 
+       if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
+               readOnly = 1;
+               printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
+               sb->s_flags |= MS_RDONLY;
+       }
+
        dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
        context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
        
@@ -2759,12 +2776,12 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        param = &(dev->param);
 
        memset(context,0,sizeof(struct yaffs_LinuxContext));
-       dev->context = context;
+       dev->osContext = context;
        YINIT_LIST_HEAD(&(context->contextList));
        context->dev = dev;
        context->superBlock = sb;
 
-       
+       dev->readOnly = readOnly;
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
        sb->s_fs_info = dev;
@@ -2772,7 +2789,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        sb->u.generic_sbp = dev;
 #endif
        
-       yaffs_DeviceToContext(dev)->mtd = mtd;
+       dev->driverContext = mtd;
        param->name = mtd->name;
 
        /* Set up the memory size parameters.... */
@@ -2829,7 +2846,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
                    nandmtd2_ReadChunkWithTagsFromNAND;
                param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
                param->queryNANDBlock = nandmtd2_QueryNANDBlock;
-               yaffs_DeviceToContext(dev)->spareBuffer = YMALLOC(mtd->oobsize);
+               yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
                param->isYaffs2 = 1;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
                param->totalBytesPerChunk = mtd->writesize;
@@ -2861,12 +2878,12 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
        param->initialiseNAND = nandmtd_InitialiseNAND;
 
-       yaffs_DeviceToContext(dev)->putSuperFunc = yaffs_MTDPutSuper;
+       yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
 
        param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
        param->gcControl = yaffs_gc_control_callback;
 
-       yaffs_DeviceToContext(dev)->superBlock= sb;
+       yaffs_DeviceToLC(dev)->superBlock= sb;
        
 
 #ifndef CONFIG_YAFFS_DOES_ECC
@@ -2893,14 +2910,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        }
        context->mount_id = mount_id;
 
-       ylist_add_tail(&(yaffs_DeviceToContext(dev)->contextList), &yaffs_context_list);
+       ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
        up(&yaffs_context_lock);
 
         /* Directory search handling...*/
-        YINIT_LIST_HEAD(&(yaffs_DeviceToContext(dev)->searchContexts));
+        YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
         param->removeObjectCallback = yaffs_RemoveObjectCallback;
 
-       init_MUTEX(&(yaffs_DeviceToContext(dev)->grossLock));
+       init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
 
        yaffs_GrossLock(dev);