原文地址:http://my.oschina.net/shelllife/blog/123482
今天做升级方案用到了mtd-utils中的flash_eraseall和flash_cp两个工具,在进行方案验证的时候,遭遇到各种不解和疑惑,因对MTD的原理不熟悉,所以只能多次尝试,虽然最后把方案搞定了,不过觉得MTD中的mtd和mtdblock区别这块还是值得总结学习一下。这里先说明一下问题现象,然后在进行具体的区别原理解释。
/ $ flash_eraseall /dev/mtdblock/2
flash_eraseall: /dev/mtdblock/2: unable to get MTD device info
/ $ flash_eraseall /dev/mtdblock/2
flash_eraseall: /dev/mtdblock/2: unable to get MTD device info
/ $ flash_eraseall /dev/mtd/2
Erasing 128 Kibyte @ 8e0000 -- 98 % complete.
/ $ ls
/ $ flashcp rootfs_version /dev/mtdblock2
This doesn't seem to be a valid MTD flash device!
/ $ flashcp rootfs_version /dev/mtdblock/2
This doesn't seem to be a valid MTD flash device!
/ $ flashcp rootfs_version /dev/mtd2
/ $ ls
/ $ mount -t jffs2 /dev/mtd/2 qqzm/ mount: Mounting /dev/mtd/2 on qqzm/ failed: Invalid argument / $ mount -t jffs2 /dev/mtd2 qqzm/ mount: Mounting /dev/mtd2 on qqzm/ failed: Invalid argument / $ mount -t jffs2 /dev/mtdblock/2 qqzm/ / $ ls
/ $ flash_eraseall /dev/mtd/2 <span></span> Erasing 128 Kibyte @ 8e0000 -- 98 % complete. /qqzm $ mount /dev/root on / type jffs2 (rw,noatime) proc on /proc type proc (rw,nodiratime) sysfs on /sys type sysfs (rw) devfs on /dev type devfs (rw) devpts on /dev/pts type devpts (rw) /dev/mmcblk0p1 on /mnt/sd type vfat (rw,nodiratime,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1) /dev/mtdblock/2 on /qqzm type jffs2 (rw,noatime) none on /qqzm/www/cgi-bin/tmp type ramfs (rw) /qqzm $ cd .. / $ umount /qqzm umount: Couldn't umount /qqzm: Inappropriate ioctl for device / $ umount /dev/mtdblock/2 umount: Couldn't umount /dev/mtdblock/2: Inappropriate ioctl for device / $
通过上面的不断尝试和错误反馈,我把方案基本验证通过了,只是对其中的原理不清楚:
MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口,并进行了一个层次划分,层次从上到下大致为:设备文件、MTD设备层、MTD原始设备层、硬件驱动层。MTD的所有源代码在/drivers/mtd子目录下。
~ $ ls /dev/mtd* -l crw-rw---- 1 root root 90, 0 Jan 1 00:00 /dev/mtd0 crw-rw---- 1 root root 90, 1 Jan 1 00:00 /dev/mtd0ro crw-rw---- 1 root root 90, 2 Jan 1 00:00 /dev/mtd1 crw-rw---- 1 root root 90, 3 Jan 1 00:00 /dev/mtd1ro crw-rw---- 1 root root 90, 4 Jan 1 00:00 /dev/mtd2 crw-rw---- 1 root root 90, 5 Jan 1 00:00 /dev/mtd2ro crw-rw---- 1 root root 90, 6 Jan 1 00:00 /dev/mtd3 crw-rw---- 1 root root 90, 7 Jan 1 00:00 /dev/mtd3ro brw-rw---- 1 root root 31, 0 Jan 1 00:00 /dev/mtdblock0 brw-rw---- 1 root root 31, 1 Jan 1 00:00 /dev/mtdblock1 brw-rw---- 1 root root 31, 2 Jan 1 00:00 /dev/mtdblock2 brw-rw---- 1 root root 31, 3 Jan 1 00:00 /dev/mtdblock3 /dev/mtd: crw-rw-rw- 1 root root 90, 0 Jan 1 00:00 0 cr--r--r-- 1 root root 90, 1 Jan 1 00:00 0ro crw-rw-rw- 1 root root 90, 2 Jan 1 00:00 1 cr--r--r-- 1 root root 90, 3 Jan 1 00:00 1ro crw-rw-rw- 1 root root 90, 4 Jan 1 00:00 2 cr--r--r-- 1 root root 90, 5 Jan 1 00:00 2ro crw-rw-rw- 1 root root 90, 6 Jan 1 00:00 3 cr--r--r-- 1 root root 90, 7 Jan 1 00:00 3ro /dev/mtdblock: brw------- 1 root root 31, 0 Jan 1 00:00 0 brw------- 1 root root 31, 1 Jan 1 00:00 1 brw------- 1 root root 31, 2 Jan 1 00:00 2 brw------- 1 root root 31, 3 Jan 1 00:00 3 ~ $
/dev/mtdN 是MTD架构中实现的mtd分区所对应的字符设备(将mtd设备分成多个区,每个区就为一个字符设备),其里面添加了一些ioctl,支持很多命令,如MEMGETINFO,MEMERASE等。
mtd-utils中的flash_eraseall等工具,就是以这些ioctl为基础而实现的工具,实现一些关于Flash的操作。比如,mtd 工具中 flash_eraseall中:
if (ioctl(fd, MEMGETINFO, &meminfo) != 0)
{
fprintf(stderr, "%s: %s: unable to get MTD device info\n",exe_name, mtd_device);
return 1;
}
/dev/mtdblockN,是Flash驱动中用add_mtd_partitions()添加MTD设备分区,而生成的对应的块设备。MTD块设备驱动程序可以让flash器件伪装成块设备,实际上它通过把整块的erase block放到ram里面进行访问,然后再更新到flash,用户可以在这个块设备上创建通常的文件系统。
而对于MTD块设备,MTD设备层是不提供ioctl的实现方法的,也就不会有对应的MEMGETINFO命令之类,因此不能使用nandwrite,flash_eraseall,flash_erase等工具去对/dev/mtdblockN去进行操作,否则就会出现上面的现象一,同时也解释了现象3——用mtd2擦除分区后,在用mtdblock2进行umount就会造成混乱。
mtd块设备的大小可以通过proc文件系统进行查看:
~ $ cat /proc/partitions
major minor #blocks name
31 0 512 mtdblock0
31 1 1024 mtdblock1
31 2 5632 mtdblock2
31 3 9216 mtdblock3
254 0 30760960 mmcblk0
254 1 30756864 mmcblk0p1
~ $
通过proc文件系统查看mtd设备的分区情况:
~ $ cat /proc/mtd dev: size erasesize name mtd0: 00080000 00020000 "boot" mtd1: 00100000 00020000 "kernel" mtd2: 00580000 00020000 "roofs70" mtd3: 00900000 00020000 "app" ~ $
这里对于mtd和mtdblock设备的使用场景进行简单总结: