Yaffs2文件系统移植艰辛记录
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
// 测试发现此处返回 0
} -------------------------------------------------------
而 yaffs_internal_read_super 函数将作为最终被调用者,打印出挂载是终端上的信息(如下),并
返回超级块 sb。
yaffs: dev is 32505859 name is "mtdblock3" yaffs: passed flags "" yaffs: Attempting MTD mount on 31.3, "mtdblock3" yaffs: auto selecting yaffs1 yaffs_read_super: isCheckpointed 0
fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
exit(1);
} …
由上代码知,问题出在 ioctl。我的天,越揪问题越多!看来要开始充分来认识认识 ioctl 系统调用了。 目前估计内核不支持此处的 MEMGETINFO。MEMGETINFO 在 mtd-util-1.0.0/include/mtd/mtd-abi.h 中定义:
图4 此时,终端无反应了,敲击键盘没有任何作用。核心板上有两个发光管 D1 和 D2(查手册得知为输入/输出指示灯)。 发现挂载前后,D1 指示灯照常闪烁,而 D2 指示灯由快速闪烁变为持续高亮。终端完蛋?系统崩溃?未知! 上 述 “ Hi,Rocky! I’m here(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 格式)。
Yaffs2 文件系统移植艰辛记录
1. 下载 yaffs2 包
2. 将包以补丁形式放入内核中 #tar xvf yaffs2.tar #cd yaffs2 #./patch-ker.sh c /home/arm/dev_home/kernel/gec2410-2.6.8.1
3. 配置内核、并编译 编译出现错误:
这里,可以看出其实 yaffs 注册了两种文件系统,一种是 yaffs,另外一种是 yaffs2。对于 yaffs2_fs_type 结构: static struct file_system_type yaffs2_fs_type = { .owner = THIS_MODULE, .name = "yaffs2", .get_sb = yaffs2_read_super, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, };
/dev/mtd/n
或
/dev/mtdn
à
字符设备
/dev/mtdblock/n 或
/dev/mtdblockn
à
块设备
由此,使用 flash_eraseall 命令如下:
图6 擦除字符设备 3 和 3ro,前者成功,后者失败! 由此,因前面 flash_eraseall 的是一个块设备,故弹出“unable to get MTD device info”信息,故可基本排 除是系统调用的问题。 /dev/mtd 目录下的文件为:
下面来理解 yaffs2_read_super 函数: static struct super_block *yaffs2_read_super(struct file_system_type *fs, int flags, const char *dev_name, void *data) { return get_sb_bdev(fs, flags, dev_name, data, yaffs2_internal_read_super_mtd); }
// 文件系统安装结构
struct file_system_type *fst;
int installed;
};
static struct file_system_to_install fs_to_install[] = { {&yaffs_fs_type, 0}, {&yaffs2_fs_type, 0}, {NULL, 0}
-------------------------------------------------------
前 面 测 试 发 现 yaffs2_internal_read_super_mtd 函 数 返 回 的 是 “ 0 ”; 由 此 ,
yaffs2_internal_read_super_mtd 函数调用应该正确无误!
分析源码“yaffs2/yaffs_fs.c” Yaffs_fs.c 文件中包含两个函数:__init 函数和__exit 函数。和所有普通的内核源码(或者是驱动)一样,它可以以模 块的形式编译。文件系统的注册和销毁就在这两个函数中。
Байду номын сангаас对于文件系统的注册有一个重要的数据结构体:
struct file_system_to_install {
Rocky 于昆山
图1 此时,修改 fs/yaffs2/yaffs_fs.c 中 111 行:
改为:#include <asm/uacesss.h> 重新编译通过!
4. 下载到板子上,运行,结果如下:
图2 上述过程把 yaffs2 的移植和挂载一起进行,为方便调试,找出遇到问题,对上述过程分开进行。 按目前理解,成功移植 yaffs2 文件系统并挂载需有以下两个步骤: A. 下载 yaffs2 包,解压到内核 fs 目录下。修改 fs/Makefile,重新编译内核; B.在根文件系统的启动脚本中添加 mount 命令行,对某分区进行挂载 yaffs2 操作;
};
__init 函数正是注册此结构体中列出的文件系统,对于__init 函数,重要代码如下: static int __init init_yaffs_fs(void) { …… fsinst = fs_to_install; while (fsinst->fst && !error) { error = register_filesystem(fsinst->fst); if (!error) fsinst->installed = 1; fsinst++; } …… }
(★)后期工作: 1. 了解 ioctl 系统调用的相关知识; 2. /dev/mtd 目录下的 3ro 干嘛用的? 权限更大些。
同“3”字符文件是指同一个东西,但对 3ro 操作的话为只读,而对 3 的操作
MTD 设备笔记
一、 Flash 硬件驱动层 NAND 型 Flash 的驱动程序位于/drivers/mtd/nand NOR 型 Flash 的驱动程序位于/drivers/mtd/chips
启动系统后执行如下命令: flash_eraseall /dev/mtdblock/3 结果如下:
// 擦除 3 号分区(用户分区)
图5 无法获取 MTD(内存技术设备)设备信息! 好在有 flash_eraseall 命令代码,进入 mtd-util 目录,查看 flash_eraseall.c 文件:
另外,编译好 mkyaffs 工具,擦除了一遍分区。最终 mount 还是一样的结果,终端崩溃!
内核配置为: File systems --->
Miscellaneous filesystems --->
Memory Technology Devices(MTD) ---> 另外,MTD 的 ECC 校验已关闭!
--------------------------------
yaffs2_internal_read_super_mtd 函数如下: static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, int silent) { return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
#define MEMGETINFO
_IOR('M', 1, struct mtd_info_user)
关于 ioctl 系统调用的相关知识暂且放一放。(★)
但查询资料发现上面编译的 flash_eraseall 命令是可以使用的,需要注意的是:“擦除只能对字符设备,挂载要用块设
备的”。
此处“字符设备”和“块设备”是指 MTD 设备文件的两种类型,对于 nandflash 体现如下:
由此,先完成步骤 A: 根据上述过程 1、2、3 及完成步骤 A,此时,可进入系统查看是否已支持 yaffs2 文件系统, 系统启动后,进入/proc 目录,查看 filesystems 文件,如下:
图3 由此可知,系统已支持 yaffs2 文件系统!故肯定步骤 A 正确无误。 继续完成步骤 B: 对步骤 B 而言,为调试方便,先不将 mount 命令行写进启动脚本。直接在终端进行 mount 操作,将 3 号分区以 yaffs2 文件系统格式挂载到 yaffs2_dir 目录下: cd /tmp mkdir yaffs2_dir mount –t yaffs2 /dev/mtdblock/3 yaffs2_dir 终端显示结果为:
结构中最最重要的就是 get_sb 函数,它完成了整个 yaffs2 文件系统和 linux vfs 挂钩,和 nand 硬件的挂钩,以及 yaffs2 文件系统初始化。因此理解 linux 中的 yaffs2,核心就是理解 yaffs2_read_super 这个函数。
-------------------------------------------------------
图7
其中,3ro 为“只读”,这里“3”、“3ro”两字符文件的关系待查!(★) 如果“3ro”为只读字符设备,则完成“3”字符设备的擦除既可认为对第 3 号分区进行了擦除。 此时,再次使用 mount 命令将第 3 分区挂载到/tmp 目录下,结果依然如图 4 所示。
回到图 4,重新理清思路,发现图 4 的打印信息比网上成功案例多了一句话。 “yaffs_read_super: isCheckpointed 0” 计划由此入手深入代码,一探究竟!
二、 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 加入/删除
… 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) {
} -------------------------------------------------------
而 yaffs_internal_read_super 函数将作为最终被调用者,打印出挂载是终端上的信息(如下),并
返回超级块 sb。
yaffs: dev is 32505859 name is "mtdblock3" yaffs: passed flags "" yaffs: Attempting MTD mount on 31.3, "mtdblock3" yaffs: auto selecting yaffs1 yaffs_read_super: isCheckpointed 0
fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
exit(1);
} …
由上代码知,问题出在 ioctl。我的天,越揪问题越多!看来要开始充分来认识认识 ioctl 系统调用了。 目前估计内核不支持此处的 MEMGETINFO。MEMGETINFO 在 mtd-util-1.0.0/include/mtd/mtd-abi.h 中定义:
图4 此时,终端无反应了,敲击键盘没有任何作用。核心板上有两个发光管 D1 和 D2(查手册得知为输入/输出指示灯)。 发现挂载前后,D1 指示灯照常闪烁,而 D2 指示灯由快速闪烁变为持续高亮。终端完蛋?系统崩溃?未知! 上 述 “ Hi,Rocky! I’m here(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 格式)。
Yaffs2 文件系统移植艰辛记录
1. 下载 yaffs2 包
2. 将包以补丁形式放入内核中 #tar xvf yaffs2.tar #cd yaffs2 #./patch-ker.sh c /home/arm/dev_home/kernel/gec2410-2.6.8.1
3. 配置内核、并编译 编译出现错误:
这里,可以看出其实 yaffs 注册了两种文件系统,一种是 yaffs,另外一种是 yaffs2。对于 yaffs2_fs_type 结构: static struct file_system_type yaffs2_fs_type = { .owner = THIS_MODULE, .name = "yaffs2", .get_sb = yaffs2_read_super, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, };
/dev/mtd/n
或
/dev/mtdn
à
字符设备
/dev/mtdblock/n 或
/dev/mtdblockn
à
块设备
由此,使用 flash_eraseall 命令如下:
图6 擦除字符设备 3 和 3ro,前者成功,后者失败! 由此,因前面 flash_eraseall 的是一个块设备,故弹出“unable to get MTD device info”信息,故可基本排 除是系统调用的问题。 /dev/mtd 目录下的文件为:
下面来理解 yaffs2_read_super 函数: static struct super_block *yaffs2_read_super(struct file_system_type *fs, int flags, const char *dev_name, void *data) { return get_sb_bdev(fs, flags, dev_name, data, yaffs2_internal_read_super_mtd); }
// 文件系统安装结构
struct file_system_type *fst;
int installed;
};
static struct file_system_to_install fs_to_install[] = { {&yaffs_fs_type, 0}, {&yaffs2_fs_type, 0}, {NULL, 0}
-------------------------------------------------------
前 面 测 试 发 现 yaffs2_internal_read_super_mtd 函 数 返 回 的 是 “ 0 ”; 由 此 ,
yaffs2_internal_read_super_mtd 函数调用应该正确无误!
分析源码“yaffs2/yaffs_fs.c” Yaffs_fs.c 文件中包含两个函数:__init 函数和__exit 函数。和所有普通的内核源码(或者是驱动)一样,它可以以模 块的形式编译。文件系统的注册和销毁就在这两个函数中。
Байду номын сангаас对于文件系统的注册有一个重要的数据结构体:
struct file_system_to_install {
Rocky 于昆山
图1 此时,修改 fs/yaffs2/yaffs_fs.c 中 111 行:
改为:#include <asm/uacesss.h> 重新编译通过!
4. 下载到板子上,运行,结果如下:
图2 上述过程把 yaffs2 的移植和挂载一起进行,为方便调试,找出遇到问题,对上述过程分开进行。 按目前理解,成功移植 yaffs2 文件系统并挂载需有以下两个步骤: A. 下载 yaffs2 包,解压到内核 fs 目录下。修改 fs/Makefile,重新编译内核; B.在根文件系统的启动脚本中添加 mount 命令行,对某分区进行挂载 yaffs2 操作;
};
__init 函数正是注册此结构体中列出的文件系统,对于__init 函数,重要代码如下: static int __init init_yaffs_fs(void) { …… fsinst = fs_to_install; while (fsinst->fst && !error) { error = register_filesystem(fsinst->fst); if (!error) fsinst->installed = 1; fsinst++; } …… }
(★)后期工作: 1. 了解 ioctl 系统调用的相关知识; 2. /dev/mtd 目录下的 3ro 干嘛用的? 权限更大些。
同“3”字符文件是指同一个东西,但对 3ro 操作的话为只读,而对 3 的操作
MTD 设备笔记
一、 Flash 硬件驱动层 NAND 型 Flash 的驱动程序位于/drivers/mtd/nand NOR 型 Flash 的驱动程序位于/drivers/mtd/chips
启动系统后执行如下命令: flash_eraseall /dev/mtdblock/3 结果如下:
// 擦除 3 号分区(用户分区)
图5 无法获取 MTD(内存技术设备)设备信息! 好在有 flash_eraseall 命令代码,进入 mtd-util 目录,查看 flash_eraseall.c 文件:
另外,编译好 mkyaffs 工具,擦除了一遍分区。最终 mount 还是一样的结果,终端崩溃!
内核配置为: File systems --->
Miscellaneous filesystems --->
Memory Technology Devices(MTD) ---> 另外,MTD 的 ECC 校验已关闭!
--------------------------------
yaffs2_internal_read_super_mtd 函数如下: static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, int silent) { return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
#define MEMGETINFO
_IOR('M', 1, struct mtd_info_user)
关于 ioctl 系统调用的相关知识暂且放一放。(★)
但查询资料发现上面编译的 flash_eraseall 命令是可以使用的,需要注意的是:“擦除只能对字符设备,挂载要用块设
备的”。
此处“字符设备”和“块设备”是指 MTD 设备文件的两种类型,对于 nandflash 体现如下:
由此,先完成步骤 A: 根据上述过程 1、2、3 及完成步骤 A,此时,可进入系统查看是否已支持 yaffs2 文件系统, 系统启动后,进入/proc 目录,查看 filesystems 文件,如下:
图3 由此可知,系统已支持 yaffs2 文件系统!故肯定步骤 A 正确无误。 继续完成步骤 B: 对步骤 B 而言,为调试方便,先不将 mount 命令行写进启动脚本。直接在终端进行 mount 操作,将 3 号分区以 yaffs2 文件系统格式挂载到 yaffs2_dir 目录下: cd /tmp mkdir yaffs2_dir mount –t yaffs2 /dev/mtdblock/3 yaffs2_dir 终端显示结果为:
结构中最最重要的就是 get_sb 函数,它完成了整个 yaffs2 文件系统和 linux vfs 挂钩,和 nand 硬件的挂钩,以及 yaffs2 文件系统初始化。因此理解 linux 中的 yaffs2,核心就是理解 yaffs2_read_super 这个函数。
-------------------------------------------------------
图7
其中,3ro 为“只读”,这里“3”、“3ro”两字符文件的关系待查!(★) 如果“3ro”为只读字符设备,则完成“3”字符设备的擦除既可认为对第 3 号分区进行了擦除。 此时,再次使用 mount 命令将第 3 分区挂载到/tmp 目录下,结果依然如图 4 所示。
回到图 4,重新理清思路,发现图 4 的打印信息比网上成功案例多了一句话。 “yaffs_read_super: isCheckpointed 0” 计划由此入手深入代码,一探究竟!
二、 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 加入/删除
… 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) {