linux内核follow_link分析

在linux内核文件系统源代码里,有一个很重要的函数,就是do_follow_link函数,这个函数对应着用户空间的软链接文件的索引操作,有着很广泛的应用,我们今天来看一下他的来龙去脉。
首先我们从vfs_follow_link函数看起,vfs_follow_link函数定义在fs/namei.c,定义如下
int vfs_follow_link(struct nameidata *nd, const char *link)
{
	return __vfs_follow_link(nd, link);
}


继续看__vfs_follow_link函数,定义如下
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
	int res = 0;
	char *name;
	/*检查传入的参数*/
	if (IS_ERR(link))
		goto fail;
	/*如果是从根目录开始的路径,释放path,然后调用walk_init_root*/
	if (*link == '/') {
		path_release(nd);
		if (!walk_init_root(link, nd))
			/* weird __emul_prefix() stuff did it */
			goto out;
	}
	/*之前讲过的,获得文件对应的inode*/
	res = link_path_walk(link, nd);
out:
	/*有错误就返回错误*/
	if (nd->depth || res || nd->last_type!=LAST_NORM)
		return res;
	/*申请内存返回文件名*/
	name = __getname();
	if (unlikely(!name)) {
		path_release(nd);
		return -ENOMEM;
	}
	strcpy(name, nd->last.name);
	nd->last.name = name;
	return 0;
fail:
	path_release(nd);
	return PTR_ERR(link);
}


然后在link_path_walk里主要调用了do_follow_link函数,do_follow_link函数定义在fs/namei.c,定义如下
/*软链接有限制,为了防止出现无限循环*/
static inline int do_follow_link(struct path *path, struct nameidata *nd)
{
	int err = -ELOOP;
	/*如果已经超出了最大循环限度,就退出*/
	if (current->link_count >= MAX_NESTED_LINKS)
		goto loop;
	if (current->total_link_count >= 40)
		goto loop;
	BUG_ON(nd->depth >= MAX_NESTED_LINKS);
	cond_resched();
	/*安全操作,尅呀不管他*/
	err = security_inode_follow_link(path->dentry, nd);
	if (err)
		goto loop;
	/*进入之前,先把循环的深度++*/
	current->link_count++;
	current->total_link_count++;
	nd->depth++;
	/*主要工作函数*/
	err = __do_follow_link(path, nd);
	/*退出后减一*/
	current->link_count--;
	nd->depth--;
	return err;
loop:
	dput_path(path, nd);
	path_release(nd);
	return err;
}


我们继续看__do_follow_link函数,__do_follow_link函数定义在fs/namei.c,定义如下
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
	int error;
	void *cookie;
	struct dentry *dentry = path->dentry;


	touch_atime(path->mnt, dentry);
	nd_set_link(nd, NULL);


	if (path->mnt != nd->mnt) {
		path_to_nameidata(path, nd);
		dget(dentry);
	}
	mntget(path->mnt);
	/*调用底层文件系统的follow_link函数*/
	cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
	error = PTR_ERR(cookie);
	/*如果没有出错,就调用高层的follow_link*/
	if (!IS_ERR(cookie)) {
		/*首先从nd里获得软链接所指向的文件*/
		char *s = nd_get_link(nd);
		error = 0;
		/*因为软链接可能指向其他的文件系统的文件,所以需要给高层调用,继续寻找*/
		if (s)
			error = __vfs_follow_link(nd, s);
		/*使用后释放*/
		if (dentry->d_inode->i_op->put_link)
			dentry->d_inode->i_op->put_link(dentry, nd, cookie);
	}
	dput(dentry);
	mntput(path->mnt);


	return error;
}


以ext2文件系统为例,dentry->d_inode->i_op->follow_link函数就是ext2_follow_link,赋值在fs/ext2/symlink.c里
const struct inode_operations ext2_fast_symlink_inode_operations = {
	.readlink	= generic_readlink,
	.follow_link	= ext2_follow_link,
#ifdef CONFIG_EXT2_FS_XATTR
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr	= ext2_listxattr,
	.removexattr	= generic_removexattr,
#endif
};


可以看到对应的就是ext2_follow_link函数,ext2_follow_link函数定义在fs/ext2/symlink.c里,定义如下
static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	/*首先得到ext2_inode_info结构体,获得i_data字段,这个字段在ext2文件系统就是软链接的指向文件*/
	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
	/*然后就在nd结构体内部记录下来*/
	nd_set_link(nd, (char *)ei->i_data);
	return NULL;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值