基于mx27ads 的yaffs 文件系统释疑

 

Mx27ads bsp内核采用2.6.19, 选择文件系统中的yaffs2

File systems  ---> Miscellaneous filesystems  ---> <*> YAFFS2 file system support

 

创建测试的yaffs image

mkdir userfs

echo test > userfs/test

mkyaffsimage userfs userfs.yaffs

写入nand flash

nandwrite –a –o /dev/mtd/8 userfs.yaffs

挂载yaffs mtd

mount –t yaffs /dev/mtdblock/8 /mnt/rwfs

发现mount报错,  只有一个lost+found目录, 其余空空如也. 看样子只好分析yaffsnand flash代码了.

 

mx27的使用的是8bit 512bytes+16bytes oob/page 128M nand flash, 分析yaffsnand flash驱动代码, 发现yaffs中调用yaffs_mtdif.c中的nandmtd_WriteChunkToNAND函数将它的chunk写入FLASH,包含一个512字节的数据与yaffs_Spare结构, 512字节数据对应nand flash page, 所以不需要关心他的512字节数据区; yaffs_Spare结构,在yaffs_guts.h中定义的

typedef struct {
 __u8 tagByte0;
 __u8 tagByte1;
 __u8 tagByte2;
 __u8 tagByte3;
 __u8 pageStatus; /* set to 0 to delete the chunk */
 __u8 blockStatus;
 __u8 tagByte4;
 __u8 tagByte5;
 __u8 ecc1[3];
 __u8 tagByte6;
 __u8 tagByte7;
 __u8 ecc2[3];
} yaffs_Spare;

正好是16字节, 那就是使用这16字节作为OOB. 其中ecc1ecc2是用来计算ECC, 只有使用yaffs自身的ECC时才用到, 我们这里使用mtd的硬件ECC, 可以忽略不计, 省下了YAFFS用来存放文件系统相关的信息(yaffs_Tags8bytes. mx27 nand flash oob定义如下:

static struct nand_ecclayout nand_hw_eccoob_8 = {

    .eccbytes = 5,

    .eccpos = {6, 7, 8, 9, 10},

    .oobfree = {{0, 5}, {11, 5}}

};

Oobfree有两块, {0,5}, {11,5}总共10个字节. 需要将这8个字节保存到OOB区中, 就需要一个转换.  继续分析yaffs_mtdif.c,发现2.6.19内核在yaffs写入oob时先使用translate_spare2oobyaffs_Spare转换为一个8bytes数据块,然后通过mtd->write_oob使用MTD_OOB_AUTO方式写入oob数据;

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

    __u8 spareAsBytes[8]; /* OOB */

 

//只有数据

    if (data && !spare)

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

                &dummy, data);

else if (spare) {

     //使用nand 硬件ECC

        if (dev->useNANDECC) {

            //转换tag8bytes数据块

translate_spare2oob(spare, spareAsBytes);

//使用MTD_OOB_AUTO方式将8bytes块写入到oobfree

            ops.mode = MTD_OOB_AUTO;

            ops.ooblen = 8; /* temp hack */

        } else {

                 //使用yaffs自身ECC, 直接将yaffs_Spare数据作为OOB

            ops.mode = MTD_OOB_RAW;

            ops.ooblen = YAFFS_BYTES_PER_SPARE;

        }

        ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;

        ops.datbuf = (u8 *)data;

        ops.ooboffs = 0;

        ops.oobbuf = spareAsBytes;

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

}

#endif

继续深入分析,  发现mtd-write_oob实际上是调用的是nand_do_write_opsnand_do_write_oob(都在driver/mtd/nand/nand_base.c), 在这两个函数中在处理oob数据时都调用了同一个函数nand_fill_oob:

static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,

                  struct mtd_oob_ops *ops)

{

    size_t len = ops->ooblen;

 

    switch(ops->mode) {

 

    case MTD_OOB_PLACE:

    case MTD_OOB_RAW:

        memcpy(chip->oob_poi + ops->ooboffs, oob, len);

        return oob + len;

 

    case MTD_OOB_AUTO: {

        struct nand_oobfree *free = chip->ecc.layout->oobfree;

        uint32_t boffs = 0, woffs = ops->ooboffs;

        size_t bytes = 0;

 

        for(; free->length && len; free++, len -= bytes) {

            /* Write request not from offset 0 ? */

            if (unlikely(woffs)) {

                if (woffs >= free->length) {

                    woffs -= free->length;

                    continue;

                }

                boffs = free->offset + woffs;

                bytes = min_t(size_t, len,

                          (free->length - woffs));

                woffs = 0;

            } else {

                bytes = min_t(size_t, len, free->length);

                boffs = free->offset;

            }

            memcpy(chip->oob_poi + boffs, oob, bytes);

            oob += bytes;

        }

        return oob;

    }

    default:

        BUG();

    }

