linux内核follow_link分析

来源:互联网 发布:淘宝摄影师接单平台 编辑:程序博客网 时间:2024/05/19 12:24
在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
原创粉丝点击