Bounds check on ecc correction
[yaffs2.git] / yaffs_fs.c
index 101cecf1c62e3729fdade0f99b8ce1dc5708c739..d90e2915f71655d6163ff8f4de0e13d3e022b8bb 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 const char *yaffs_fs_c_version =
-    "$Id: yaffs_fs.c,v 1.42 2006-02-08 07:52:51 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 <linux/config.h>
@@ -66,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 <asm/uaccess.h>
@@ -73,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 <linux/mtd/mtd.h>
 #include "yaffs_mtdif.h"
@@ -129,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
@@ -214,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)
@@ -638,6 +651,40 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
 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;
@@ -902,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,
@@ -1249,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
@@ -1277,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);
 }
@@ -1304,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)
@@ -1385,6 +1498,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
            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) {
@@ -1405,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;
                }
@@ -1476,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 {
@@ -1488,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;
@@ -1900,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");