    return NULL;

}

可以看出nand_fill­_oob使用了2种方式来组织oob的处理方式: MTD_OOB_PLACEMTD_OOB_RAW为一种, 直接将OOB数据复制到要写入oob的数据缓存chip->oob_poi; MTD_OOB_AUTOoob数据复制到要写入oob的数据缓存oobfree位置上. 这就是MTD_OOB_RAWMTD_OOB_AUTO的最终解释了.

 

再来看mkyaffsimage的代码:

static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)

{

    yaffs_Tags t;

    yaffs_Spare s;

   

    error = write(outFile,data,512);

    if(error < 0) return error;

 

    memset(&t,0xff,sizeof (yaffs_Tags));

    memset(&s,0xff,sizeof (yaffs_Spare));

 

    t.chunkId = chunkId;

    t.serialNumber = 0;

    t.byteCount = nBytes;

    t.objectId = objId;

 

    if (convert_endian)

    {

        little_to_big_endian(&t);

    }

 

   yaffs_CalcTagsECC(&t);

    yaffs_LoadTagsIntoSpare(&s,&t);

    yaffs_CalcECC(data,&s);

 

    nPages++;

    return write(outFile,&s,sizeof(yaffs_Spare));

}

他在512字节之后是包含了16字节yaffs_Spare的,这个16字节的yaffs_Spare就是他的oob结构. 但是这个16字节并没有通过translate_spare2oob转换, 而是直接写入image中了.

再看通过nandwrite -a -o 写入mtd时的代码

if (!noecc) {

                int i, start, len;

                /*

                 *  We use autoplacement and have the oobinfo with the autoplacement

                 * information from the kernel available

                 *

                 * Modified to support out of order oobfree segments,

                 * such as the layout used by diskonchip.c

                 */

                if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {

                    for (i = 0;old_oobinfo.oobfree[i][1]; i++) {

                        /* Set the reserved bytes to 0xff */

                        start = old_oobinfo.oobfree[i][0];

                        len = old_oobinfo.oobfree[i][1];

                        printf( "oob:[%d:%d]/n", start, len );

                        memcpy(oobbuf + start,

                            oobreadbuf + start,

                            len);

                    }

                } else {

                    /* jffs2 or yaffs */

                    /* Set at least the ecc byte positions to 0xff */

                    start = old_oobinfo.eccbytes;

                    len = meminfo.oobsize - start;

 

                    memcpy(oobbuf + start,

                        oobreadbuf + start,

                        len);

                }

            }

可见nandwrite在写入oob时是也是通过MTD_NANDECC_AUTOPLACE(等同MTD_OOB_AUTO)方式写入的.

 

比较一下yaffs流程与mkyaffsimage流程:

yaffs流程是通过translate_spare2oob8bytesyaffs_tags转为8bytes数据块,然后通过write_oob将这8bytes写入到OOBoobfree块区; 读出来的时候反过来translate_oob2spare, 就可以还原成yaffs_tags; mkyaffsimage创建yaffs image时却是直接将yaffs_Spare写入文件, 通过nandwrite -a -o 写入mtd, 直接使用这块yaffs_Spare作为oob数据写入, 虽然使用方式也是MTD_OOB_AUTO; 这就造成yaffs读取chunk时无法读取正确的yaffs_Spare数据了;

 

由此可见只要在mkyaffsimage写入yaffs_Spare, 只要将写入的数据转换为yaffs中写入flash之前一致的数据即可.

 

以下是修改过的 write_chunk

static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)

{

    yaffs_Tags t;

    yaffs_Spare s;

    __u8 oobdata[16];

 

    error = write(outFile,data,512);

    if(error < 0) return error;

 

    memset(&t,0xff,sizeof (yaffs_Tags));

    memset(&s,0xff,sizeof (yaffs_Spare));

 

    t.chunkId = chunkId;

    t.serialNumber = 0;

    t.byteCount = nBytes;

    t.objectId = objId;

 

    if (convert_endian)

    {

        little_to_big_endian(&t);

    }

 

    yaffs_CalcTagsECC(&t);

    yaffs_LoadTagsIntoSpare(&s,&t);

    yaffs_CalcECC(data,&s);

 

    nPages++;

#if 0

    return write(outFile,&s,sizeof(yaffs_Spare));

#else

    memset(oobdata,0xff,16);

translate_spare2oob( &s, oobdata )

//因为采用的是硬件ECC, 这里忽略了yaffs自身的ECC

return write(outFile, oobdata, 16);

#endif

}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值