Fix compilation on Linux 2.6.26, fix compilation warnings
[yaffs2.git] / yaffs_fs.c
index eceb34f3c0e23bd1f771d690255bdae2801497a2..2d0f8a068ef0755038db472a9068e4aee4944f9a 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 const char *yaffs_fs_c_version =
-    "$Id: yaffs_fs.c,v 1.65 2007-12-13 15:35:17 wookey Exp $";
+    "$Id: yaffs_fs.c,v 1.68 2008-07-23 03:35:12 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 #include <linux/version.h>
@@ -43,7 +43,6 @@ extern const char *yaffs_guts_c_version;
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/list.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
@@ -53,6 +52,8 @@ extern const char *yaffs_guts_c_version;
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#include "asm/div64.h"
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 
 #include <linux/statfs.h>      /* Added NCB 15-8-2003 */
@@ -76,6 +77,12 @@ extern const char *yaffs_guts_c_version;
 
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
+#define YPROC_ROOT  &proc_root
+#else
+#define YPROC_ROOT  NULL
+#endif
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 #define WRITE_SIZE_STR "writesize"
 #define WRITE_SIZE(mtd) (mtd)->writesize
@@ -106,6 +113,19 @@ MODULE_PARM(yaffs_traceMask,"i");
 MODULE_PARM(yaffs_wr_attempts,"i");
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
+/* use iget and read_inode */
+#define Y_IGET(sb,inum) iget((sb),(inum))
+static void yaffs_read_inode(struct inode *inode);
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb,inum) yaffs_iget((sb),(inum))
+
+static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino);
+#endif
+
 /*#define T(x) printk x */
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
@@ -181,9 +201,11 @@ static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
 #else
 static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
 #endif
-static void yaffs_read_inode(struct inode *inode);
 
+#ifdef YAFFS_HAS_PUT_INODE
 static void yaffs_put_inode(struct inode *inode);
+#endif
+
 static void yaffs_delete_inode(struct inode *);
 static void yaffs_clear_inode(struct inode *);
 
@@ -284,8 +306,13 @@ static struct file_operations yaffs_dir_operations = {
 
 static struct super_operations yaffs_super_ops = {
        .statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
        .read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
        .put_inode = yaffs_put_inode,
+#endif
        .put_super = yaffs_put_super,
        .delete_inode = yaffs_delete_inode,
        .clear_inode = yaffs_clear_inode,
@@ -429,6 +456,9 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
 
 }
 
+
+#ifdef YAFFS_HAS_PUT_INODE
+
 /* For now put inode is just for debugging
  * Put inode is called when the inode **structure** is put.
  */
@@ -439,6 +469,7 @@ static void yaffs_put_inode(struct inode *inode)
           atomic_read(&inode->i_count)));
 
 }
+#endif
 
 /* clear is called to tell the fs to release any per-inode data it holds */
 static void yaffs_clear_inode(struct inode *inode)
@@ -753,6 +784,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
                        break;
                }
 
+               inode->i_flags |= S_NOATIME;
+               
                inode->i_ino = obj->objectId;
                inode->i_mode = obj->yst_mode;
                inode->i_uid = obj->yst_uid;
@@ -844,7 +877,9 @@ struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
        T(YAFFS_TRACE_OS,
          (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
 
-       inode = iget(sb, obj->objectId);
+       inode = Y_IGET(sb, obj->objectId);
+       if(IS_ERR(inode))
+         return NULL;
 
        /* NB Side effect: iget calls back to yaffs_read_inode(). */
        /* iget also increments the inode's i_count */
@@ -916,7 +951,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
        yaffs_Device *dev;
        struct inode *inode = f->f_dentry->d_inode;
        unsigned long offset, curoffs;
-       struct list_head *i;
+       struct ylist_head *i;
        yaffs_Object *l;
 
        char name[YAFFS_MAX_NAME_LENGTH + 1];
@@ -965,10 +1000,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                f->f_version = inode->i_version;
        }
 
-       list_for_each(i, &obj->variant.directoryVariant.children) {
+       ylist_for_each(i, &obj->variant.directoryVariant.children) {
                curoffs++;
                if (curoffs >= offset) {
-                       l = list_entry(i, yaffs_Object, siblings);
+                       l = ylist_entry(i, yaffs_Object, siblings);
 
                        yaffs_GetObjectName(l, name,
                                            YAFFS_MAX_NAME_LENGTH + 1);
@@ -1269,7 +1304,7 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        if (target &&
            target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
-           !list_empty(&target->variant.directoryVariant.children)) {
+           !ylist_empty(&target->variant.directoryVariant.children)) {
 
                T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
 
@@ -1350,25 +1385,47 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
        buf->f_type = YAFFS_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_namelen = 255;
-       if (sb->s_blocksize > dev->nDataBytesPerChunk) {
-
+       
+       if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
+               /* Do this if chunk size is not a power of 2 */
+               
+               uint64_t bytesInDev;
+               uint64_t bytesFree;
+
+               bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
+                            ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
+       
+               do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
+               buf->f_blocks = bytesInDev;
+
+               bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
+                            ((uint64_t)(dev->nDataBytesPerChunk));
+       
+               do_div(bytesFree,sb->s_blocksize);
+       
+               buf->f_bfree = bytesFree;
+       
+       } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
+       
                buf->f_blocks =
-                   (dev->endBlock - dev->startBlock +
-                    1) * dev->nChunksPerBlock / (sb->s_blocksize /
-                                                 dev->nDataBytesPerChunk);
-               buf->f_bfree =
-                   yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
-                                                       dev->nDataBytesPerChunk);
+                          (dev->endBlock - dev->startBlock + 1) * 
+                           dev->nChunksPerBlock / 
+                           (sb->s_blocksize / dev->nDataBytesPerChunk);
+               buf->f_bfree =
+                          yaffs_GetNumberOfFreeChunks(dev) / 
+                          (sb->s_blocksize / dev->nDataBytesPerChunk);
        } else {
-
-               buf->f_blocks =
-                   (dev->endBlock - dev->startBlock +
-                    1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
-                                                 sb->s_blocksize);
-               buf->f_bfree =
-                   yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
-                                                       sb->s_blocksize);
+              buf->f_blocks =
+                          (dev->endBlock - dev->startBlock + 1) * 
+                          dev->nChunksPerBlock * 
+                          (dev->nDataBytesPerChunk / sb->s_blocksize);
+                          
+                      buf->f_bfree =
+                          yaffs_GetNumberOfFreeChunks(dev) * 
+                          (dev->nDataBytesPerChunk / sb->s_blocksize);
        }
+       
+       
        buf->f_files = 0;
        buf->f_ffree = 0;
        buf->f_bavail = buf->f_bfree;
@@ -1378,7 +1435,6 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
 }
 
 
-/**
 static int yaffs_do_sync_fs(struct super_block *sb)
 {
 
@@ -1388,8 +1444,10 @@ static int yaffs_do_sync_fs(struct super_block *sb)
        if(sb->s_dirt) {
                yaffs_GrossLock(dev);
 
-               if(dev)
+               if(dev){
+                       yaffs_FlushEntireDeviceCache(dev);
                        yaffs_CheckpointSave(dev);
+               }
 
                yaffs_GrossUnlock(dev);
 
@@ -1397,7 +1455,7 @@ static int yaffs_do_sync_fs(struct super_block *sb)
        }
        return 0;
 }
-**/
+
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 static void yaffs_write_super(struct super_block *sb)
@@ -1407,8 +1465,9 @@ static int yaffs_write_super(struct super_block *sb)
 {
 
        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
+       yaffs_do_sync_fs(sb);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
-       return 0; /* yaffs_do_sync_fs(sb);*/
+       return 0; 
 #endif
 }
 
@@ -1422,10 +1481,47 @@ 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);*/
+       yaffs_do_sync_fs(sb);
+       
+       return 0; 
+
+}
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+       struct inode *inode;
+       yaffs_Object *obj;
+       yaffs_Device *dev = yaffs_SuperToDevice(sb);
 
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_iget for %lu\n", ino));
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       /* NB This is called as a side effect of other functions, but
+       * we had to release the lock to prevent deadlocks, so
+       * need to lock again.
+       */
+    
+       yaffs_GrossLock(dev);
+
+       obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+       yaffs_FillInodeFromObject(inode, obj);
+
+       yaffs_GrossUnlock(dev);
+       
+       unlock_new_inode(inode);
+       return inode;
 }
 
+#else
 
 static void yaffs_read_inode(struct inode *inode)
 {
@@ -1449,7 +1545,9 @@ static void yaffs_read_inode(struct inode *inode)
        yaffs_GrossUnlock(dev);
 }
 
-static LIST_HEAD(yaffs_dev_list);
+#endif
+
+static YLIST_HEAD(yaffs_dev_list);
 
 #if 0 // not used
 static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -1503,7 +1601,7 @@ static void yaffs_put_super(struct super_block *sb)
        yaffs_GrossUnlock(dev);
 
        /* we assume this is protected by lock_kernel() in mount/umount */
-       list_del(&dev->devList);
+       ylist_del(&dev->devList);
 
        if(dev->spareBuffer){
                YFREE(dev->spareBuffer);
@@ -1602,6 +1700,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
 
        sb->s_magic = YAFFS_MAGIC;
        sb->s_op = &yaffs_super_ops;
+       sb->s_flags |= MS_NOATIME;
 
        if (!sb)
                printk(KERN_INFO "yaffs: sb is NULL\n");
@@ -1678,22 +1777,15 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
 
        if (yaffsVersion == 1 &&
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-           mtd->writesize >= 2048) {
-#else
-           mtd->oobblock >= 2048) {
-#endif
+           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 &&
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-           mtd->writesize == 512) {
-#else
-           mtd->oobblock == 512) {
-#endif
+       if (yaffsVersion == 2 && 
+           !options.inband_tags &&
+           WRITE_SIZE(mtd) == 512){
            T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
            yaffsVersion = 1;
        }
@@ -1719,12 +1811,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
                        return NULL;
                }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-               if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
-#else
-               if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
-#endif
-                   mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
+               if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+                   mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
+                   !options.inband_tags) {
                        T(YAFFS_TRACE_ALWAYS,
                          ("yaffs: MTD device does not have the "
                           "right page sizes\n"));
@@ -1784,9 +1873,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        dev->startBlock = 0;
        dev->endBlock = nBlocks - 1;
        dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
-       dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+       dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
        dev->nReservedBlocks = 5;
        dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
+       dev->inbandTags = options.inband_tags;
 
        /* ... and the functions. */
        if (yaffsVersion == 2) {
@@ -1799,10 +1889,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
                dev->spareBuffer = YMALLOC(mtd->oobsize);
                dev->isYaffs2 = 1;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-               dev->nDataBytesPerChunk = mtd->writesize;
+               dev->totalBytesPerChunk = mtd->writesize;
                dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
 #else
-               dev->nDataBytesPerChunk = mtd->oobblock;
+               dev->totalBytesPerChunk = mtd->oobblock;
                dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
 #endif
                nBlocks = mtd->size / mtd->erasesize;
@@ -1846,7 +1936,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        dev->skipCheckpointWrite = options.skip_checkpoint_write;
 
        /* we assume this is protected by lock_kernel() in mount/umount */
-       list_add_tail(&dev->devList, &yaffs_dev_list);
+       ylist_add_tail(&dev->devList, &yaffs_dev_list);
 
        init_MUTEX(&dev->grossLock);
 
@@ -1989,6 +2079,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
 {
        buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
        buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
+       buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
        buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
        buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
        buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
@@ -2004,10 +2095,8 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
        buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
        buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
        buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
-       buf +=
-           sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
-       buf +=
-           sprintf(buf, "passiveGCs......... %d\n",
+       buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
+       buf += sprintf(buf, "passiveGCs......... %d\n",
                    dev->passiveGarbageCollections);
        buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
        buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
@@ -2023,6 +2112,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
            sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
        buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
        buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
+       buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
 
        return buf;
 }
@@ -2031,7 +2121,7 @@ static int yaffs_proc_read(char *page,
                           char **start,
                           off_t offset, int count, int *eof, void *data)
 {
-       struct list_head *item;
+       struct ylist_head *item;
        char *buf = page;
        int step = offset;
        int n = 0;
@@ -2055,8 +2145,8 @@ static int yaffs_proc_read(char *page,
        lock_kernel();
 
        /* Locate and print the Nth entry.  Order N-squared but N is small. */
-       list_for_each(item, &yaffs_dev_list) {
-               yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
+       ylist_for_each(item, &yaffs_dev_list) {
+               yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
                if (n < step) {
                        n++;
                        continue;
@@ -2229,7 +2319,7 @@ static int __init init_yaffs_fs(void)
        /* Install the proc_fs entry */
        my_proc_entry = create_proc_entry("yaffs",
                                               S_IRUGO | S_IFREG,
-                                              &proc_root);
+                                              YPROC_ROOT);
 
        if (my_proc_entry) {
                my_proc_entry->write_proc = yaffs_proc_write;
@@ -2275,7 +2365,7 @@ static void __exit exit_yaffs_fs(void)
        T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
                               " removing. \n"));
 
-       remove_proc_entry("yaffs", &proc_root);
+       remove_proc_entry("yaffs", YPROC_ROOT);
 
        fsinst = fs_to_install;