基于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目录, 其余空空如也. 看样子只好分析yaffs和nand flash代码了.
mx27的使用的是8bit 512bytes+16bytes oob/page 的128M nand flash, 分析yaffs与nand 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. 其中ecc1与ecc2是用来计算ECC的, 只有使用yaffs自身的ECC时才用到, 我们这里使用mtd的硬件ECC, 可以忽略不计, 省下了YAFFS用来存放文件系统相关的信息(yaffs_Tags)8个bytes. 而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_spare2oob将yaffs_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) {
//转换tag为8bytes数据块
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_ops或nand_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_PLACE与MTD_OOB_RAW为一种, 直接将OOB数据复制到要写入oob的数据缓存chip->oob_poi; MTD_OOB_AUTO讲oob数据复制到要写入oob的数据缓存oobfree位置上. 这就是MTD_OOB_RAW与MTD_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_spare2oob将8bytes的yaffs_tags转为8bytes数据块,然后通过write_oob将这8bytes写入到OOB的oobfree块区; 读出来的时候反过来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
}
基于mx27ads 的yaffs 文件系统释疑相关推荐
- 嵌入式基于Flash上的文件系统
在嵌入式领域,FLASH是一种常用的存储介质,由于其特殊的硬件结构,所以普通的文件系统如ext2,ext3等都不适合在其上使用,于是就出现了专门针对FLASH的文件系统,比较常用的有jffs2,yaf ...
- 在内核中增加对yaffs文件系统的支持
1.解压下载的内核源代码linux-2.6.30.4.tar.bz2.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-co ...
- 【移植Linux 3.4.2内核之四】修改内核代码支持YAFFS文件系统
上一篇文章,我们从0制作jffs2文件系统,因为我们的内核本身就支持iffs2文件系统,但是它不支持yaffs文件系统.今天我们就来修改内核代码,让内核支持yaffs文件系统的格式. 1.首先我们获取 ...
- 移植U-BOOT之支持烧写YAFFS文件系统以及制作U-BOOT补丁
今天,我们来移植U-BOOT让其支持YAFFS文件系统映像的烧写,以及最后的终极目标,制作Uboot补丁,因为我们信心苦苦移植好了Uboot,如果换一个地方的或者换一台电脑之类的,我们也不想再浪费时间 ...
- 内核移植(4)移植yaffs文件系统
yaffs这种文件系统专门为NAND Flash设计的嵌入式文件系统, 虽减少了一些功能,但比JFFS速度更快,占用内存更少. 一般而言,在Nor Flash上使用JFFS2文件系统,在NAND Fl ...
- u-boot-2012.04.01移植到TQ2440(八):支持烧写yaffs文件系统
一.支持yaffs烧写文件系统 先直接烧写试一下 TQ2440 # nand write.yaffs32000000 rootfs $filesize NAND write: device 0 off ...
- 基于nand flash的文件系统的整理
一. Nandflash简介 基本概念:flash芯片.block.page.附加页 1.1结构 Flash芯片的擦除以块为单位,写以页为单位.在每个flash芯片中包括非常多的 ...
- 基于ubuntu-base构建根文件系统并移植到RK3568开发板
目录 前言 一.根文件系统是什么? 二.构建根文件系统的方法 1.debootstrap 2.builroot 3.busybox 4.ubuntu-base 三.进入主题--如何使用ubuntu-b ...
- 基于Linux的嵌入式文件系统构建与设计
摘 要: Linux是当今一种十分流行的嵌入式操作系统.由于其具有执行效率高.占用空间小.实时性能优良和可扩展性强等特点,因此被广泛应用于工业控制领域.该文对其文件系统进行了简单的介绍,结合嵌入式系统 ...
- 基于IndexedDB实现简单文件系统
现在的indexedDB已经有几个成熟的库了,比如西面这几个,任何一个都是非常出色的. 用别人的东西好处是上手快,看文档就好,要是文档不太好,那就有点尴尬了. dexie.js :A Minimali ...
最新文章
- H3C 交换机升级说明
- VSTO为Excel快捷菜单添加项
- pu learning的建模实践,半监督学习的好方法!
- 隐马尔科夫模型 概念(上)
- Python-内建函数
- 一个MVP+RxJava+Retrofit的干货集中营
- linux 用户、群组及权限操作
- python设计模式2-工厂方法模式
- Office 2007无法卸载也无法安装的解决
- 空号检测、号码状态查询接口免费测试、精准实时版(支持携号转网查询)
- 图像处理经典算法及OpenCV程序
- 在Ubuntu Linux Server上使用奔图P2206NW打印机
- Scala 函数式编程(一) 什么是函数式编程?
- 工业控制网络通信协议概览 2020年7月27日
- 百度地图开发技术方案及解决办法
- Vista桌面图标无法拖动
- 【JavaWeb】一文学会JPA
- Fadeln()方法
- el-table自定义排序
- 电脑为什么刚开机时网速挺快,可过一段时间后就很慢了?重启电脑就解决了问题。
热门文章
- mysql中加号变成空格了_从数据库中读取字符串时其中的空格变成加号
- android使用Charles抓包https请求
- CF984A Game
- Luogu4366[CodePlus#4] 最短路
- 1005	地球人口承载力估计
- 黑马品优购项目的总结-首页
- /dev/null空字符设备文件
- vue调用日期_Vue 前端开发——打印功能实现
- 城市轨道交通运营管理属于什么院系_青西新区高职校城市轨道交通运营与管理专业礼仪教学成果考核圆满结束...
- java 怎么调用clojure_从java调用Clojure时Clojure状态的范围