在 的文件系统中,有个很重要的概念就是挂载,挂载大家应该都很熟悉,除了根文件系统,其他所有文件系统都要先挂载到根文件系统中的某个目录之后才能访问。
所谓的根文件系统就是系统启动的时候安装的第一个文件系统,它也是内核映像所在的文件系统。而 挂载到某个目录
的 某个目录
就是所谓的挂载点。
中有专门的命令来挂载文件系统,mount device dir
, 为要挂载的设备文件名, 为挂载点。这里所说的设备不是真的指单个实体设备,而是其上的逻辑设备,比如说一个磁盘上的不同分区都可以看作是不同的设备。
每个设备都有一个设备号来标识,设备号可以分为两部分,一部分叫做主设备号 ,它用来标识某一类型的设备,比如说磁盘。另一部分叫做次设备号 ,它来标识某一具体设备,比如说磁盘上的某一具体分区。
当文件系统挂载到某个目录后,我们就可以通过这个目录来访问该文件系统,很多地方就只是简单的这样讲了一下,但其实这只能说是挂载的作用,那到底什么是挂载,要想解决这个问题还是只能从源码着手。下面我将根据 的代码来讲述挂载,涉及的东西比较多,我们只讨论相关的部分。
struct m_inode {
/********略*********/
unsigned short i_mode; //文件类型和属性
unsigned char i_mount; //是否有文件系统挂载到这儿
unsigned short i_zone[9]; //索引取,如果是块/字符设备文件i_zone[0]是设备号
/********略*********/
};
struct super_block {
/********略*********/
unsigned short s_magic; //文件系统魔数
/********略*********/
unsigned short s_dev; //设备号
/********略*********/
struct m_inode * s_isup; //被挂载的文件系统的根目录inode
struct m_inode * s_imount; //该文件系统被安装到此inode
};
所谓的内存中的超级块和 指的是两者在内存中的缓存:
struct super_block super_block[NR_SUPER];
#define NR_SUPER 8
struct m_inode inode_table[NR_INODE];
#define NR_INODE 32
可以看出在 里面内存中最多同时存在 8 个超级块和 32 个文件的 。这个缓存与我们平时所说的缓存差不多,当系统要想获取一个 时,会先在 中寻找有没有该 ,如果有的话就直接返回,如果没有,就从设备上将 读到 之后再返回。
在看 挂载之前,先来看看一些操作函数。
static struct super_block * read_super(int dev);
如果缓存区中没有该设备的超级块,则先找一个空闲的超级块槽,然后从设备上读取超级块到找到的空闲超级块槽。如果该设备的超级块已经在缓存区中且数据有效,则直接返回该超级块的指针。
struct super_block * get_super(int dev);
根据设备号 从超级块数组当中获取超级块。
void put_super(int dev);
释放指定的设备超级块,也就是将超级块的 字段清 0,如此使得该超级块槽空闲出来。
struct m_inode * namei(const char * pathname);
函数根据路径 获取末尾文件的 ,这个函数应该是有印象的吧,在 中也有类似的函数。如果不太清楚的话,我这里举个例子:如果参数路径是 /a/b/c
,调用 之后就会返回文件 的
挂载的实现还是挺简单的,来看代码
int sys_mount(char * dev_name, char * dir_name, int rw_flag) //将名称为dev_name的设备上的文件系统挂载到目录dir_name上
{
struct m_inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
if (!(dev_i=namei(dev_name))) //没有找到该设备
return -ENOENT;
dev = dev_i->i_zone[0];
if (!S_ISBLK(dev_i->i_mode)) { //不是块设备
iput(dev_i);
return -EPERM;
}
iput(dev_i); //释放该设备的inode
if (!(dir_i=namei(dir_name))) //解析获取挂载点的inode
return -ENOENT;
if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { //如果挂载点的引用数不等于1获取挂载点为根目录
iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { //挂载点不是目录
iput(dir_i);
return -EPERM;
}
if (!(sb=read_super(dev))) { //将设备上的文件系统的超级块读取到内存中
iput(dir_i);
return -EBUSY;
}
if (sb->s_imount) { //如果该文件系统已挂载
iput(dir_i);
return -EBUSY;
}
if (dir_i->i_mount) { //如果挂载点已经挂载了其他文件系统
iput(dir_i);
return -EPERM;
}
sb->s_imount=dir_i; //将挂载点的inode记录到设备的超级块中
dir_i->i_mount=1; //表示该挂载点已经挂载了该文件系统
dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ //我们不会释放挂载点的inode
return 0; /* we do that in umount */ //我们在umount卸载文件系统时释放
}
其流程图为:
上图为 的实现过程,除了各种检查之外, 实际上只做了两件事:
另外再解释几点:
这就是挂载的本质,有没有感觉简单的同时又还是模模糊糊的?为什么将文件系统挂载到某个目录之后,这个目录就能表示被挂载的文件系统。解决这个问题还是要再来捋捋文件系统是如何寻找一个文件的,也就是 函数,比如说给定一个路径 /a/b
,这是一个绝对路径,如何从最开始的根目录寻到文件 的呢?
这个问题我在 文件系统里面也详细说过, 里也类似。这里我们假设 文件都是目录文件, 是一个普通文件。首先根目录文件就是一个个目录项,在其中寻找文件名为 的目录项,从中获取 目录文件的 ,根据 的索引字段找到 目录文件的数据,也是一个个目录项,在其中寻找文件名为 的目录项,从中获取普通文件 的 然后返回。
上述所说的获取某个 ,使用的函数是,,其意为从设备 中获取编号为 的 。这个函数就会判断编号为 的 上是否挂载的有文件系统,来看相关代码:
struct m_inode * iget(int dev, int nr){
/*********略**********/
inode = inode_table; //从inode表中第一个元素开始
while (inode < NR_INODE+inode_table) { //扫描内存里缓存的inode表
if (inode->i_dev != dev || inode->i_num != nr) { //如果设备号对不上或者inode编号对不上
inode++; //下一个
continue;
}
wait_on_inode(inode); //等待该inode解锁
if (inode->i_dev != dev || inode->i_num != nr) { //因为等待过程中inode可能会发生变化,所以再次判断
inode = inode_table;
continue;
}
inode->i_count++; //找到了该inode,将其引用数加1
if (inode->i_mount) { //如果该inode上挂载的有文件系统
int i;
for (i = 0 ; i<NR_SUPER ; i++) //在内存中缓存的超级块中寻找挂载点为当前inode的超级块
if (super_block[i].s_imount==inode) //找到了,break
break;
if (i >= NR_SUPER) { //没找到,返回
printk("Mounted inode hasn't got sb\n");
if (empty)
iput(empty);
return inode;
}
iput(inode); //释放当前inode
dev = super_block[i].s_dev; //将设备号重新设置为被挂载的文件系统所在的设备号
nr = ROOT_INO; //将要寻找的inode编号重新设置为根目录的inode编号
inode = inode_table; //从内存的inode表第一个元素重新开始寻找inode
continue;
}
if (empty) //释放临时找的空闲inode
iput(empty);
return inode; //返回获取到的inode
}
}
其完整的流程图如下:
这是我根据赵炯画的图改编,因为没有详细讲述 的代码,所以主要关注虚线方框里面的就行。
如果在 中找到相应的 ,就判断 ,如果为真,表示该 表示的目录文件上面挂载的有文件系统。此时这个目录应该表示被挂载的文件系统的根目录,所以设置 超级块表示的设备,,原目录就被隐藏掉了。举个例子再说明一下,假如调用 ,本来我是要获取 1 号设备的第 99 个 ,然后发现这个 指向的目录上面挂载的有 2 号设备的文件系统,那么我们就去寻找 2 号设备的根目录 然后返回。所以看起来调用 实则调用的 ,这也就是为什么说将文件系统挂载到某个目录之后,这个目录就被屏蔽了的原因所在。
到此,对文件系统的挂载应该有个很清晰的认识呢,最后来看看文件系统的卸载,基本上就是挂载的逆操作,来简单看看:
int sys_umount(char * dev_name)
{
struct m_inode * inode;
struct super_block * sb;
int dev;
if (!(inode=namei(dev_name))) //解析获取设备文件的inode
return -ENOENT;
dev = inode->i_zone[0]; //对于块/字符设备,设备号记录在i_zone[0]
if (!S_ISBLK(inode->i_mode)) { //如果不是块设备
iput(inode);
return -ENOTBLK;
}
iput(inode); //释放设备文件的inode
if (dev==ROOT_DEV) //如果要卸载的是根文件系统
return -EBUSY;
if (!(sb=get_super(dev)) || !(sb->s_imount)) //如果没有获取到设备的超级块或者如果挂载点为空
return -ENOENT;
if (!sb->s_imount->i_mount) //如果挂载点的挂载标识为空
printk("Mounted inode has i_mount=0\n");
//检查是否有进程在使用将要卸载文件系统上的文件
for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
if (inode->i_dev==dev && inode->i_count)
return -EBUSY;
sb->s_imount->i_mount=0; //挂载标识设为0
iput(sb->s_imount); //释放挂载点的inode
sb->s_imount = NULL; //超级块的挂载点字段设为空
iput(sb->s_isup); //释放被卸载的文件系统的根目录inode
sb->s_isup = NULL; //根目录inode字段清0
put_super(dev); //释放设备超级块
sync_dev(dev); //更新的信息同步到设备
return 0;
}
文件系统的卸载主要就是释放超级块,然后将一些字段值复原,具体见上面注释就不细说了。
好了本文关于文件系统的挂载就这么多,所以回到开头什么是挂载,但从实现上来说,就是将超级块加载到内存里面,因为超级块就是一个文件系统的元信息集合,超级块就能代表一个文件系统,所以将超级块加载到内存里面,我们就可以认为挂载了相应的文件系统。当然挂载这个机制不可能就只是靠超级块是否在内存里面来决定实现,还需要其他的函数来辅助,就比如说获取 的 函数,这个函数就会来判断当前获取的这个 是否为挂载点,如果是,那就需要屏蔽当前这个 指向的目录文件,然后将其替换为被挂载的文件系统的根目录。这些总总加起来应该才算是挂载这个机制的实现,而不是说单靠一个 函数就实现了挂载的机制。
本文就到这里了,有什么问题还请批评指正,也欢迎大家来同我探讨交流一起学习一起进步。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/cwUlwhNQcQTqyipWcEFIlg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。