整理了下伪文件系统bdev:
517static struct file_system_type bd_type = { 518 .name = "bdev", 519 .get_sb = bd_get_sb, 520 .kill_sb = kill_anon_super, 521}; 522 523static struct vfsmount *bd_mnt __read_mostly; 524struct super_block *blockdev_superblock;
这三个是文件系统的代表成员。文件系统类型、挂载点和超级块。
下面这个函数,应该是bdev文件系统的初始化函数:
1、为bdev_inode结构体创建slab缓存:kmem_cache_create
2、把文件系统类型注册进系统:register_filesystem
说下系统启动的时候,伪文件系统的启动流程:
start_kernel
→vfs_caches_init
→bdev_cache_init
所以这个函数就是伪文件系统的初始过程,我们也可以看到,在系统启动的时候,伪文件系统已经启动起来了。
493void __init bdev_cache_init(void) 494{ 495 int err; 496 struct vfsmount *bd_mnt; 497 498 bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), 499 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 500 SLAB_MEM_SPREAD|SLAB_PANIC), 501 init_once); 502 err = register_filesystem(&bd_type); 503 if (err) 504 panic("Cannot register bdev pseudo-fs"); 505 bd_mnt = kern_mount(&bd_type); 506 if (IS_ERR(bd_mnt)) 507 panic("Cannot create bdev pseudo-fs"); 508 /* 509 * This vfsmount structure is only used to obtain the 510 * blockdev_superblock, so tell kmemleak not to report it. 511 */ 512 kmemleak_not_leak(bd_mnt); 513 blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ 514}
kern_mount是挂载文件系统的函数,按道理,我们的伪文件系统bdev是无法挂载的阿。
架构p450:
内核提供了装载标志MS_NOUSER,防止此类文件系统被装载。
所有的文件系统机制,都适用于伪文件系统。
内核可以调用1804#definekern_mount(type)kern_mount_data(type,NULL)
这两个函数来“挂载”bdev文件系统。
(架构P443)
通常意义上的挂载(用户空间的)会调用
sys_mount->do_mount->do_new_mount->
-->>vfs_kern_mount把文件系统集成到VFS中去
-->>graft_tree 把文件系统的文件和目录集成到用户可见的表示中
我们这里伪文件系统bdev会通过上面提到的两个函数,调用vfs_kern_mount,把自身集成到vfs中去,供内核使用。但是它调用graft_tree的时候,因为设置了装载标志位MS_NOUSER,所以这个函数什么都不干。
文件系统的使用
这样以来,伪文件系统就初始化好了。一个挂载的文件系统对应三个全局变量:
523staticstructvfsmount*bd_mnt__read_mostly;
524structsuper_block*blockdev_superblock;
517staticstructfile_system_typebd_type= {
考虑到两点:
1、一种类型的文件系统,在系统中可能同时存在多种。比如说/目录和/home目录可能都挂载了ext3类型的文件系统,在内存中存在的文件系统类型变量却是只有一个的。
2、一个块设备,对应着一个超级块,可以挂载在多个目录上。
超级块对应的是一个块设备,对应这结构体supter_block。
一个文件系统挂载一次,对应着一个结构体vfs_mount。
所以我们不可以使用这两个结构体来操作我们欲操作的文件系统
523staticstructvfsmount*bd_mnt__read_mostly;
517staticstructfile_system_typebd_type= {
当我们查找一个文件系统的文件的时候,或者添加,或者删除文件,(本质上都是操作inode),我们都是以超级块来标志我们要操作的文件系统的。
524structsuper_block*blockdev_superblock;
bdev文件系统这就创建好了,我们下面需要知道两点:
1、他内部的节点是什么时候创建的bdev文件系统中的节点。
2、我们什么时候访问,和如何访问里面的节点。
其实内核中使用了这么一种机制:把查找和创建做成了一个接口,可能很多时候在创建的时候都需要判断是否已经存在,所以他很多东西的创建都是以查找函数为接口的,当查找不到的时候,再创建他,反正查找和创建返回的是一个东西。
目前我知道的踪迹是这个:(这个是创建的时候)
add_disk->
register_disk->
bdget_disk->
bdget(设备号)->
566struct block_device *bdget(dev_t dev) 567{ 568 struct block_device *bdev; 569 struct inode *inode; 570 571 inode = iget5_locked(bd_mnt->mnt_sb, hash(dev), 572 bdev_test, bdev_set, &dev); 573 574 if (!inode) 575 return NULL; 576 577 bdev = &BDEV_I(inode)->bdev; 578 579 if (inode->i_state & I_NEW) { 580 bdev->bd_contains = NULL; 581 bdev->bd_inode = inode; 582 bdev->bd_block_size = (1 << inode->i_blkbits); 583 bdev->bd_part_count = 0; 584 bdev->bd_invalidated = 0; 585 inode->i_mode = S_IFBLK; 586 inode->i_rdev = dev; 587 inode->i_bdev = bdev; 588 inode->i_data.a_ops = &def_blk_aops; 589 mapping_set_gfp_mask(&inode->i_data, GFP_USER); 590 inode->i_data.backing_dev_info = &default_backing_dev_info; 591 spin_lock(&bdev_lock); 592 list_add(&bdev->bd_list, &all_bdevs); 593 spin_unlock(&bdev_lock); 594 unlock_new_inode(inode); 595 } 596 return bdev; 597} 571 inode = iget5_locked(bd_mnt->mnt_sb, hash(dev), 572 bdev_test, bdev_set, &dev); 577 bdev = &BDEV_I(inode)->bdev;
看到这里两个东西,我们知道了,571这个必然是创建了一个inode,一个block_device,一个bdev_inode(后面这两个要跟到源码中看下)。
因为577这个bdev本质上就等效是bdev =bdev_inode->block_device。借助container_of(inode)这个宏来实现的效果。
所以可以看到,我们的代表整个硬盘的block_device是这个时候被创建的。
下一步来研究我们每个分区的block_device是什么时候创建的。