当前位置: 首页 > backend >正文

文件系统挂载详细分析(《图解Linux内核》虚拟文件系统篇笔记二)

上次分析到,系统初始化时会创建出一个vfsmount结构体mnt,并把创建出来的这个mnt以及他的小兄弟mnt->mnt_root包装成一个path结构体root并赋值给current->fs->root,然后在后续文件查找时,会先初始化一个nameidata结构体nd,将nd->root初始化为current->fs->root。

这里其实当中还漏了很多,因为上节的分析之后我们知道创建硬链接所需要的vfsmount结构体mnt来源于系统初始化时自动挂载的文件系统rootfs,而实际从系统初始化到创建硬链接的过程当中,一定还会挂载其他的真实的文件系统,例如ext4、proc、sysfs等等,那么这些文件系统挂载和rootfs有区别吗?有相似之处吗?是否也是创建出vfsmount结构体的mnt供后续创建硬链接使用呢?

要回答上述的这些疑问,我觉得首先得从书中的一句话入手:mount一次就像时给原path的墙后面垒上了一堵墙,我们要做的就是穿过一堵堵墙,走到墙的尽头,垒起属于我们的新的墙。mount操作是穿过一堵堵墙去垒墙,那么同理,文件查找呢?就是穿过一堵堵墙去查找呗!

那么我就来看一下mount垒墙的时候,是怎么创建vfsmount结构体的mnt的,以及文件查找的时候是怎么穿越一堵堵墙去查找的

先看mount操作:

我们看到有这么个函数,这个函数在挂载新的文件系统的时候会被调用,简化后是这样:

static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,unsigned int mnt_flags)
{struct vfsmount *mnt;mnt = vfs_create_mount(fc);error = do_add_mount(real_mount(mnt), mp, mountpoint, mnt_flags);return error;
}

我们看到这里有个vfsmount,是create创建出来的,我们看最后是怎么“垒墙”的。

void mnt_set_mountpoint(struct mount *mnt,struct mountpoint *mp,struct mount *child_mnt)
{//chiled_mnt就是新挂载的文件系统,mnt是他的父级文件系统,都是mount结构体,其中的mnt属性是vfsmount结构体child_mnt->mnt_mountpoint = mp->m_dentry;child_mnt->mnt_parent = mnt;child_mnt->mnt_mp = mp;hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
}

我们再看看文件查找的时候是怎么穿过一度堵墙,在最后一堵墙的基础上进行文件查找的。

书中有提到这么一个函数:handle_mounts

这个函数中会调用_lookup_mnt越过一堵堵墙,而这个操作依赖于挂载时候子文件系统和父级文件系统使用mnt_parent关联。

struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
{struct hlist_head *head = m_hash(mnt, dentry);struct mount *p;hlist_for_each_entry_rcu(p, head, mnt_hash)if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)return p;return NULL;
}

这个函数中使用父级文件系统的mnt和dentry计算出一个hash值,而父级文件系统的子文件系统都存放在mount_hashtable这个数组中以这个hash值为下标的链表上。

再来看看之前文件系统挂载的时候是怎么插入的:

static int attach_recursive_mnt(struct mount *source_mnt,struct mount *dest_mnt,struct mountpoint *dest_mp,bool moving)
{struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;HLIST_HEAD(tree_list);struct mnt_namespace *ns = dest_mnt->mnt_ns;struct mountpoint *smp;struct mount *child, *p;struct hlist_node *n;int err;if (moving) {unhash_mnt(source_mnt);attach_mnt(source_mnt, dest_mnt, dest_mp);touch_mnt_namespace(source_mnt->mnt_ns);} else {if (source_mnt->mnt_ns) {/* move from anon - the caller will destroy */list_del_init(&source_mnt->mnt_ns->list);}mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);//垒墙(父子之间通过mnt_parent关联)之后,插入mount_hashtablecommit_tree(source_mnt);}return err;
}static void commit_tree(struct mount *mnt)
{struct mount *parent = mnt->mnt_parent;struct mount *m;LIST_HEAD(head);struct mnt_namespace *n = parent->mnt_ns;__attach_mnt(mnt, parent);
}static void __attach_mnt(struct mount *mnt, struct mount *parent)
{//将子文件系统的mnt(mount结构体)插入到mount_hashtable中根据父级文件系统的mnt和dentry计算出来的hash值为下标的链表上hlist_add_head_rcu(&mnt->mnt_hash,m_hash(&parent->mnt, mnt->mnt_mountpoint));list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
}

http://www.xdnf.cn/news/18478.html

相关文章:

  • UDP报文的数据结构
  • 可转换债券高频交易Level-2五档Tick级分钟历史数据分析
  • 20250823解决荣品RD-RK3588-MID核心板的底板的adb不通
  • 超越基础:Glide 高级优化与自定义实战
  • 12.Shell脚本修炼手册--函数的基础认知与实战演练(fock炸弹!!)
  • 第1.2节:早期AI发展(1950-1980)
  • Mybatis Plus - 代码生成器简单使用
  • Baumer高防护相机如何通过YoloV8深度学习模型实现社交距离的检测识别(python)
  • 【204页PPT】某著名企业信息化规划方案(附下载方式)
  • 【攻防世界】Web_php_include
  • GitLab CI:安全扫描双雄 SAST vs. Dependency Scanning 该如何抉择?
  • 阿德莱德多模态大模型导航能力挑战赛!NavBench:多模态大语言模型在具身导航中的能力探索
  • C++ csignal库详细使用介绍
  • 密码管理中Null 密码
  • 第九届86358贾家庄短片周在山西汾阳贾家庄举办
  • 齐次变换矩阵的逆变换:原理与SymPy实现
  • FIFO核心原理与机制
  • 解决 SymPy Lambdify 中的符号覆盖与语法错误问题
  • PiscCode使用 MediaPipe 检测人脸关键点多样展示
  • 大数据世界的开拓者:深入浅出MapReduce分布式计算经典范式
  • 相似度、距离
  • 一次性密码(OTP)原理及应用
  • OFD格式文件及Python将PDF转换为OFD格式文件
  • Centos 8 管理防火墙
  • 多目标跟踪中基于目标威胁度评估的传感器控制方法复现
  • LeeCode 40.组合总和II
  • SpringBoot -- 集成Spring Security (二)
  • CTFSHOW | 其他篇题解(二)web417 - web437
  • LeetCode第55题 - 跳跃游戏
  • 学习游戏制作记录(合成表UI和技能树的UI)8.22