📄 namei.c
字号:
break; } /*释放资源*/ path_release(nd);/*返回错误信息*/return_err: return err;}/*查找相应的dentry结构*/int path_walk(const char * name, struct nameidata *nd){ /*置当前文件链为空0*/ current->total_link_count = 0; /*调用link_path_walk*/ return link_path_walk(name, nd);}/* SMP-safe *//*将nameidata指针指向相应的dentry 和vfsmount*/static int __emul_lookup_dentry(const char *name, struct nameidata *nd){ /*调用path_walk()若不能找到相应的dentry则返回0*/ if (path_walk(name, nd)) return 0; /*如果通过altroot寻找没有出错, *nd中保留了经过path_walk()的数据 *但当前nd中没有d_inode,从另一个root入口重新找入*/ if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) { /*建立一个新的nameidata*/ struct nameidata nd_root; nd_root.last_type = LAST_ROOT; nd_root.flags = nd->flags; /*将当前进程所用文件系统的根目录信息 *赋给nameidata的相应项*/ read_lock(¤t->fs->lock); nd_root.mnt = mntget(current->fs->rootmnt); nd_root.dentry = dget(current->fs->root); read_unlock(¤t->fs->lock); /*******/ if (path_walk(name, &nd_root)) return 1; /*查找成功nd中各项值重新赋值*/ if (nd_root.dentry->d_inode) { path_release(nd); nd->dentry = nd_root.dentry; nd->mnt = nd_root.mnt; nd->last = nd_root.last; return 1; } path_release(&nd_root); } return 1;}/*设置替换根目录*/void set_fs_altroot(void){ /*获取替换根目录*/ char *emul = __emul_prefix(); /*新建一个nameidata结构*/ struct nameidata nd; /*mnt指向替换目录的vfsmount的变量 *oldmnt指向原替换目录的vfsmount的变量*/ struct vfsmount *mnt = NULL, *oldmnt; /*dentry指向替换目录dentry的变量 *olddentry指向原替换目录dentry的变量*/ struct dentry *dentry = NULL, *olddentry; if (emul) { /*读加锁*/ read_lock(¤t->fs->lock); /*nameidata结构的mnt、dentry指向当前根目录的对应项*/ nd.mnt = mntget(current->fs->rootmnt); nd.dentry = dget(current->fs->root); /*读解锁*/ read_unlock(¤t->fs->lock); /*设置nameidata结构查找方式标记*/ nd.flags = LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE; /*查找要替换的路径*/ if (path_walk(emul,&nd) == 0) { /*找到则更改mnt指向替换目录的vfsmount的变量*/ mnt = nd.mnt; /*找到则更改dentry指向替换目录dentry的变量*/ dentry = nd.dentry; } } /*写加锁实现互斥*/ write_lock(¤t->fs->lock); /*记录原来的替换根目录指针*/ oldmnt = current->fs->altrootmnt; olddentry = current->fs->altroot; /*重新设置替换根目录的altrootmnt指向对应的vfsmount*/ current->fs->altrootmnt = mnt; /*重新设置替换根目录的altroot指向对应的dentry*/ current->fs->altroot = dentry; /*写解锁*/ write_unlock(¤t->fs->lock); /*释放资源*/ if (olddentry) { dput(olddentry); mntput(oldmnt); }}/* 给定的文件在根录下,对其nameidata结构初始化 */static inline intwalk_init_root(const char *name, struct nameidata *nd){ /*上锁*/ read_lock(¤t->fs->lock); /*判断当前的文件系统是否存在altroot*/ if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { /*当前文件系系统的altrootmnt、altroot *赋给nameidata的相应项*/ nd->mnt = mntget(current->fs->altrootmnt); nd->dentry = dget(current->fs->altroot); /*解锁*/ read_unlock(¤t->fs->lock); /*调用__emul_lookup_dentry(name,nd)看能否找到相应的dentry*/ if (__emul_lookup_dentry(name,nd)) /*找到返回0*/ return 0; read_lock(¤t->fs->lock); } /*若当前文件系统不存在altroot *将当前进程文件系统的rootmnt、root *赋给nameidata的相应项*/ nd->mnt = mntget(current->fs->rootmnt); nd->dentry = dget(current->fs->root); /*解锁*/ read_unlock(¤t->fs->lock); return 1;}/* 主要实现对于nameidata数据结构的一些初始化工作*/int path_init(const char *name, unsigned int flags, struct nameidata *nd){ /*文件名尾部指向上一级的类型 *LAST_ROOT是以“/”指向上一级 *其它类型还有LAST_NORM, LAST_DOT, LAST_DOTDOT, LAST_BIND*/ nd->last_type = LAST_ROOT; /*设置查找方式标记*/ nd->flags = flags; /*处理在根目录下的文件*/ if (*name=='/') return walk_init_root(name,nd); /*上锁*/ read_lock(¤t->fs->lock); /*得到当前进程文件系统的vsmount*/ nd->mnt = mntget(current->fs->pwdmnt); /*得到当前进程文件系统的dentry*/ nd->dentry = dget(current->fs->pwd); /*解锁*/ read_unlock(¤t->fs->lock); return 1;}/*生成散列值,并据该散列值查找相应的dentry结构,若未找到则创建该dentry*/struct dentry * lookup_hash(struct qstr *name, struct dentry * base){ /*要返回的dentry结构*/ struct dentry * dentry; struct inode *inode; /*记录调用函数返回值的变量*/ int err; inode = base->d_inode; /*判断该结点是否有执行权限*/ err = permission(inode, MAY_EXEC); dentry = ERR_PTR(err); /*不可执行则返回*/ if (err) goto out; /* * 判断文件系统是否存在具体的散列函数 */ if (base->d_op && base->d_op->d_hash) { /*生成一个散列值,结果存在name结构中*/ err = base->d_op->d_hash(base, name); dentry = ERR_PTR(err); /*散列值生成不成功则返回*/ if (err < 0) goto out; } /*高速缓存中查找指定的dentry*/ dentry = cached_lookup(base, name, 0); /*高速缓存中未找到*/ if (!dentry) { /*根据指定入口分配一个新的dentry*/ struct dentry *new = d_alloc(base, name); dentry = ERR_PTR(-ENOMEM); /*若分配不成功则返回*/ if (!new) goto out; /*上锁*/ lock_kernel(); /*查找new中所指索引结点所在目录*/ dentry = inode->i_op->lookup(inode, new); /*解锁*/ unlock_kernel(); /*若查找结果为空则返回new*/ if (!dentry) dentry = new; /*查找不空释放new资源*/ else dput(new); }out: return dentry;}/* 给定路径和该路径节点名称,查找该节点所对应的目录项对象 *查找则返回找到的dentry地址*/struct dentry * lookup_one_len(const char * name, struct dentry * base, int len){ unsigned long hash; struct qstr this; unsigned int c; this.name = name; this.len = len; /*若len为0则返回错误信息*/ if (!len) goto access; /*将散列值清零*/ hash = init_name_hash(); /*对一层目录名做散列转化*/ while (len--) { c = *(const unsigned char *)name++; if (c == '/' || c == '\0') goto access; /*执行散列转化函数*/ hash = partial_name_hash(c, hash); } /*获得要查找节点的散列值*/ this.hash = end_name_hash(hash); /*查找dentry*/ return lookup_hash(&this, base);access: /*返回错误信息(命令拒绝执行)*/ return ERR_PTR(-EACCES);}/* *通过调用path_init()、path_walk(), *根据给定的文件路径名 *在内存中找到或建立代表着目标文件或目录的dentry结构和inode结构。 */int __user_walk(const char *name, unsigned flags, struct nameidata *nd){ char *tmp; int err; /*在系统空间中分配一个页面 *并从用户空间把文件名复制到这个页面上*/ tmp = getname(name); /*获得返回结果*/ err = PTR_ERR(tmp); if (!IS_ERR(tmp)) { err = 0; /*nameidata数据结构的一些初始化*/ if (path_init(tmp, flags, nd)) /*查找相应的dentry结构*/ err = path_walk(tmp, nd); /*因为动态分布,释放申请的页面*/ putname(tmp); } return err;}/* * It's inline, so penalty for filesystems that don't use sticky bit is * minimal. */static inline int check_sticky(struct inode *dir, struct inode *inode){ /*检查文件的粘滞位,只有粘滞为只能被文件的所有者和目录的所有者或root修改*/ if (!(dir->i_mode & S_ISVTX)) return 0; /*若当前文件系统的用户号和文件的用户号相同*/ if (inode->i_uid == current->fsuid) return 0; /*若当前文件系统的用户号和目录的用户号相同*/ if (dir->i_uid == current->fsuid) return 0; return !capable(CAP_FOWNER);}/* * Check whether we can remove a link victim from directory dir, check * whether the type of victim is right. *检测在指定路径下是否可以删除与victim相关的inode *dir目录必需是可执行可写的,且是非append-only,非immutable *victim目录项对象所指索引结点非append-only,非immutable *victim目录项对象必需与要删除文件的属性一致 *victim目录项非根目录 *若可删除返回0,不可删除返回其它错误信息 * 1. We can't do it if dir is read-only (done in permission()) * 2. We should have write and exec permissions on dir * 3. We can't remove anything from append-only dir * 4. We can't do anything with immutable dir (done in permission()) * 5. If the sticky bit on dir is set we should either * a. be owner of dir, or * b. be owner of victim, or * c. have CAP_FOWNER capability * 6. If the victim is append-only or immutable we can't do antyhing with * links pointing to it. * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. * 9. We can't remove a root or mountpoint. */static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir){ int error; /*若索引节点与目录项所指索引结点不对应则返回错误信息*/ if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; /*判断是否有MAY_WRITE、MAY_EXEC权限*/ error = permission(dir,MAY_WRITE | MAY_EXEC); /*无MAY_WRITE、MAY_EXEC权限则返回错误信息*/ if (error) return error; /*若是append-only则返回错误信息*/ if (IS_APPEND(dir)) return -EPERM; /*若victim目录项所指索引节点是append-only或是永久的则返回错误信息*/ if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| IS_IMMUTABLE(victim->d_inode)) return -EPERM; /*要删除目录*/ if (isdir) { /*victim所指索引结点不是目录则返回错误信息*/ if (!S_ISDIR(victim->d_inode->i_mode)) return -ENOTDIR; /*victim所指索引结点是根目录则返回错误信息*/ if (IS_ROOT(victim)) return -EBUSY; } /*要删除的不是目录而victim所指索引结点是目录也返回错误信息*/ else if (S_ISDIR(victim->d_inode->i_mode)) return -EISDIR; /*以上条件都符合返回可删除的信息0*/ return 0;}/* *检测在指定路径下是否可以新建一个与dentry目录项相关的inode *以下三种情况下不允许新建: *1、给定dentry的d_inode已经有效 *2、如果给定目录是只读的 *3、如果给定目录是永久的 *给定目录访问权限必是既可MAY_WRITE又可MAY_EXEC *返回值0表示可以新建,其它表错误信息 */static inline int may_create(struct inode *dir, struct dentry *child) { /*若该dentry已经指向一个inode结构则返回错误信息*/ if (child->d_inode) return -EEXIST; /*若该目录是只读则返回错误信息*/ if (IS_DEADDIR(dir)) return -ENOENT; /*判断给定目录的访问权是否既MAY_WRITE又MAY_EXEC*/ return permission(dir,MAY_WRITE | MAY_EXEC);}/* 根据参数f构造一个查找标识符retval,该标志为LOOKUP_FOLLOW和LOOKUP_DIRECTORY的组合 */static inline int lookup_flags(unsigned int f){ /*初始化查找标识符为LOOKUP_FOLLOW(顺次查找)*/ unsigned long retval = LOOKUP_FOLLOW; /*若f 中定义了O_NOFOLLOW(不跟随查找)则去掉retval中LOOKUP_FOLLOW*/ if (f & O_NOFOLLOW) retval &= ~LOOKUP_FOLLOW; /*若f中定义了O_CREAT|O_EXCL表示需要创建,则去掉retval中LOOKUP_FOLLOW*/ if ((f & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) retval &= ~LOOKUP_FOLLOW; /*若f为O_DIRECTORY表示为目录,则增加LOOKUP_DIRECTORY表示查找目标必须是目录*/ if (f & O_DIRECTORY) retval |= LOOKUP_DIRECTORY; /*返回查找标识符*/ return retval;}/*根据给定信息在VFS系统新建一个inode*/int vfs_create(struct inode *dir, struct dentry *dentry, int mode){ int error; mode &= S_IALLUGO; mode |= S_IFREG; /*处理信号量*/ down(&dir->i_zombie); /*判断是否可以在dir目录下新建一个与dentry有关的索引结点*/ error = may_create(dir, dentry); /*若有错,则返回*/ if (error) goto exit_lock; error = -EACCES; /* shouldn't it be ENOSYS? */ /*若当前目录的i_op所指函数集中无create函数,则返回*/ if (!dir->i_op || !dir->i_op->create) goto exit_lock; /*磁盘配额*/ DQUOT_INIT(dir); /*加锁*/ lock_kernel(); /*在dir目录下为与dentry目录项相关的正规文件创建一个新的磁盘索引节点*/ error = dir->i_op->create(dir, dentry, mode); /*解锁*/ unlock_kernel();exit_lock: /*处理信号量*/ up(&dir->i_zombie); if (!error) inode_dir_notify(dir, DN_CREATE); return error;}/*主要执行文件操作inode部分的打开工作 */int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd){ int acc_mode, error = 0; struct inode *inode; /*要打开文件的dentry*/ struct dentry *dentry; /*父目录的dentry*/ struct dentry *dir;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -