配色: 字号:
Yaffs2文件系统移植艰辛记录
2014-05-27 | 阅:  转:  |  分享 
  
Yaffs2文件系统移植艰辛记录

Rocky于昆山

1.下载yaffs2包



2.将包以补丁形式放入内核中

#tarxvfyaffs2.tar

#cdyaffs2

#./patch-ker.shc/home/arm/dev_home/kernel/gec2410-2.6.8.1



3.配置内核、并编译

编译出现错误:



图1

此时,修改fs/yaffs2/yaffs_fs.c中111行:

改为:#include

重新编译通过!



4.下载到板子上,运行,结果如下:

图2

上述过程把yaffs2的移植和挂载一起进行,为方便调试,找出遇到问题,对上述过程分开进行。

按目前理解,成功移植yaffs2文件系统并挂载需有以下两个步骤:

A.下载yaffs2包,解压到内核fs目录下。修改fs/Makefile,重新编译内核;

B.在根文件系统的启动脚本中添加mount命令行,对某分区进行挂载yaffs2操作;



由此,先完成步骤A:

根据上述过程1、2、3及完成步骤A,此时,可进入系统查看是否已支持yaffs2文件系统,

系统启动后,进入/proc目录,查看filesystems文件,如下:



图3

由此可知,系统已支持yaffs2文件系统!故肯定步骤A正确无误。



继续完成步骤B:

对步骤B而言,为调试方便,先不将mount命令行写进启动脚本。直接在终端进行mount操作,将3号分区以yaffs2

文件系统格式挂载到yaffs2_dir目录下:

cd/tmp

mkdiryaffs2_dir

mount–tyaffs2/dev/mtdblock/3yaffs2_dir

终端显示结果为:



图4

此时,终端无反应了,敲击键盘没有任何作用。核心板上有两个发光管D1和D2(查手册得知为输入/输出指示灯)。

发现挂载前后,D1指示灯照常闪烁,而D2指示灯由快速闪烁变为持续高亮。终端完蛋?系统崩溃?未知!



上述“Hi,Rocky!I’mhere(yaffs2)”为我添加的打印信息。添加地方为“内核->/fs/yaffs2/Yaffs_fs.c->

yaffs_internal_read_super()函数”中,经添加信息发现,此函数能完全执行完,中间过程没有任何return发生。



对此,查阅很多资料仍未果!

查阅资料发现mount之前应先将所要mount的分区擦除一遍。于是费九牛二虎之力找erase分区工具。

找资料,对nandflash擦除需要flash_erase、flash_eraseall工具。由此需交叉编译mtd-util工具。对于包为:mtd-util-1.0.0

对应网络文章《cramfs+yaffs嵌入式平台的实现》中关于mtd-util的编译,成功获取flash_erase、flash_eraseall工具。

拷贝到根文件系统的bin目录下,chmod成777,然后采用u-boot重新烧写根文件系统(cramfs格式)。

启动系统后执行如下命令:

flash_eraseall/dev/mtdblock/3//擦除3号分区(用户分区)

结果如下:



图5

无法获取MTD(内存技术设备)设备信息!

好在有flash_eraseall命令代码,进入mtd-util目录,查看flash_eraseall.c文件:



if((fd=open(mtd_device,O_RDWR))<0){

fprintf(stderr,"%s:%s:%s\n",exe_name,mtd_device,strerror(errno));

exit(1);

}



if(ioctl(fd,MEMGETINFO,&meminfo)!=0){

fprintf(stderr,"%s:%s:unabletogetMTDdeviceinfo\n",exe_name,mtd_device);

exit(1);

}



由上代码知,问题出在ioctl。我的天,越揪问题越多!看来要开始充分来认识认识ioctl系统调用了。

目前估计内核不支持此处的MEMGETINFO。MEMGETINFO在mtd-util-1.0.0/include/mtd/mtd-abi.h中定义:

#defineMEMGETINFO_IOR(''M'',1,structmtd_info_user)



关于ioctl系统调用的相关知识暂且放一放。(★)

但查询资料发现上面编译的flash_eraseall命令是可以使用的,需要注意的是:“擦除只能对字符设备,挂载要用块设

备的”。

此处“字符设备”和“块设备”是指MTD设备文件的两种类型,对于nandflash体现如下:

/dev/mtd/n或/dev/mtdn字符设备

/dev/mtdblock/n或/dev/mtdblockn块设备

由此,使用flash_eraseall命令如下:



图6

擦除字符设备3和3ro,前者成功,后者失败!

由此,因前面flash_eraseall的是一个块设备,故弹出“unabletogetMTDdeviceinfo”信息,故可基本排

除是系统调用的问题。

/dev/mtd目录下的文件为:



图7

其中,3ro为“只读”,这里“3”、“3ro”两字符文件的关系待查!(★)

如果“3ro”为只读字符设备,则完成“3”字符设备的擦除既可认为对第3号分区进行了擦除。

此时,再次使用mount命令将第3分区挂载到/tmp目录下,结果依然如图4所示。





回到图4,重新理清思路,发现图4的打印信息比网上成功案例多了一句话。

“yaffs_read_super:isCheckpointed0”

计划由此入手深入代码,一探究竟!



分析源码“yaffs2/yaffs_fs.c”

Yaffs_fs.c文件中包含两个函数:__init函数和__exit函数。和所有普通的内核源码(或者是驱动)一样,它可以以模

块的形式编译。文件系统的注册和销毁就在这两个函数中。

对于文件系统的注册有一个重要的数据结构体:

structfile_system_to_install{//文件系统安装结构

structfile_system_typefst;

intinstalled;

};



staticstructfile_system_to_installfs_to_install[]={

{&yaffs_fs_type,0},

{&yaffs2_fs_type,0},

{NULL,0}

};



__init函数正是注册此结构体中列出的文件系统,对于__init函数,重要代码如下:

staticint__initinit_yaffs_fs(void)

{

……

fsinst=fs_to_install;

while(fsinst->fst&&!error){

error=register_filesystem(fsinst->fst);

if(!error)

fsinst->installed=1;

fsinst++;

}

……

}

这里,可以看出其实yaffs注册了两种文件系统,一种是yaffs,另外一种是yaffs2。对于yaffs2_fs_type结构:

staticstructfile_system_typeyaffs2_fs_type={

.owner=THIS_MODULE,

.name="yaffs2",

.get_sb=yaffs2_read_super,

.kill_sb=kill_block_super,

.fs_flags=FS_REQUIRES_DEV,

};

结构中最最重要的就是get_sb函数,它完成了整个yaffs2文件系统和linuxvfs挂钩,和nand硬件的挂钩,以及yaffs2

文件系统初始化。因此理解linux中的yaffs2,核心就是理解yaffs2_read_super这个函数。



-------------------------------------------------------

下面来理解yaffs2_read_super函数:

staticstructsuper_blockyaffs2_read_super(structfile_system_typefs,intflags,

constchardev_name,voiddata)

{

returnget_sb_bdev(fs,flags,dev_name,data,yaffs2_internal_read_super_mtd);

}

--------------------------------

yaffs2_internal_read_super_mtd函数如下:

staticintyaffs2_internal_read_super_mtd(structsuper_blocksb,voiddata,intsilent)

{

returnyaffs_internal_read_super(2,sb,data,silent)?0:-EINVAL;

//测试发现此处返回0

}

-------------------------------------------------------

而yaffs_internal_read_super函数将作为最终被调用者,打印出挂载是终端上的信息(如下),并

返回超级块sb。

yaffs:devis32505859nameis"mtdblock3"

yaffs:passedflags""

yaffs:AttemptingMTDmounton31.3,"mtdblock3"

yaffs:autoselectingyaffs1

yaffs_read_super:isCheckpointed0

-------------------------------------------------------

前面测试发现yaffs2_internal_read_super_mtd函数返回的是“0”;由此,

yaffs2_internal_read_super_mtd函数调用应该正确无误!





另外,编译好mkyaffs工具,擦除了一遍分区。最终mount还是一样的结果,终端崩溃!

内核配置为:

Filesystems--->Miscellaneousfilesystems--->





MemoryTechnologyDevices(MTD)--->



另外,MTD的ECC校验已关闭!

(★)后期工作:

1.了解ioctl系统调用的相关知识;

2./dev/mtd目录下的3ro干嘛用的?同“3”字符文件是指同一个东西,但对3ro操作的话为只读,而对3的操作

权限更大些。





MTD设备笔记

一、Flash硬件驱动层

NAND型Flash的驱动程序位于/drivers/mtd/nand

NOR型Flash的驱动程序位于/drivers/mtd/chips



二、MTD原始设备

mtd_table:所有MTD原始设备的列表(每一个分区为一个MTD原始设备);

mtd_part:表示MTD原始设备分区的结构(包括mtd_info);

mtd_info:描述MTD原始设备的数据结构(包括MTD的数据和操作函数);

add_mtd_device()、del_mtd_device()建立/删除mtd_info结构并将其加入/删除mtd_table

(或者调用add_mtd_partition()、del_mtd_partition()(mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除

mtd_table中)



structmtd_infomtd_table[MAX_MTD_DEVICES];



/Ourpartitionnodestructure/

structmtd_part{

structmtd_infomtd;

structmtd_infomaster;

u_int32_toffset;

intindex;

structlist_headlist;

intregistered;

};



structmtd_info{

u_chartype;

u_int32_tflags;

u_int32_tsize;//TotalsizeoftheMTD

……

int(erase)(structmtd_infomtd,structerase_infoinstr);

int(read)(structmtd_infomtd,loff_tfrom,size_tlen,size_tretlen,u_charbuf);

int(write)(structmtd_infomtd,loff_tto,size_tlen,size_tretlen,constu_charbuf);

……

};



三、MTD设备层

MTD的块设备(主设备号31)和字符设备(设备号90)

mtdblk_dev:一个描述MTD块设备的结构

mtdblks:一个MTD块设备指针数组(数组中的每一个mtdblk_dev和mtd_table中的每一个mtd_info一一对应);

staticstructmtdblk_dev{

structmtd_infomtd;

intcount;

structsemaphorecache_sem;

unsignedcharcache_data;

unsignedlongcache_offset;

unsignedintcache_size;

enum{STATE_EMPTY,STATE_CLEAN,STATE_DIRTY}cache_state;

}mtdblks[MAX_MTD_DEVICES];







献花(0)
+1
(本文系海漩涡首藏)