您的位置:首页 > 运维架构 > Linux

yaffs2应用到较老版本linux上时的问题 (移植日记)

2009-07-21 17:26 841 查看
2009.7.21

yaffs2 在 2.6.22的 kernel 上表现很正常,但在老的 2.6.12 上,则出现问题。

无奈之下只好阅读 yaffs2 的代码

fs/yaffs2/yaffs_mtdif2.c 中的 nandmtd2_ReadChunkWithTagsFromNAND 函数从nand flash 中

读取 oob 信息, 获取 yaffs_ExtendedTags tags,

if (tags){

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

yaffs_UnpackTags2(tags, &pt);

if(pt.t.chunkId != -1)

{

printk("yaffs_UnpackTags2 chunkId = %x addr = %x/n", pt.t.chunkId, addr);

int i = 0;

for(; i<28; i++)

{

printk(" %02x " , dev->spareBuffer[i]);

}

printk("/n");

}

}

通过和 2.6.22 的kernel 对比,发现数据偏移了两位, 我就太阳。。

后来找到下面这篇文章:

新版本内核中的MTD驱动考虑到了与yaffs2的接口问题,与yaffs2的整合一般都很顺利。但是老版本就容易出现写进去的文件umount/mount后丢失的问题。基本上应该属于oob中数据布局的问题。MTD中的oob(2k-page)布局:

====================

字节0: 坏块标记

字节1: 保留

2-0x27: 给上层使用(yaffs)

0x28-0x3F: ECC

====================

YAFFS中与MTD最纠缠不清的就是oob中的数据存储。yaffs需要将tag存入MTD的oob区域,写入时通过write_ecc, 读取时会用到read_ecc和read_oob,后者在扫描文件系统的时候会用到,问题出在这里:

1. NAND驱动中read_ecc和write_ecc都会小心得将yaffs2传递过来的oob数据写到2-0x27的位置,

2. read_oob时,则是将整个oob从0开始都读取出来了。导致yaffs2取到的tag数据错误,这是造成文件丢失或者mout失败的罪魁祸首。

解决的方法很简单(只针对pagesize=2K的nand,其他的要参考driver/mtd/nand/nand_base.c中的nand_oobinfo,修改yaffs_mtdif2.c中的ReadChunkWithTagsFromNand,

1. 添加一个变量oobOffset,默认值为0, 当版本<=2.6.17并且调用read_oob时,oobOffset = 2.

2. 最后copy数据到tag结构体时,加上oobOffset即可。

参考文档:
http://www.linux-mtd.infradead.org/tech/mtdnand/x255.html http://www.yaffs.net/yaffs-2-specification-and-development-notes
读的问题解决了,能正确读到数据了,但写数据的时候还是不正常。。

写入数据以后, 会导致文件丢失, 并产生:Partially written block 15 chunk 973 detected 警告。

其实根本原因还是写入的时候,写oob 信息有问题。明天继续查吧。

2009.7.22

问题终于解决了,现在我的 2.6.12 也能顺畅的使用 yaffs2 了。

问题的根源还是在读flash的 oob的时候出问题了,

2.6.12 的kernel 中 mtd->read_ecc 函数既读取 data 也读取 tags 但是读tags 的时候ecc错误,或者说这个函数在处理 512byte/page 的 nand flash 时工作正常,

但是在读 2k/page 的 flash 时,工作就不正常了。再看mtd->read 只读数据,工作OK, mtd->read_oob 只读oob 或者说只读 tags ,也正常,但是在memcpy数据的时候

需要加 2 的偏移就正常了。问题找到了,不使用 mtd->read_ecc 函数 就什么问题都没有了,如果既需要读数据,又需要读oob, 那么就分别调用 另外两个函数。代码:

int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,

__u8 * data, yaffs_ExtendedTags * tags)

{

struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);

#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))

struct mtd_oob_ops ops;

#endif

size_t dummy;

int retval = 0;

int localData = 0;

int tag_off = 0;

int tag_mod = 0;

loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;

yaffs_PackedTags2 pt;

memset((char*)&pt, 0, sizeof(pt) );

T(YAFFS_TRACE_MTD,

(TSTR

("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"

TENDSTR), chunkInNAND, data, tags));



if(dev->inbandTags){



if(!data) {

localData = 1;

data = yaffs_GetTempBuffer(dev,__LINE__);

}



}

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))

if (dev->inbandTags || (data && !tags))

retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,

&dummy, data);

else if (tags) {

ops.mode = MTD_OOB_AUTO;

ops.ooblen = sizeof(pt);

ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);

ops.ooboffs = 0;

ops.datbuf = data;

ops.oobbuf = dev->spareBuffer;

retval = mtd->read_oob(mtd, addr, &ops);

}

#else

tag_off = 2;

#if 0

if (!dev->inbandTags && data && tags) {

retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,

&dummy, data, dev->spareBuffer,

NULL);

tag_mod = 1;

}

else

{

#endif

if (data)

retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,

data);

if (!dev->inbandTags && tags)

{

retval =

mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,

dev->spareBuffer);

tag_mod = 2;

}



#endif

if (!dev->inbandTags && data && tags)

{

tag_mod = 1;

}

if(dev->inbandTags){

if(tags){

yaffs_PackedTags2TagsPart * pt2tp;

pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk+tag_off];

yaffs_UnpackTags2TagsPart(tags,pt2tp);

}

}

else {

if (tags){

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

yaffs_UnpackTags2(tags, &pt);

}

}

if(localData)

yaffs_ReleaseTempBuffer(dev,data,__LINE__);



if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)

{

tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;

}



if (retval == 0)

return YAFFS_OK;

else

return YAFFS_FAIL;

}

参考文档:

如何编写linux下nand flash驱动
http://blog.ednchina.com/edaworld/140765/Message.aspx
Yaffs文件系统结构
http://www.360doc.com/content/070110/14/198_325124.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