Hello folks,
okay, here's the patch which should basically work not only in native
YAFFS2 mode but in YAFFS1 compatibility mode as well. Please note that
due to the reasons described in my previous letter, some
implementation steps are hacks rather than solutions, so it's kind of
'proof of concept' in a way.
Well, however it received some limited testing on nandsim w/ 512b page
size configured and looks like it works.
Jonathan, can you please try this version and report the problems, if any?
Best regards,
Vitaly
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 | 52 ++++++++++++++++++++++++
3 files changed, 230 insertions(+), 7 deletions(-)
Signed-off-by: Vitaly Wool <
vitalywool@gmail.com>
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(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->pageStatus == 'Y' ? 0: 0x80;
+ oob[5] |= spare->blockStatus == 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->pageStatus = oob[5] & 0x80 ? 0xff : 'Y';
+ spare->blockStatus = 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)
+ retval = mtd->write(mtd, addr, dev->nBytesPerChunk,
+ &dummy, data);
+
+ if (spare) {
+ if (dev->useNANDECC) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = ops.len = 8; /* temp hack */
+ translate_spare2oob(spare, spareAsBytes);
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = ops.len = YAFFS_BYTES_PER_SPARE;
+ }
+ ops.datbuf = NULL;
+ 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)
+ retval = mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
+ data);
+
+ if (spare) {
+ if (dev->useNANDECC) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = ops.len = 8; /* temp hack */
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = ops.len = YAFFS_BYTES_PER_SPARE;
+ }
+ ops.datbuf = NULL;
+ 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,6 +34,9 @@ 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;
+#endif
size_t dummy;
int retval = 0;
@@ -46,6 +49,30 @@ 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);
+ }
+
+ if (data && !tags)
+ retval = mtd->write(mtd, addr, dev->nBytesPerChunk,
+ &dummy, data);
+ else if (data) {
+ if (dev->useNANDECC) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = sizeof(pt);
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = mtd->oobsize;
+ }
+ ops.len = dev->nBytesPerChunk;
+ ops.ooboffs = 0;
+ ops.datbuf = (__u8 *)data;
+ ops.oobbuf = (void *)&pt;
+ retval = mtd->write_oob(mtd, addr, &ops);
+ } else
+ BUG(); /* shouldn't ever write tags without data */
+#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
@@ -70,6 +97,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
(__u8 *) & pt);
}
+#endif
if (retval == 0)
return YAFFS_OK;
@@ -81,6 +109,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 +124,26 @@ 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) {
+ if (dev->useNANDECC) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = sizeof(pt);
+ ops.len = data ? dev->nBytesPerChunk : sizeof(pt);
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = mtd->oobsize;
+ ops.len = data ? dev->nBytesPerChunk : mtd->oobsize;
+ }
+ 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 +166,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
}
+#endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));