Hello folks,
currently yaffs2 can not be used on some 2k page NAND flashes where the controller reserves
a lot of OOB space for ECC, due to PackedTags not fitting into one page's free OOB space,
and on OneNAND, for roughly the same reason.
OTOH, on these types of flashes/controllers the ECC capabilities are strong enough to just
not calculate/save ECC by filesystem (e. g. yaffs). So, the patch inlined below just
suppresses ECCOther reading/writing/calculation in case we anyway don't have space to write
it.
fs/yaffs2/yaffs_mtdif2.c | 30 +++++++++++++++++++-----------
fs/yaffs2/yaffs_packedtags2.c | 22 ++++++++++++----------
fs/yaffs2/yaffs_packedtags2.h | 4 ++--
3 files changed, 33 insertions(+), 23 deletions(-)
Signed-off-by: Vitaly Wool <
vitalywool@gmail.com>
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
index 5a18725..12b5ce3 100644
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -38,10 +38,14 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
size_t dummy;
#endif
int retval = 0;
+ /* low on OOB space? write only tags then */
+ int do_ecc = mtd->oobavail < sizeof(yaffs_PackedTags2) ? 0 : 1;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
+ void *oob = do_ecc ? (void *)&pt : (void *)&pt.t;
+ int ooblen = do_ecc ? sizeof(yaffs_PackedTags2) : sizeof(yaffs_PackedTags2TagsPart);
T(YAFFS_TRACE_MTD,
(TSTR
@@ -50,34 +54,34 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (tags)
- yaffs_PackTags2(&pt, tags);
+ yaffs_PackTags2(&pt, tags, do_ecc);
else
BUG(); /* both tags and data should always be present */
if (data) {
ops.mode = MTD_OOB_AUTO;
- ops.ooblen = sizeof(pt);
+ ops.ooblen = ooblen;
ops.len = dev->nDataBytesPerChunk;
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
- ops.oobbuf = (void *)&pt;
+ ops.oobbuf = oob;
retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
- yaffs_PackTags2(&pt, tags);
+ yaffs_PackTags2(&pt, tags, do_ecc);
}
if (data && tags) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
- &dummy, data, (__u8 *) & pt, NULL);
+ &dummy, data, oob, NULL);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
- &dummy, data, (__u8 *) & pt, NULL);
+ &dummy, data, oob, NULL);
} else {
if (data)
retval =
@@ -86,7 +90,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
- (__u8 *) & pt);
+ oob);
}
#endif
@@ -106,10 +110,14 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
#endif
size_t dummy;
int retval = 0;
+ /* low on OOB space? write only tags then */
+ int do_ecc = mtd->oobavail < sizeof(yaffs_PackedTags2) ? 0 : 1;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
+ void *oob = do_ecc ? (void *)&pt : (void *)&pt.t;
+ int ooblen = do_ecc ? sizeof(yaffs_PackedTags2) : sizeof(yaffs_PackedTags2TagsPart);
T(YAFFS_TRACE_MTD,
(TSTR
@@ -122,8 +130,8 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
- ops.ooblen = sizeof(pt);
- ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
+ ops.ooblen = ooblen;
+ ops.len = data ? dev->nDataBytesPerChunk : ooblen;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
@@ -154,10 +162,10 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
}
#endif
- memcpy(&pt, dev->spareBuffer, sizeof(pt));
+ memcpy(oob, dev->spareBuffer, ooblen);
if (tags)
- yaffs_UnpackTags2(tags, &pt);
+ yaffs_UnpackTags2(tags, &pt, do_ecc);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
index 6860876..55e5149 100644
--- a/fs/yaffs2/yaffs_packedtags2.c
+++ b/fs/yaffs2/yaffs_packedtags2.c
@@ -57,7 +57,8 @@ static void yaffs_DumpTags2(const yaffs_
}
-void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t,
+ int do_ecc)
{
pt->t.chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber;
@@ -93,7 +94,7 @@ void yaffs_PackTags2(yaffs_PackedTags2 *
yaffs_DumpTags2(t);
#ifndef YAFFS_IGNORE_TAGS_ECC
- {
+ if (do_ecc) {
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
@@ -101,7 +102,8 @@ void yaffs_PackTags2(yaffs_PackedTags2 *
#endif
}
-void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
+void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt,
+ int do_ecc)
{
memset(t, 0, sizeof(yaffs_ExtendedTags));
@@ -110,12 +112,8 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */
-#ifdef YAFFS_IGNORE_TAGS_ECC
- {
- t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
- }
-#else
- {
+#ifndef YAFFS_IGNORE_TAGS_ECC
+ if (do_ecc) {
yaffs_ECCOther ecc;
int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
@@ -140,8 +138,12 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
default:
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
}
- }
+ } else
#endif
+ {
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ }
+
t->blockBad = 0;
t->chunkUsed = 1;
t->objectId = pt->t.objectId;
diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
index 7c4a72c..b2e8d6b 100644
--- a/fs/yaffs2/yaffs_packedtags2.h
+++ b/fs/yaffs2/yaffs_packedtags2.h
@@ -33,6 +33,6 @@ typedef struct {
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
-void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
-void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t, int);
+void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt, int);
#endif