浅析fat文件系统是怎么和sd物理卡块设备关联上的
====================sd卡物理设备的添加====================
drivers/mmc/card/block.c=>
mmc_blk_init()=>mmc_blk_probe()
mmc_init_queue()=>初始化request_queue磁盘排队处理函数
md->queue.queue = blk_init_queue(mmc_request, lock);
request_queue->make_request_fn = __make_request;
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");处理线程创建
//mmc_init_queue=>blk_init_queue=>blk_init_queue_node=>
//q->request_fn = rfn;也就是q->request_fn = mmc_request;
//blk_queue_make_request(q, __make_request);
//=>q->make_request_fn = __make_request
mmc_blk_alloc()=>
md->queue.issue_fn = mmc_blk_issue_rq;//实际数据传输函数,将queue上的bio数据通过物理信道传送到sd卡上
md->queue.data = md;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;//对应mmc_request申请,mmc_request会唤醒mmc_queue_thread内核线程,进行sd卡数据传输
add_disk(md->disk);//将sd卡块设备登记到文件系统中,同时通过hotplug广播消息给用户空间的daemon,创建/dev/mmcblk设备节点
====================fat文件系统挂接到sd物理卡上====================
执行mount命令装载sd卡为fat文件系统,sudo mount /dev/mmcblk sd -t vfat -o iocharset=utf8
sys_mount()=>do_kern_mount()=>接下来就是以前做过的分析了,从fs链表上摘出module_init(init_fat_fs)注册的fatfs,
具体由module_init(init_msdos_fs);完成.
调用msdos_get_sb填充超级块,打开/dev/mmcblk设备,获取其MAJOR主设备号,并根据MAJOR从block设备表中,找到由mmc_blk_probe()登记的block设备操作(这样应用层提交对磁盘操作的read和write函数之后,最终就会到达这个super超级块,fat文件系统将格式化为fat格式数据,然后进行/dev/mmcblk设备实际queue物理读写操作,通过super超级块也就将物理设备sd卡,和操作物理设备sd卡的文件系统msdos,以及使用文件系统的应用层read,wirte关联了起来,这种机制为给各个环节上的用户提供了更加一致、统一的操作视图),然后申请root对应的inode节点,之后将inode节点的操作函数集指向:
fat_read_root()=>
inode->i_op = sbi->dir_ops;也就是fs_dir_inode_ops;也就是msdos_dir_inode_operations;
inode->i_fop = &fat_dir_operations;
sb->s_op = &fat_sops;超级块操作函数集
对于fat上的inode节点对应的
inode->i_op = &fat_file_inode_operations;
inode->i_fop = &fat_file_operations;
inode->i_mapping->a_ops = &fat_aops;
比如sys_read()=>
mapping->a_ops->readpage(filp, page);
就是调用fat_readpage函数,申请bio然后,mpage_bio_submit()=>submit_bio()提交该bio,
电梯算法之后,接着调用generic_make_request()=>__generic_make_request发出磁盘请求,
q = bdev_get_queue(bio->bi_bdev);将获得该block磁盘的queue队列,对于sd卡,
这里bi_bdev就是super超级块,也就是上面register_disk是登记的东东,
所以bdev_get_queue(bio->bi_bdev);获得的q,也就是blk_register_queue注册登记的sd卡操作queue,
所以最后的数据提交都会经由super超级块来完成.
*******
//mmc_init_queue=>blk_init_queue=>blk_init_queue_node=>
//q->request_fn = rfn;也就是q->request_fn = mmc_request;
blk_queue_make_request(q, __make_request);
//=>q->make_request_fn = __make_request
*******
fat_readpage=>mpage_readpage=>mpage_bio_submit=>submit_bio=>generic_make_request=>__generic_make_request
=>q = bdev_get_queue(bio->bi_bdev);获取上边的q->request_fn = mmc_request;对应的queue,
接着ret = q->make_request_fn(q, bio);对于sd卡就是__make_request,
=>add_request=>__elv_add_request=>elv_insert=>q->request_fn(q);
=>mmc_request()
然后wake_up_process激活mmc_queue_thread()内核线程,
继续调用mq->issue_fn(mq, req);也就是sd卡的mmc_blk_issue_rq,最终到达了这里--物理寄存器控制层,完成真正的数据传输[gliethttp_20080703].
PS:fat_fill_super会尝试读取sd卡的DBR数据区,即通过sb_bread(sb, 0);读取操作系统所能读取的所谓第一个簇--0簇,但DBR前边的MBR怎么来读?通过在windows下使用winhex对u盘和c盘进行操作观察,确实起始扇区就是DBR,根本就读不到MBR,但是通过下面mbr_test测试程序的测试之后,发现,linux下可以轻松读取到MBR数据和DBR数据,不是太懂为什么,以后慢慢分析吧,必须靠时间了.
PS:当u盘插入之后,会生成/dev/sdb和/dev/sdb1(我的u盘只有1个主分区,为fat32格式),
调用sudo mount /dev/sdb1 /home/gliethttp/Desktop/udisk -t vfat -o iocharset=utf8之后,
就将sdb1挂载上了,所以很有可能是这样的,即:/dev/sdb对应的是MBR,然后/dev/sdb1对应的是一个fat分区,也就是DBR开始的空间,所以
当mount的是/dev/sdb1时,就可以正常mount,但是mount的是/dev/sdb时,就不行了.
PS:fdisk源码可以从这里下载:ftp.kernel.org/pub/linux/utils/util-linux-ng/
PS:由于整个系统过于复杂,当前也仅仅掌握了这么一个大概,更细致的分析,有待时间,晕了已经.
PS:但是SD卡设计,不是这样,比如在pxa上操作mmc主控制器host,对sd卡进行读写操作,那么需要实现对MBR、DBR、FAT1、FAT2、FDT和DATA的完全控制,所以mmc对sd的控制,既要管理sd的存储,又要对上层提供出合理的API,所以这是一种省去了scsi协议的usb host和usb slave的集成一体的实现,如果是单纯的usb host,那么对于更底层的管理host不需要关系,因为通过scsi可以交由slave去进一步处理数据,但是sd卡,不像slave那样智能,sd卡,是一个带有数据传输cpu控制器的nand存储器,仅此而已,cpu控制器没有再封装更多的其他协议,对于sd卡上的MBR和DBR等操作,就不是0地址了,MBR是0地址开始,DBR的位置应该根据MBR中DPT的主分区表来定位找到DBR的偏移量,而在ubuntu下这是没有的,/dev/sdb和/dev/sdb1的访问地址都是0,肯定是有个地方做了这种转换,但是现在还不知道在哪[gliethttp_20080703].
PS:读写/dev/sdb和/dev/sdb1磁盘源程序(ubuntu操作系统,2.6.24-19-generic,不论/dev/sdb1是否mount,都可以直接读取sdb和sdb1)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
//sudo mbr_test /dev/sdb 从MBR的0地址开始连续读取512字节数据
//sudo mbr_test /dev/sdb1 从第1个分区DBR的0地址开始连续读取512字节数据
int main(int argc, char *argv[])
{
unsigned char buffer[1024];
int fhandle = open(argv[1], O_RDONLY);
if(fhandle > 0)
{
if( read(fhandle, buffer, 512) < 0)
{
printf("shit\n");
return 0;
}
{
int i;
for(i = 0;i < 512;i++)
{
printf("%02X ", buffer[i]);
if( (i & 0xf) == 0xf )printf("\n");
fflush(stdout);
}
}
}
else
{
printf("no\n");
}
}
读出的MBR数据内容
gliethttp@Leith:~/tmp$ sudo ./mbr_test /dev/sdb
FA 31 C0 8E D8 8E D0 BC 00 7C 89 E6 06 57 52 8E
C0 FB FC BF 00 06 B9 00 01 F3 A5 EA 20 06 00 00
52 B8 00 41 BB AA 55 31 C9 30 F6 F9 CD 13 72 13
81 FB 55 AA 75 0D D1 E9 73 09 66 C7 06 8F 06 B4
42 EB 15 5A B4 08 CD 13 83 E1 3F 51 0F B6 C6 40
F7 E1 52 50 66 31 C0 66 99 E8 67 00 E8 24 01 4D
69 73 73 69 6E 67 20 6F 70 65 72 61 74 69 6E 67
20 73 79 73 74 65 6D 2E 0D 0A 00 66 60 66 31 D2
BB 00 7C 66 52 66 50 06 53 6A 01 6A 10 89 E6 66
F7 36 F4 7B C0 E4 06 88 E1 88 C5 92 F6 36 F8 7B
88 C6 08 E1 41 B8 01 02 8A 16 FA 7B CD 13 83 C4
10 66 61 C3 E8 C4 FF BE BE 7D BF BE 07 B9 20 00
F3 A5 C3 66 60 89 E5 BB BE 07 B9 04 00 31 C0 53
51 F6 07 80 74 03 40 89 DE 83 C3 10 E2 F3 48 74
5C 79 39 59 5B 8A 47 04 3C 0F 74 06 24 7F 3C 05
75 22 66 8B 47 08 66 8B 56 14 66 01 D0 66 21 D2
75 03 66 89 C2 E8 AC FF 72 03 E8 B6 FF 66 8B 46
1C E8 A0 FF 83 C3 10 E2 CC 66 61 C3 E8 64 00 4D
75 6C 74 69 70 6C 65 20 61 63 74 69 76 65 20 70
61 72 74 69 74 69 6F 6E 73 2E 0D 0A 00 66 8B 44
08 66 03 46 1C 66 89 44 08 E8 2F FF 72 13 81 3E
FE 7D 55 AA 0F 85 04 FF BC FA 7B 5A 5F 07 FA FF
E4 E8 1F 00 4F 70 65 72 61 74 69 6E 67 20 73 79
73 74 65 6D 20 6C 6F 61 64 20 65 72 72 6F 72 2E
0D 0A 00 5E AC 20 C0 74 0C B4 0E 8A 3E 62 04 B3
07 CD 10 EB EF CD 18 F4 EB FD 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 0D 0A 4E 54
4C 44 52 20 69 73 20 6D 69 73 73 69 68 67 00 01
01 00 0B FE BF 03 3F 00 00 00 C5 7C 7E 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
读出的u盘第一个分区的DBR数据内容
gliethttp@Leith:~/tmp$ sudo ./mbr_test /dev/sdb1
EB 58 90 6D 6B 64 6F 73 66 73 00 00 02 08 20 00
02 00 00 00 00 F8 00 00 3F 00 FF 00 00 00 00 00
C4 7C 7E 00 90 1F 00 00 00 00 00 00 02 00 00 00
01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 29 D1 96 68 48 20 20 20 20 20 20 20 20 20
20 20 46 41 54 33 32 20 20 20 0E 1F BE 77 7C AC
22 C0 74 0B 56 B4 0E BB 07 00 CD 10 5E EB F0 32
E4 CD 16 CD 19 EB FE 54 68 69 73 20 69 73 20 6E
6F 74 20 61 20 62 6F 6F 74 61 62 6C 65 20 64 69
73 6B 2E 20 20 50 6C 65 61 73 65 20 69 6E 73 65
72 74 20 61 20 62 6F 6F 74 61 62 6C 65 20 66 6C
6F 70 70 79 20 61 6E 64 0D 0A 70 72 65 73 73 20
61 6E 79 20 6B 65 79 20 74 6F 20 74 72 79 20 61
67 61 69 6E 20 2E 2E 2E 20 0D 0A 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
|