📄 namei.c
字号:
mntput(*mnt); *mnt = parent; return 1;}int follow_up(struct vfsmount **mnt, struct dentry **dentry){ /*调用__follow_up函数*/ return __follow_up(mnt, dentry);}/*获得当前文件系统,并赋给nameidata结构的mnt指针, *并将其根目录赋给dentry*/static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry){ struct vfsmount *mounted; /*上锁*/ spin_lock(&dcache_lock); /**/ mounted = lookup_mnt(*mnt, *dentry); if (mounted) { /*获得当前文件系统*/ *mnt = mntget(mounted); spin_unlock(&dcache_lock); /*释放dentry*/ dput(*dentry); /*父目录连接到当前vfsmount的相应指针*/ mntput(mounted->mnt_parent); /*根目录赋值到dentry*/ *dentry = dget(mounted->mnt_root); /*成功返回*/ return 1; } /*解锁*/ spin_unlock(&dcache_lock); /*不成功返回为0*/ return 0;}/*调用__follow_down函数*/int follow_down(struct vfsmount **mnt, struct dentry **dentry){ /*返回__follow_down函数调用的结果*/ return __follow_down(mnt,dentry);} /*寻找nameidata描述文件的父目录*/static inline void follow_dotdot(struct nameidata *nd){ while(1) { /*指向其上层设备的vfsmount的变量*/ struct vfsmount *parent; /*指向其父目录dentry的变量*/ struct dentry *dentry; /*读上锁*/ read_lock(¤t->fs->lock); /*已到达 结点是本进程的根结点,dentry和mnt指针都相等*/ if (nd->dentry == current->fs->root && nd->mnt == current->fs->rootmnt) { /*解锁*/ read_unlock(¤t->fs->lock); break; } /*解锁*/ read_unlock(¤t->fs->lock); /*实现缓冲区互斥上锁*/ spin_lock(&dcache_lock); /*已到达的节点nd->dentry与其父结点在同一设备上*/ if (nd->dentry != nd->mnt->mnt_root) { /*当前节点dentry结构中d_parent指针即指向其父结点的dentry *调用dget获得其父节点的dentry*/ dentry = dget(nd->dentry->d_parent); /*解锁*/ spin_unlock(&dcache_lock); /*释放当前节点的dentry*/ dput(nd->dentry); /*将所得父节点的dentry结构纳入到nameidata结构中*/ nd->dentry = dentry; break; } /*当前节点vfsmount结构中mnt_parent指针即指向其上层设备的vfsmount*/ parent=nd->mnt->mnt_parent; /*已到达结点即是其所在设备上的根节点,表明已是根目录则保持现状跳出循环*/ if (parent == nd->mnt) { /*解锁*/ spin_unlock(&dcache_lock); /*跳出循环*/ break; } /*已到达结点不是其所在设备根节点的处理,层层向上直到根节点*/ /*获得上层设备的vfsmount*/ mntget(parent); /*获得上层目录的dentry*/ dentry=dget(nd->mnt->mnt_mountpoint); /*解锁*/ spin_unlock(&dcache_lock); /*释放已到达结点的dentry*/ dput(nd->dentry); /*nameidata结构的dentry指针指向上层目录的dentry*/ nd->dentry = dentry; /*释放已到达结点的vfsmount*/ mntput(nd->mnt); /*nameidata结构的dentry指针指向上层设备的vfsmount*/ nd->mnt = parent; }}/* *顺着路径名查找文件,将查找结果记录到nameidata结构 */int link_path_walk(const char * name, struct nameidata *nd){ /*新建一个dentry结构*/ struct dentry *dentry; /*新建一个inode结构*/ struct inode *inode; /*错误标志*/ int err; /*将namei的寻找方式标记赋值给lookup_flags*/ unsigned int lookup_flags = nd->flags; /*除去路径名开头的所有'/'*/ while (*name=='/') name++; /*路径名中仅含有"/",即其目标就是根目录,任务完成成功返回*/ if (!*name) goto return_base; /*inode赋值*/ inode = nd->dentry->d_inode; /*如果当前文件链不为0, *则将查找方式标记设为LOOKUP_FOLLOW,即依次寻找*/ if (current->link_count) lookup_flags = LOOKUP_FOLLOW; /* At this point we know we have a real path component. */ for(;;) { /*哈希变量*/ unsigned long hash; /*quick string结构*/ struct qstr this; /*存放目录名中单个字母的变量*/ unsigned int c; /*检查文件系统对应的inode是否可有“执行”权*/ err = permission(inode, MAY_EXEC); /*错误类型转化后赋值给dentry*/ dentry = ERR_PTR(err); /*无“执行权”则跳出循环*/ if (err) break; /*将目录名赋值给this的成员变量this*/ this.name = this; /*得到当前节点名中第一个字母*/ c = *(const unsigned char *)name; /*将哈希值清零*/ hash = init_name_hash(); /*对一层目录名做哈希转化*/ do { name++; hash = partial_name_hash(c, hash); c = *(const unsigned char *)name; } while (c && (c != '/')); /*得到进行hash转化的目录名的长度*/ this.len = name - (const char *) this.name; /*将hash值赋给this.hash, *若超过了unsigned int 的长度,再hash*/ this.hash = end_name_hash(hash); /* 若c为空则跳转到 last_component*/ if (!c) goto last_component; /*跳过所有的'/',若为空则跳到last_with_slashes*/ while (*++name == '/'); if (!*name) goto last_with_slashes; /*判断this.name的前两位是否以'.'开头 *如果当前第一个节点以'.'开头则节点名长度只能是1或2 *当长度为2时,第二个也必为'.'否则搜索失败*/ if (this.name[0] == '.') switch (this.len) { default: break; case 2: /*搜索失败*/ if (this.name[1] != '.') break; /*若有两个'.' *则执行follow_dotdot寻找它当前的根目录和父目录*/ follow_dotdot(nd); /*重设inode的值*/ inode = nd->dentry->d_inode; /* fallthrough */ /*若只有一个'.'则执行下一次循环 *路径名"/home/./user1"等价于"/home/user1"*/ case 1: continue; } /*如果当前目录项的d_op与d_op的d_hash非空 *则调用它自己文件系统的d_hash函数*/ if (nd->dentry->d_op && nd->dentry->d_op->d_hash) { err = nd->dentry->d_op->d_hash(nd->dentry, &this); /*若出错则跳出当前循环*/ if (err < 0) break; } /*从缓存中寻找当前目录的dentry*/ dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE); /*如果没有找到dentry则需要再一次搜索*/ if (!dentry) { /*调用real_lookup实现搜索*/ dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE); /*错误类型转化*/ err = PTR_ERR(dentry); /*判断有错则跳出循环*/ if (IS_ERR(dentry)) break; } /* 如果当前目录下挂有文件系统 *找到它并将其赋给nd->mnt *并将其根目录赋给dentry*/ while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry)) ; /*错误标记赋值*/ err = -ENOENT; /*inode赋值*/ inode = dentry->d_inode; /*若dentry的d_inode为空则跳转到out_dput,即适放资源后返回出错信息*/ if (!inode) goto out_dput; /*错误标记赋值*/ err = -ENOTDIR; /*若此时inode的i_op为空则不是一个目录结点跳转到out_dput*/ if (!inode->i_op) goto out_dput; /*若此节点是文件链接,调用do_follow_link处理链接*/ if (inode->i_op->follow_link) { err = do_follow_link(dentry, nd); dput(dentry); /*有错跳到返回字段*/ if (err) goto return_err; err = -ENOENT; /*新获得inode*/ inode = nd->dentry->d_inode; /*若dentry的d_inode为空则跳出循环*/ if (!inode) break; err = -ENOTDIR; /*若此时inode的i_op为空则不是一个目录结点跳出循环*/ if (!inode->i_op) break; } /*处理普通目录节点*/ else { /**/ dput(nd->dentry); /*将得到dentry保存到nd->dentry*/ nd->dentry = dentry; } err = -ENOTDIR; /*如果inode->i_op->lookup为空则无后续目录结点,跳出循环*/ if (!inode->i_op->lookup) break; /*继续循环处理下一层目录*/ continue; /* here ends the main loop */last_with_slashes: /*如果文件名路径最后是以'/'结束的, *则该将搜索的方式加上LOOKUP_FOLLOW与LOOKUP_FOLLOW*/ lookup_flags |= LOOKUP_FOLLOW | LOOKUP_FOLLOW;last_component: if (lookup_flags & LOOKUP_PARENT) goto lookup_parent; /*以下代码处理路径名最后一项*/ /*判断this.name的前两位是否以'.'开头*/ if (this.name[0] == '.') switch (this.len) { default: break; /*长度为2*/ case 2: /*搜索失败*/ if (this.name[1] != '.') break; /*若有两个'.' *则执行follow_dotdot寻找它当前的根目录和父目录*/ follow_dotdot(nd); /*重设inode的值*/ inode = nd->dentry->d_inode; /* fallthrough */ /*若只有一个'.'则执行下一次循环 *路径名"/home/./user1"等价于"/home/user1"*/ case 1: goto return_base; } /*如果当前目录项的d_op与d_op的d_hash非空 *则调用它自己文件系统的d_hash函数*/ if (nd->dentry->d_op && nd->dentry->d_op->d_hash) { err = nd->dentry->d_op->d_hash(nd->dentry, &this); /*若出错则跳出当前循环*/ if (err < 0) break; } /*从缓存中寻找当前目录的dentry*/ dentry = cached_lookup(nd->dentry, &this, 0); /*如果没有找到dentry则需要再一次搜索*/ if (!dentry) { /*调用real_lookup实现搜索*/ dentry = real_lookup(nd->dentry, &this, 0); /*错误类型转化*/ err = PTR_ERR(dentry); /*判断有错则跳出循环*/ if (IS_ERR(dentry)) break; } /* 如果当前目录下挂有文件系统 *找到它并将其赋给nd->mnt *并将其根目录赋给dentry*/ while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry)) ; /*inode赋值*/ inode = dentry->d_inode; /*inode、inode->i_op、inode->i_op->follow_link均不空且 *其查找标志为LOOKUP_FOLLOW *调用do_follow_link处理链接*/ if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { /*调用do_follow_link*/ err = do_follow_link(dentry, nd); dput(dentry); /*有错跳到返回字段*/ if (err) goto return_err; /*新获得inode*/ inode = nd->dentry->d_inode; } /*处理普通目录节点*/ else { dput(nd->dentry); /*将得到dentry保存到nd->dentry*/ nd->dentry = dentry; } err = -ENOENT; /*如果inode为空,跳到no_inode字段*/(580) if (!inode) goto no_inode; /*如果查找标志为LOOKUP_DIRECTORY*/ if (lookup_flags & LOOKUP_DIRECTORY) { err = -ENOTDIR; /*inode->i_op或inode->i_op->lookup为空则跳出循环*/ if (!inode->i_op || !inode->i_op->lookup) break; } /*如果查找标志不为LOOKUP_DIRECTORY跳到返回字段*/ goto return_base;/*no_inode字段*/no_inode: err = -ENOENT; /*LOOKUP_POSITIVE与LOOKUP_DIRECTORY被置位,出错,跳出循环境污染*/ if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY)) break; /*成功返回*/ goto return_base;/*将当前信息保存到父节点*/lookup_parent: /*nd->last赋值*/ nd->last = this; /*nd->last_type赋值*/ nd->last_type = LAST_NORM; /*若路径名的第一个字母不为'.'*/ if (this.name[0] != '.') /*成功返回*/ goto return_base; /*若长度为1*/ if (this.len == 1) /*设nd->last_type为LAST_DOT*/ nd->last_type = LAST_DOT; /*若前两个字母均为'.'*/ else if (this.len == 2 && this.name[1] == '.') /*设nd->last_type为LAST_DOTDOT*/ nd->last_type = LAST_DOTDOT;/*成功返回*/return_base: return 0; /*释放资源并返回出错信息*/out_dput: /*释放dentry资源*/ dput(dentry);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -