sys_mount - > do_mount -> do_new_mount -> vfs_kern_mount -> mount_fs -> xfs_fs_mount -> mount_bdev
mount_bdev是针对块设备挂载时使用的函数,此外还有mount_nodev, mount_single等函数,分别用于不同的挂载情况,这里以mount_bdev为例继续讲解。看一下mount_bdev的定义(fs/super.c中):
struct dentry *mount_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
struct block_device *bdev;
struct super_block *s;
fmode_t mode = FMODE_READ | FMODE_EXCL;
int error = 0;
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
// 通过dev_name设备名(如/dev/sda1)得到对应的block_device结构
// 首先是一个路径查找的过程,调用kern_path()得到struct path
// 然后以path.dentry->d_inode为参数调用bd_acquire得到block_device结构
// 对于路径查找和块设备的问题以后再叙述
bdev = blkdev_get_by_path(dev_name, mode, fs_type);
if (IS_ERR(bdev))
return ERR_CAST(bdev);
/*
* once the super is inserted into the list by sget, s_umount
* will protect the lockfs code from trying to start a snapshot
* while we are mounting
*/
mutex_lock(&bdev->bd_fsfreeze_mutex);
if (bdev->bd_fsfreeze_count > 0) {
mutex_unlock(&bdev->bd_fsfreeze_mutex);
error = -EBUSY;
goto error_bdev;
}
// sget现在现存fs_type->fs_supers链表中查找已经存在的对应的超级块实例(因为一个设备可能已经被挂载过了),fs_supers是file_system_type的成员,它指向一个特定文件系统下的所有超级块实例的链表表头。比较的过程就是遍历fs_supers链表,用每一个super_block->s_bdev和sget的bdev参数做比较,比较他们是不是同一个设备,test_bdev_super就是为了比较bdev而传入的函数参数。
// 如果没能找到已经存在的超级块实例,那就只能创建一个新的了。此时set_bdev_super函数就是用来把bdev参数设置到新创建的super_block的s_bdev域中。然后设置一下s_type和s_id(s_id这里先初始化为文件系统名,之后如果发现是磁盘设备再改为磁盘设备名),并把这个新的sb加入到全局super_blocks链表,以及此file_system_type的fs_supers链表中。
// 到此就得到了一个已知的或新的super_block实例,后面的工作都是为了填充这个super_block的内容&#x