📄 namei.c
字号:
* * if (!d_unhashed(dentry)) * return -EBUSY; * * if it cannot handle the case of removing a directory * that is still in use by something else.. */static void d_unhash(struct dentry *dentry){ /*验证该dentry共享计数不为0*/ dget(dentry); /*检测使用该dentry的用户数*/ switch (atomic_read(&dentry->d_count)) { default: /*将不用的子目录从其该目录中删除*/ shrink_dcache_parent(dentry); if (atomic_read(&dentry->d_count) != 2) break; /*若使用该dentry的用户有两个则可执行d_drop*/ case 2: /*撤消其哈希值使得cache lookup无法查找到该子目录*/ d_drop(dentry); }}/*从指定目录下删除一个由给定目录项对象描述的子目录*/int vfs_rmdir(struct inode *dir, struct dentry *dentry){ int error; /*检测是否可以删除指定目录下与dentry相关的索引节点*/ error = may_delete(dir, dentry, 1); /*若不能删除此返回错误信息*/ if (error) return error; /*若给定目录的索引节点操作函数不包含rmdir函数则返回错误信息*/ if (!dir->i_op || !dir->i_op->rmdir) return -EPERM; /*配额初始化*/ DQUOT_INIT(dir); /*两个信号量的操作*/ double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); /*撤消该dentry散列值使得cache lookup无法查找到该子目录*/ d_unhash(dentry); /*目录不存在则返回该目录不存在的信息*/ if (IS_DEADDIR(dir)) error = -ENOENT; /*若文件系统未安装则返回错误信息*/ else if (d_mountpoint(dentry)) error = -EBUSY; else { /*上锁*/ lock_kernel(); /*众目录dir删除一个子目录,子目录的名字包含在dentry中*/ error = dir->i_op->rmdir(dir, dentry); /*解锁*/ unlock_kernel(); /*若删除成功则重置与dentry相关结点的标志*/ if (!error) dentry->d_inode->i_flags |= S_DEAD; } /*两个信号量处理*/ double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); /*执行删除操作后需处理标志位*/ if (!error) { /*文件dir中的i_dnotify_mask定义为DN_RENAME重命名*/ inode_dir_notify(dir, DN_DELETE); /*删除该dentry*/ d_delete(dentry); } /*释放dentry资源*/ dput(dentry); return error;}/*在相关的目录下删除一个的索引节点*/asmlinkage long sys_rmdir(const char * pathname){ int error = 0; char * name; struct dentry *dentry; struct nameidata nd; /*分配内存空间*/ name = getname(pathname); /*分配空间不成功*/ if(IS_ERR(name)) return PTR_ERR(name); /*查找该父目录的dentry*/ if (path_init(name, LOOKUP_PARENT, &nd)) error = path_walk(name, &nd); /*查找不成功则返回错误信息*/ if (error) goto exit; /*检测nameidata结构路径名结尾方式*/ switch(nd.last_type) { /*若LAST_DOTDOT即最后停留在两个'.'则返回ENOTEMPTY(目录不空)*/ case LAST_DOTDOT: error = -ENOTEMPTY; goto exit1; /*若为LAST_DOT,即最后停留在一个'.'则返回EINVAL*/ case LAST_DOT: error = -EINVAL; goto exit1; /*若为LAST_ROOT型,即最后一个是根目录则返回EBUSY*/ case LAST_ROOT: error = -EBUSY; goto exit1; } /*处理信号量*/ down(&nd.dentry->d_inode->i_sem); /*查找指定的dentry*/ dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); /*若查找成功*/ if (!IS_ERR(dentry)) { /*调用vfs_rmdir函数,从指定目录下删除一个由给定目录项对象描述的子目录*/ error = vfs_rmdir(nd.dentry->d_inode, dentry); dput(dentry); } up(&nd.dentry->d_inode->i_sem);exit1: /*释放资源*/ path_release(&nd);exit: /*释放内存中的名称name*/ putname(name); return error;}/*从指定目录删除给定目录项对象所指文件的硬链接 *删除成功则返回值为0,删除不成功返回错误信息*/int vfs_unlink(struct inode *dir, struct dentry *dentry){ int error; /*处理信号量*/ down(&dir->i_zombie); /*检测是否可以删除指定目录下与dentry相关的索引节点*/ error = may_delete(dir, dentry, 0); /*若可以删除*/ if (!error) { error = -EPERM; /*检测给定目录索引结点操作函数包含ulink操作*/ if (dir->i_op && dir->i_op->unlink) { /*配额初始化*/ DQUOT_INIT(dir); /*检查是否安装文件系统*/ if (d_mountpoint(dentry)) error = -EBUSY; else { /*上锁*/ lock_kernel(); /*从dir目录删除dentry目录项对象所指文件的硬链接*/ error = dir->i_op->unlink(dir, dentry); /*解锁*/ unlock_kernel(); /*删除成功删除所对应目录项对象*/ if (!error) d_delete(dentry); } } } /*信号量处理*/ up(&dir->i_zombie); /*若成功创建索引节点则修改其目录i_dnotify_mask信息*/ if (!error) inode_dir_notify(dir, DN_DELETE); return error;}/*删除指定路径名下文件的硬链接*/asmlinkage long sys_unlink(const char * pathname){ int error = 0; char * name; struct dentry *dentry; struct nameidata nd; /*分配内存空间*/ name = getname(pathname); /*分配内存空间不成功则返回错误信息*/ if(IS_ERR(name)) return PTR_ERR(name); /*查找文件父目录的dentry*/ if (path_init(name, LOOKUP_PARENT, &nd)) error = path_walk(name, &nd); /*若查找不成功则返回*/ if (error) goto exit; error = -EISDIR; /*已找到目标文件则返回*/ if (nd.last_type != LAST_NORM) goto exit1; /*处理信号量*/ down(&nd.dentry->d_inode->i_sem); /*依散列值查找dentry*/ dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); /*若查找成功*/ if (!IS_ERR(dentry)) { /*若最后一项是'/'即为目录文件则跳转到slashes*/ if (nd.last.name[nd.last.len]) goto slashes; /*从指定目录删除给定目录项对象所指文件的硬链接*/ error = vfs_unlink(nd.dentry->d_inode, dentry); exit2: /*释放dentry*/ dput(dentry); } /*信号量处理*/ up(&nd.dentry->d_inode->i_sem);exit1: /*释放资源*/ path_release(&nd);exit: /*释放内存中的名称name*/ putname(name); return error;slashes: /*若该dentry的d_inode无效则返回ENOENT *有效则判断dentry的d_inode的文件类型,若为目录则返回EISDIR,非目录则返回ENOTDIR*/ error = !dentry->d_inode ? -ENOENT : S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; goto exit2;}/*在给定目录下为与目录项对象相关的符号链创建一个新的索引节点 *创建成功返回值为0不成功返回对应的错误信息*/int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname){ int error; /*处理信号量*/ down(&dir->i_zombie); /*检测是否可在dir下建立与dentry相关的索引节点*/ error = may_create(dir, dentry); /*若不可建立则跳转到返回段*/ if (error) goto exit_lock; error = -EPERM; /*若给定目录索引结点操作函数不含symlink操作跳转以返回程序段*/ if (!dir->i_op || !dir->i_op->symlink) goto exit_lock; /*配额初始化*/ DQUOT_INIT(dir); /*上锁*/ lock_kernel(); /*在dir下为与dentry相关的符号链创建一个新的索引节点*/ error = dir->i_op->symlink(dir, dentry, oldname); /*解锁*/ unlock_kernel();exit_lock: /*处理信号量*/ up(&dir->i_zombie); /*若成功创建索引节点则修改其目录i_dnotify_mask信息*/ if (!error) inode_dir_notify(dir, DN_CREATE); return error;}/*在newname处为符号链接创建一个新的索引节点 */asmlinkage long sys_symlink(const char * oldname, const char * newname){ int error = 0; char * from; char * to; /*分配内存空间*/ from = getname(oldname); /*若分配空间不成功则返回错误信息*/ if(IS_ERR(from)) return PTR_ERR(from); /*分配内存空间*/ to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { struct dentry *dentry; struct nameidata nd; /*查找该父目录的dentry*/ if (path_init(to, LOOKUP_PARENT, &nd)) error = path_walk(to, &nd); if (error) goto out; dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { /*在给定目录下为为与目录项对象相关的符号链创建一个新的索引节点*/ error = vfs_symlink(nd.dentry->d_inode, dentry, from); dput(dentry); } /*处理信号量*/ up(&nd.dentry->d_inode->i_sem); /*释放资源*/ path_release(&nd);out: /*释放内存中的名称to*/ putname(to); } /*释放内存中的名称*/ putname(from); return error;}/*创建一个名为new_dentry的硬链接,该硬链接指向dir目录下名为old_dentry的文件*/int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry){ struct inode *inode; int error; /*信号量处理*/ down(&dir->i_zombie); error = -ENOENT; inode = old_dentry->d_inode; /*若inode无效,则跳转到返回段*/ if (!inode) goto exit_lock; /*检测是否可创建inode*/ error = may_create(dir, new_dentry); /*若有错则跳转到返回段*/ if (error) goto exit_lock; error = -EXDEV; /*给定目录的普通文件标记与old_dentry下普通文件标记不同则跳转到返回段*/ if (dir->i_dev != inode->i_dev) goto exit_lock; error = -EPERM; /*若链接是append-only或immutable则不可建跳到返回段*/ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto exit_lock; /*若索引结点操作无link操作则跳到返回段*/ if (!dir->i_op || !dir->i_op->link) goto exit_lock; /*磁盘配额*/ DQUOT_INIT(dir); /*上锁*/ lock_kernel(); /*创建一个名为new_dentry的硬链接,该硬链接指向dir目录下名为old_dentry的文件*/ error = dir->i_op->link(old_dentry, dir, new_dentry); /*解锁*/ unlock_kernel();exit_lock: /*处理信号量*/ up(&dir->i_zombie); /*文件dir中的i_dnotify_mask定义为DN_RENAME重命名*/ if (!error) inode_dir_notify(dir, DN_CREATE); return error;}/* * Hardlinks are often used in delicate situations. We avoid * security-related surprises by not following symlinks on the * newname. --KAB * * We don't follow them on the oldname either to be compatible * with linux 2.0, and to avoid hard-linking to directories * and other special files. --ADM *为newname所指的内容创建新的硬链接,这个硬链接指向oldname所指的内容 */asmlinkage long sys_link(const char * oldname, const char * newname){ int error; char * from; char * to; /*分配内存空间*/ from = getname(oldname); /*有错则返回*/ if(IS_ERR(from)) return PTR_ERR(from); /*分配内存空间*/ to = getname(newname); error = PTR_ERR(to); /*若无错*/ if (!IS_ERR(to)) { struct dentry *new_dentry; struct nameidata nd, old_nd; error = 0; /*在内存中找到或建立代表着目标文件或目录dentry结构和inode结构由old_nd反回搜索结果*/ if (path_init(from, LOOKUP_POSITIVE, &old_nd)) error = path_walk(from, &old_nd); if (error) goto exit; /*在内存中找到或建立代表着目标文件或目录newname的dentry结构和inode结构由nd反回搜索结果*/ if (path_init(to, LOOKUP_PARENT, &nd)) error = path_walk(to, &nd); if (error) goto out; error = -EXDEV; /*搜索所得结果old_nd、nd所指vfsmount结构不同则跳转到返回段*/ if (old_nd.mnt != nd.mnt) goto out_release; /*查找指定类型文件所对应的目录项对象未找到则创建*/ new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { /*创建一个名为new_dentry的硬链接,该硬链接指向nd.dentry->d_inode目录下名为old_nd.dentry的文件*/ error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } /*处理信号量*/ up(&nd.dentry->d_inode->i_sem);out_release: /*释放资源*/ path_release(&nd);out: /*释放资源*/ path_release(&old_nd);exit: /*释放空间*/ putname(to); } putname(from); return error;}/* * The worst of all namespace operations - renaming directory. "Perverted" * doesn't even start to describe it. Somebody in UCB had a heck of a trip... * Problems: * a) we can get into loop creation. Check is done in is_subdir(). * b) race potential - two innocent renames can create a loop together. * That's where 4.4 screws up. Current fix: serialization on * sb->s_vfs_rename_sem. We might be more accurate, but that's another * story. * c) we have to lock _three_ objects - parents and victim (if it exists). * And that - after we got ->i_sem on parents (until then we don't know * whether the target exists at all, let alone whether it is a directory * or not). Solution: ->i_zombie. Taken only after ->i_sem. Always taken * on link creation/removal of any kind. And taken (without ->i_sem) on * directory that will be removed (both in rmdir() and here). * d) some filesystems don't support opened-but-unlinked directories, * either because of layout or because they are not ready to deal with * all cases correctly. The latter will be fixed (taking this sort of * stuff into VFS), but the former is not going away. Solution: the same * trick as in rmdir(). * e) conversion from fhandle to dentry may come in the wrong moment - when * we are removing the target. Solution: we will have to grab ->i_zombie * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on * ->i_sem on parents, which works but leads to some truely excessive * locking]. */ /*重命名一个目录文件,成功返回0,不成功返回错误信息*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -