Re: [Yaffs] [PATCH] make yaffs2 work with 2.6.17+ kernels

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Vitaly Wool
Date:  
To: Charles Manning
CC: yaffs
Subject: Re: [Yaffs] [PATCH] make yaffs2 work with 2.6.17+ kernels
On Wed, 20 Sep 2006 21:08:56 +1200
Charles Manning <> wrote:

> The oob layout I used for yaffs1 fits in with the SmartMedia spec (in terms of
> placement of ECC, block & page state bytes etc). SM uses 1 byte for block
> state. YAFFS1 used to use 0x00 to mark bad blocks, but I changed this to 'Y'
> to make it easier to tell factory marked bad blocks from yaffs-marked.


I don't think you should worry about that much, since there's always a way to figure out bad blocks from MTD/NAND layer. You can think of that as of compatibility thingie, not to intrude into yaffs too much for the moment.

> This breaks down with some of the more modern non-SM-compatable parts which
> have internal controllers etc and don't give you full access to the 16 bytes.
>
>
> >
> > I assume there's a better way to do it, but I don't know it.
> > The _real_ way out would be to have the tags fit in not more than 8 bytes,
> > better in 6.
>
> The real way, I think, is to start doing tags-in-data for 512 then it can run
> yaffs2 on 512-byte pages. Watch this space......


Oh yeah, that's definitely the best, but let's first stabilize this one. It will work for most cases, I think.

> > And thanks a lot for the review!
>
> Yea, sorry it should have been sooner :-).


Well, inlined in the updated patch with your comments/corrections taken into account.

This patch adds YAFFS2 <--> MTD interworking support for the 2.6.17+ kernels.

 fs/yaffs2/yaffs_fs.c     |   99 +++++++++++++++++++++++++++++++++++++++++++----
 fs/yaffs2/yaffs_mtdif.c  |   86 ++++++++++++++++++++++++++++++++++++++++
 fs/yaffs2/yaffs_mtdif2.c |   40 ++++++++++++++++++
 3 files changed, 218 insertions(+), 7 deletions(-)


Signed-off-by: Vitaly Wool <>

Index: linux-2.6.git/fs/yaffs2/yaffs_fs.c
===================================================================
--- linux-2.6.git.orig/fs/yaffs2/yaffs_fs.c
+++ linux-2.6.git/fs/yaffs2/yaffs_fs.c
@@ -103,7 +103,11 @@ static void yaffs_put_super(struct super
 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
                 loff_t * pos);


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_file_flush(struct file *file, fl_owner_t id);
+#else
static int yaffs_file_flush(struct file *file);
+#endif

 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
                  int datasync);
@@ -137,10 +141,17 @@ static int yaffs_rename(struct inode *ol
             struct inode *new_dir, struct dentry *new_dentry);
 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_sync_fs(struct super_block *sb, int wait);
+static void yaffs_write_super(struct super_block *sb);
+#else
static int yaffs_sync_fs(struct super_block *sb);
static int yaffs_write_super(struct super_block *sb);
+#endif

-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
 #else
 static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
@@ -438,7 +449,11 @@ static void yaffs_delete_inode(struct in
     clear_inode(inode);
 }


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
 static int yaffs_file_flush(struct file *file)
+#endif
 {
     yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);


@@ -1223,14 +1238,21 @@ static int yaffs_setattr(struct dentry *
     return error;
 }


-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+    yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+    struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+    yaffs_Device *dev = yaffs_SuperToDevice(sb);
 #else
 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
-#endif
 {
-
     yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#endif
+
     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));


     yaffs_GrossLock(dev);
@@ -1287,16 +1309,25 @@ static int yaffs_do_sync_fs(struct super
 }



+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static void yaffs_write_super(struct super_block *sb)
+#else
static int yaffs_write_super(struct super_block *sb)
+#endif
{

     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
     return 0; /* yaffs_do_sync_fs(sb);*/
-    
+#endif
 }



+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
static int yaffs_sync_fs(struct super_block *sb)
+#endif
{

     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
@@ -1452,7 +1483,11 @@ static struct super_block *yaffs_interna
     T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
     T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
     T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize));
+#else
     T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock));
+#endif
     T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
     T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
     T(YAFFS_TRACE_OS, (" size %d\n", mtd->size));
@@ -1460,14 +1495,22 @@ static struct super_block *yaffs_interna
 #ifdef CONFIG_YAFFS_AUTO_YAFFS2


     if (yaffsVersion == 1 && 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+        mtd->writesize >= 2048) {
+#else
         mtd->oobblock >= 2048) {
+#endif
         T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
         yaffsVersion = 2;
     }    

    
     /* Added NCB 26/5/2006 for completeness */
     if (yaffsVersion == 2 && 
-        mtd->oobblock == 512) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+        mtd->writesize == 512) {
+#else
+        mtd->oobblock >= 512) {
+#endif
         T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
         yaffsVersion = 1;
     }    
