文件系统注册
注册fs:国家允许开银行/国企/股份制公司,把他们的性质特征写在法律里面公开,大家可以查阅。=>注册到链表
加载fs:开工商银行,神华公司等。需要登记公司地址和联系方式(mnt),法人(sb)等信息。=>同样注册各种链表,包括更追溯到上一级公司,下面的子公司等。
module_init(init_ext3_fs)
=>init_ext3_xattr();
=>init_inodecache();
=>register_filesystem(&ext3_fs_type);//如果在链表则返回,否则加入链表
static struct file_system_type ext3_fs_type = {
.owner = THIS_MODULE,
.name = "ext3",
.get_sb = ext3_get_sb,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
加载,共有两个路径,都需要解析
sys_mount
=>retval = do_mount((char *)dev_page, dir_page, (char *)type_page, flags, (void *)data_page);
=>retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
=>do_path_lookup(AT_FDCWD, name, flags, nd);//加载的路径解析
=>if (*name=='/')
==>nd->mnt = mntget(fs->rootmnt);
==>nd->dentry = dget(fs->root);//初始化
=>else if (dfd == AT_FDCWD)
==>nd->mnt = mntget(fs->pwdmnt);
==>nd->dentry = dget(fs->pwd);
=>retval = path_walk(name, nd); }
=>retval = do_new_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page);
=>struct vfsmount *mnt = do_kern_mount(type, flags, name, data);
=>struct file_system_type *type = get_fs_type(fstype);
=>struct vfsmount *mnt = vfs_kern_mount(type, flags, name, data);//3大功能 分配mnt;分配sb(如果没有分配的话);填充mnt基本信息
=>mnt = alloc_vfsmnt(name);//第一功能
=>error = type->get_sb(type, flags, name, data, mnt);//Super.c (c:\linux\linux-2.6.23\fs\ext2): .get_sb = ext2_get_sb,//第二功能
=>ext2_get_sb
=>get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);//到了通用通用块层
=>bdev = open_bdev_excl(dev_name, flags, fs_type);//需要通过块设备驱动读取的原因是,超级块不在文件系统管理之内,文件系统的root_inode等信息存放在裸块里面,只能通过块设备驱动先读取块信息,然后根据文件系统type解析里面的内容填充到root_inode
=>struct block_device *bdev = lookup_bdev(path);
=>error = path_lookup(path, LOOKUP_FOLLOW, &nd);
=>do_path_lookup(AT_FDCWD, name, flags, nd);//设备节点路径解析
=>inode = nd.dentry->d_inode;
=>bdev = bd_acquire(inode);
=>error = blkdev_get(bdev, mode, 0);
=>__blkdev_get(bdev, mode, flags, 0);
=>do_open(bdev, &fake_file, for_part);//建立bdev、block_device和gendisk的联系
=>s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
=>if (s->s_root)
close_bdev_excl(bdev);//如果已经有super block,那么不需要重新申请和填充
=>else
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);//调用ext2_fill_super回调函数
=>sb_block = get_sb_block(&data);//默认是1,如果mount参数有sb=xxx则用用户参数,extx文件系统超级块有备份,默认超级块故障可以用备份超级块mount进行恢复
=>sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);//分配超级快
sb->s_fs_info = sbi;
=>blocksize = sb_min_blocksize(sb, BLOCK_SIZE);//估算最小逻辑块大小,为读取超级块做准备
=>bh = sb_bread(sb, logic_sb_block)//读取超级块,结果放在bh磁盘高速缓存里面
=>es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);//解析ext2磁盘超级块,并将高速缓存的sb信息填充到sbi里面
sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic);
=>for (i = 0; i < db_count; i++)
block = descriptor_loc(sb, logic_sb_block, i);
sbi->s_group_desc[i] = sb_bread(sb, block);
=>sb->s_op = &ext2_sops;//赋值超级块的方法
sb->s_export_op = &ext2_export_ops;
=>ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
=>mnt->mnt_mountpoint = mnt->mnt_root;//第三功能
mnt->mnt_parent = mnt;
=>do_add_mount(mnt, nd, mnt_flags, NULL);//将mnt放到对应的一坨各种链表里面
=>while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry));//抽丝剥茧,找到堆叠的最底层的dentry,详见《mount过程分析之七(do_add_mount)》
=>err = graft_tree(newmnt, nd))//加入链表
全路径查找是核心
static int fastcall path_walk(const char * name, struct nameidata *nd)
=>link_path_walk(name, nd);
=>result = __link_path_walk(name, nd);
=>inode = nd->dentry->d_inode;
=>for(;;) //每一次循环,剥离一层目录,通过hash抽丝剥茧找到以此找到下一个entry
==>this.name = name;//初始化hash和剥离出/~/之间的第一个name字符串,指向起始地址,通过len决定长度
c = *(const unsigned char *)name;
hash = init_name_hash();
do {
name++;
hash = partial_name_hash(c, hash);
c = *(const unsigned char *)name;
} while (c && (c != '/'));
this.len = name - (const char *) this.name;//this.len等于两个/之间的长度,即一个目录
this.hash = end_name_hash(hash);
==>nd->dentry->d_op->d_hash(nd->dentry, &this);//如果fs有私有hash,则选用私有hash,这个是dentry的方法
==>do_lookup(nd, &this, &next);
=>struct dentry *dentry = __d_lookup(nd->dentry, name);
=>dentry = real_lookup(nd->dentry, name, nd);
=>result = d_lookup(parent, name);
=>struct hlist_head *head = d_hash(parent,hash);
=>hlist_for_each_entry_rcu(dentry, node, head, d_hash)//命中哈希后,在哈希的链表里面遍历
==>qstr = &dentry->d_name;//匹配entry,如果有私有的方法,则用私有,这个是dentry的方法,否则字符串匹配
if (parent->d_op && parent->d_op->d_compare) {
if (parent->d_op->d_compare(parent, qstr, name))
goto next;
} else {
if (qstr->len != len)
goto next;
if (memcmp(qstr->name, str, len))
goto next;
}
==>found = dentry;//找到则返回
=>if (!result)//如果缓存没有找到,则需要从磁盘高速缓存读取
==>result = dir->i_op->lookup(dir, dentry, nd);//inode的方法
=>ext2_lookup
=>ino = ext2_inode_by_name(dir, dentry);
=>struct ext2_dir_entry_2 * de = ext2_find_entry (dir, dentry, &page);
=>do {
page = ext2_get_page(dir, n);
=>page = read_mapping_page(mapping, n, NULL);
=>filler_t *filler = (filler_t *)mapping->a_ops->readpage;
=>return read_cache_page(mapping, index, filler, data);
=>page = read_cache_page_async(mapping, index, filler, data);
=>page = __read_cache_page(mapping, index, filler, data);
=>page = find_get_page(mapping, index);//读磁盘高速缓存,否则分配page,通过fill回调函数读取磁盘刷新page
=>if (!page)
if (!cached_page)
cached_page = page_cache_alloc_cold(mapping);
=>page = cached_page;
=>err = filler(data, page);
=>err = filler(data, page);
}//do
=>inode = iget(dir->i_sb, ino);
=>sb->s_op->read_inode(inode);//.read_inode = ext2_read_inode,
=>struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);//高速缓存读取ext2_inode节点
=>将读取的raw_inode信息赋值给inode内存模型
=>d_splice_alias(inode, dentry);
==>if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link)
====>err = do_follow_link(&next, nd);
====>inode = nd->dentry->d_inode;
==>else
====>path_to_nameidata(&next, nd);//为下一次for循环的do_lookup做准备
=>nd->mnt = path->mnt;
nd->dentry = path->dentry;
==>continue;
last_component://路径最后一个元素
/* Clear LOOKUP_CONTINUE iff it was previously unset */
==>nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
==>err = do_lookup(nd, &this, &next);
==>inode = next.dentry->d_inode;
==>path_to_nameidata(&next, nd);
==>return 0;
文件系统错误修复实例(1)
http://blog.youkuaiyun.com/ChuiGeDaQiQiu/article/details/24138875
卸载文件系统失败的时候可以通过fuser检查和杀死访问磁盘的进程
fuser命令详解(原创)
http://czmmiao.iteye.com/blog/1733722
e2fsprogs编译问题
http://blog.youkuaiyun.com/sanwenyublog/article/details/52817796
mount过程分析之六——挂载关系(图解) 作者的系列博客写得挺好
http://blog.youkuaiyun.com/ZR_Lang/article/details/40343899
mount过程分析之七(do_add_mount)
http://blog.youkuaiyun.com/ZR_Lang/article/details/40325241
本文详细解析了Linux文件系统的注册与加载过程,重点介绍了sys_mount系统调用的内部实现,包括路径解析、文件系统类型获取、超级块读取与解析等关键步骤。此外,还深入探讨了文件系统的挂载关系及mount操作的具体流程。
1万+

被折叠的 条评论
为什么被折叠?



