mount挂载内核源码

回忆一下大家众所周知的mount指令的含义:

首先mount是一个应用层的指令,对应的是一个系统调用,系统层函数应该是sys_mount,(这里针对的是linux0.11源码),其本质就是,将一个设备挂载到一个目录上

例如我们准备将一个分区挂载到了/home/machao这个目录上,挂载之前访问/home/machao这个目录,看到的内容是啥呢?应该就是挂载到根目录的文件系统上的/home/machao里的东西吧,但是挂载之后,我们访问/home/machao这个目录,看到的就是新挂上去的文件系统里的"/"路径下的内容了,那么这是为什么呢?mount这个步骤是怎么做到这个对应的文件系统的改变的呢?那这一切得从open函数开始说起,也就是系统层的sys_open这个系统调用:

sys_open这个函数主要在干嘛呢?找inode:

int sys_open(const char * filename,int flag,int mode)
{
	struct m_inode * inode;
	struct file * f;
	int i,fd;

    //找一个空白的fd,fd就是file_talbe的索引
	for(fd=0 ; fd<NR_OPEN ; fd++)
		if (!current->filp[fd])
			break;
    //从磁盘读取inode信息
	if ((i=open_namei(filename,flag,mode,&inode))<0) {
		current->filp[fd]=NULL;
		f->f_count=0;
		return i;
	}
	f->f_inode = inode;
	return (fd);
}

上图中核心代码就是,先找一个fd,也就是当前进程的file_table的索引 ,然后呢,open_namei(filename,flag,mode,&inode)

从磁盘中读取inode信息,然后,

f->f_inode=inode进行关联,

好了,至此我们这个进程打开了一个文件,通过fd就可以找到对应的inode了。我们再看sys_read系统调用:

int sys_read(unsigned int fd,char * buf,int count)
{
	struct file * file;
	struct m_inode * inode;
    inode = file->f_inode;
	if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
		if (count+file->f_pos > inode->i_size)
			count = inode->i_size - file->f_pos;
		if (count<=0)
			return 0;
		return file_read(inode,file,buf,count);
	}
}

可以看到核心代码就是先找到inode: 

inode = file->f_inode;

然后再调用普通文件的读函数file_read,读的时候当然就是要传这个inode。

所以,至此,我们猜测mount这个操作,大概率就是在修改inode这个东西,到底在修改什么东西呢,我们再看一下sys_open里的open_namei(filename,flag,mode,&inode)这个函数,这个函数是再读inode,里面调用了

dir_namei(pathname,&namelen,&basename)

dir_name里面调用了get_dir(pathname)

而我们看下get_dir:

static struct m_inode * get_dir(const char * pathname)
{
	while(1){
		if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
			iput(inode);
			return NULL;
		}
		inr = de->inode;
		idev = inode->i_dev;
		if (!(inode = iget(idev,inr)))
			return NULL;
	}
}
}

可以看到find_entry在读目录, 这个de就是读出来的dir_entry,我们知道这个dir_entry结构里存放的就是众所周知的普通文件(或者目录)的文件名以及对应的盘块号了,然后再iget读磁盘,读完之后,因为外面套了一个while循环,会不断递归的往里找。

那么我们就能联想到,iget的时候,从哪个设备去读取inode信息,那么读到的目录内容就是对应设备的啦。所以mount大概率就是在修改/home/machao这个目录的inode里的i_dev信息了。我们再看下mount内核代码:

int sys_mount(char * dev_name, char * dir_name, int rw_flag)
{
	struct m_inode * dev_i, * dir_i;
	struct super_block * sb;
	int dev;

	if (!(dev_i=namei(dev_name)))
	
	if (!(dir_i=namei(dir_name)))
	sb->s_imount=dir_i;
	dir_i->i_mount=1;
	dir_i->i_dirt=1;		/* NOTE! we don't iput(dir_i) */
	return 0;			/* we do that in umount */
}

 核心代码就是这句sb->s_imount=dir_i,将superblock的s_imount指向了当前的这个inode,也就是/home/machao这个inode。

然后我们看,在mount之后,再open的时候,此时通过get_dir这个函数获取/home/machao这个目录inode时,调用iget方法读取inode信息的时候,贴一下iget的代码:

struct m_inode * iget(int dev,int nr)
{
	
	while (inode < NR_INODE+inode_table) {
		//当这个inode已经被标记为被挂载了的时候
		if (inode->i_mount) {
			int i;

			for (i = 0 ; i<NR_SUPER ; i++)
                //找到对应的superblock,这里就对应mount时候的
                //sb->s_imount=dir_i;相对应了
				if (super_block[i].s_imount==inode)
					break;
			if (i >= NR_SUPER) {
				printk("Mounted inode hasn't got sb\n");
				if (empty)
					iput(empty);
				return inode;
			}
			iput(inode);
			dev = super_block[i].s_dev;
			nr = ROOT_INO;
			inode = inode_table;
			continue;
		}
		if (empty)
			iput(empty);
		return inode;
	}
	if (!empty)
		return (NULL);
	inode=empty;
	inode->i_dev = dev;
	inode->i_num = nr;
	read_inode(inode);
	return inode;
}

这里iget获取inode信息的 时候,发现/home/machao这个目录inode被标记为被挂载了,就会去读对应的superblock,然后设置这个inode对应的dev为那个superblock对应的dev信息

dev = super_block[i].s_dev;
inode->i_dev = dev;

 最后read_inode从新的文件系统读取inode信息啦

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_34116044

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值