@@ -1481,15 +1524,23 @@ static struct super_block *yaffs_interna
             !mtd->block_markbad ||
             !mtd->read ||
             !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+            !mtd->read_oob || !mtd->write_oob) {
+#else
             !mtd->write_ecc ||
             !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
             T(YAFFS_TRACE_ALWAYS,
               ("yaffs: MTD device does not support required "
                "functions\n"));;
             return NULL;
         }


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+        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) {
             T(YAFFS_TRACE_ALWAYS,
               ("yaffs: MTD device does not have the "
@@ -1501,15 +1552,23 @@ static struct super_block *yaffs_interna
         if (!mtd->erase ||
             !mtd->read ||
             !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+            !mtd->read_oob || !mtd->write_oob) {
+#else
             !mtd->write_ecc ||
             !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
             T(YAFFS_TRACE_ALWAYS,
               ("yaffs: MTD device does not support required "
                "functions\n"));;
             return NULL;
         }


-        if (mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+        if (mtd->writesize < YAFFS_BYTES_PER_CHUNK ||
+#else
+        if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK ||
+#endif
             mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
             T(YAFFS_TRACE_ALWAYS,
               ("yaffs: MTD device does not support have the "
@@ -1560,8 +1619,13 @@ static struct super_block *yaffs_interna
         dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
         dev->spareBuffer = YMALLOC(mtd->oobsize);
         dev->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+        dev->nBytesPerChunk = mtd->writesize;
+        dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
         dev->nBytesPerChunk = mtd->oobblock;
         dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
         nBlocks = mtd->size / mtd->erasesize;


         dev->nCheckpointReservedBlocks = 10;
@@ -1641,6 +1705,16 @@ static int yaffs_internal_read_super_mtd
     return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
 }


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs_read_super(struct file_system_type *fs,
+                int flags, const char *dev_name,
+                void *data, struct vfsmount *mnt)
+{
+
+    return get_sb_bdev(fs, flags, dev_name, data,
+               yaffs_internal_read_super_mtd, mnt);
+}
+#else
 static struct super_block *yaffs_read_super(struct file_system_type *fs,
                         int flags, const char *dev_name,
                         void *data)
@@ -1649,6 +1723,7 @@ static struct super_block *yaffs_read_su
     return get_sb_bdev(fs, flags, dev_name, data,
                yaffs_internal_read_super_mtd);
 }
+#endif


 static struct file_system_type yaffs_fs_type = {
     .owner = THIS_MODULE,
@@ -1678,6 +1753,15 @@ static int yaffs2_internal_read_super_mt
     return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
 }


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static int yaffs2_read_super(struct file_system_type *fs,
+            int flags, const char *dev_name, void *data,
+            struct vfsmount *mnt)
+{
+    return get_sb_bdev(fs, flags, dev_name, data,
+            yaffs2_internal_read_super_mtd, mnt);
+}
+#else
 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
                          int flags, const char *dev_name,
                          void *data)
@@ -1686,6 +1770,7 @@ static struct super_block *yaffs2_read_s
     return get_sb_bdev(fs, flags, dev_name, data,
                yaffs2_internal_read_super_mtd);
 }
+#endif


 static struct file_system_type yaffs2_fs_type = {
     .owner = THIS_MODULE,
Index: linux-2.6.git/fs/yaffs2/yaffs_mtdif.c
===================================================================
--- linux-2.6.git.orig/fs/yaffs2/yaffs_mtdif.c
+++ linux-2.6.git/fs/yaffs2/yaffs_mtdif.c
@@ -26,6 +26,7 @@ const char *yaffs_mtdif_c_version =
 #include "linux/time.h"
 #include "linux/mtd/nand.h"


+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
 static struct nand_oobinfo yaffs_oobinfo = {
     .useecc = 1,
     .eccbytes = 6,
@@ -35,16 +36,74 @@ static struct nand_oobinfo yaffs_oobinfo
 static struct nand_oobinfo yaffs_noeccinfo = {
     .useecc = 0,
 };
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
+{
+    oob[0] = spare->tagByte0;
+    oob[1] = spare->tagByte1;
+    oob[2] = spare->tagByte2;
+    oob[3] = spare->tagByte3;
+    oob[4] = spare->tagByte4;
+    oob[5] = spare->tagByte5 & 0x3f;
+    oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
+    oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
+    oob[6] = spare->tagByte6;
+    oob[7] = spare->tagByte7;
+}
+
+static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
+{
+    struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
+    spare->tagByte0 = oob[0];
+    spare->tagByte1 = oob[1];
+    spare->tagByte2 = oob[2];
+    spare->tagByte3 = oob[3];
+    spare->tagByte4 = oob[4];
+    spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
+    spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
+    spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
+    spare->tagByte6 = oob[6];
+    spare->tagByte7 = oob[7];
+
+    nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
+}
+#endif


 int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
                  const __u8 * data, const yaffs_Spare * spare)
 {
     struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    struct mtd_oob_ops ops;
+#endif
     size_t dummy;
     int retval = 0;


     loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    __u8 spareAsBytes[8]; /* OOB */


+    if (data && !spare)
+        retval = mtd->write(mtd, addr, dev->nBytesPerChunk,
+                &dummy, data);
+    else if (spare) {
+        if (dev->useNANDECC) {
+            translate_spare2oob(spare, spareAsBytes);
+            ops.mode = MTD_OOB_AUTO;
+            ops.ooblen = 8; /* temp hack */
+        } else {
+            ops.mode = MTD_OOB_RAW;
+            ops.ooblen = YAFFS_BYTES_PER_SPARE;
+        }
+        ops.len = data ? dev->nBytesPerChunk : ops.ooblen;
+        ops.datbuf = (u8 *)data;
+        ops.ooboffs = 0;
+        ops.oobbuf = spareAsBytes;
+        retval = mtd->write_oob(mtd, addr, &ops);
+    }
+#else
     __u8 *spareAsBytes = (__u8 *) spare;


     if (data && spare) {
@@ -68,6 +127,7 @@ int nandmtd_WriteChunkToNAND(yaffs_Devic
                 mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
                        &dummy, spareAsBytes);
     }
+#endif


     if (retval == 0)
         return YAFFS_OK;
@@ -79,11 +139,36 @@ int nandmtd_ReadChunkFromNAND(yaffs_Devi
                   yaffs_Spare * spare)
 {
     struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    struct mtd_oob_ops ops;
+#endif
     size_t dummy;
     int retval = 0;


     loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    __u8 spareAsBytes[8]; /* OOB */


+    if (data && !spare)
+        retval = mtd->read(mtd, addr, dev->nBytesPerChunk,
+                &dummy, data);
+    else if (spare) {
+        if (dev->useNANDECC) {
+            ops.mode = MTD_OOB_AUTO;
+            ops.ooblen = 8; /* temp hack */
+        } else {
+            ops.mode = MTD_OOB_RAW;
+            ops.ooblen = YAFFS_BYTES_PER_SPARE;
+        }
+        ops.len = data ? dev->nBytesPerChunk : ops.ooblen;
+        ops.datbuf = data;
+        ops.ooboffs = 0;
+        ops.oobbuf = spareAsBytes;
+        retval = mtd->read_oob(mtd, addr, &ops);
+        if (dev->useNANDECC)
+            translate_oob2spare(spare, spareAsBytes);
+    }
+#else
     __u8 *spareAsBytes = (__u8 *) spare;


     if (data && spare) {
@@ -112,6 +197,7 @@ int nandmtd_ReadChunkFromNAND(yaffs_Devi
                 mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
                       &dummy, spareAsBytes);
     }
+#endif


     if (retval == 0)
         return YAFFS_OK;
Index: linux-2.6.git/fs/yaffs2/yaffs_mtdif2.c
===================================================================
--- linux-2.6.git.orig/fs/yaffs2/yaffs_mtdif2.c
+++ linux-2.6.git/fs/yaffs2/yaffs_mtdif2.c
@@ -34,7 +34,11 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
                       const yaffs_ExtendedTags * tags)
 {
     struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    struct mtd_oob_ops ops;
+#else
     size_t dummy;
+#endif
     int retval = 0;


     loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
@@ -46,6 +50,23 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
        ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
         TENDSTR), chunkInNAND, data, tags));


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    if (tags)
+        yaffs_PackTags2(&pt, tags);
+    else
+        BUG(); /* both tags and data should always be present */
+
+    if (data) {
+        ops.mode = MTD_OOB_AUTO;
+        ops.ooblen = sizeof(pt);
+        ops.len = dev->nBytesPerChunk;
+        ops.ooboffs = 0;
+        ops.datbuf = (__u8 *)data;
+        ops.oobbuf = (void *)&pt;
+        retval = mtd->write_oob(mtd, addr, &ops);
+    } else
+        BUG(); /* both tags and data should always be present */
+#else
     if (tags) {
         yaffs_PackTags2(&pt, tags);
     }
@@ -70,6 +91,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
                        (__u8 *) & pt);


     }
+#endif


     if (retval == 0)
         return YAFFS_OK;
@@ -81,6 +103,9 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
                        __u8 * data, yaffs_ExtendedTags * tags)
 {
     struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    struct mtd_oob_ops ops;
+#endif
     size_t dummy;
     int retval = 0;


@@ -93,6 +118,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
        ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
         TENDSTR), chunkInNAND, data, tags));


+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+    if (data && !tags)
+        retval = mtd->read(mtd, addr, dev->nBytesPerChunk,
+                &dummy, data);
+    else if (tags) {
+        ops.mode = MTD_OOB_AUTO;
+        ops.ooblen = sizeof(pt);
+        ops.len = data ? dev->nBytesPerChunk : sizeof(pt);
+        ops.ooboffs = 0;
+        ops.datbuf = data;
+        ops.oobbuf = dev->spareBuffer;
+        retval = mtd->read_oob(mtd, addr, &ops);
+    }
+#else
     if (data && tags) {
         if (dev->useNANDECC) {
             retval =
@@ -115,6 +154,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
                 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
                       dev->spareBuffer);
     }
+#endif


     memcpy(&pt, dev->spareBuffer, sizeof(pt));