do_filp_open
/* * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ static struct file *do_filp_open(int dfd, const char *filename, int flags, int mode) { int namei_flags, error; struct nameidata nd; /*内外标记不一样*/ namei_flags = flags; if ((namei_flags+1) & O_ACCMODE) namei_flags++; /*顺着文件名打开操作*/ error = open_namei(dfd, filename, namei_flags, mode, &nd); if (!error)/*根据得到的文件数据,填充file结构体*/ return nameidata_to_filp(&nd, flags); return ERR_PTR(error); }
open_namei
int open_namei(int dfd, const char *pathname, int flag, int mode, struct nameidata *nd) { int acc_mode, error; struct path path; struct dentry *dir; int count = 0; /*从flags得到打开模式*/ acc_mode = ACC_MODE(flag); /* O_TRUNC表示我们需要检查写的权限 */ if (flag & O_TRUNC) acc_mode |= MAY_WRITE; /*O_APPEND需要MAY_APPEND权限 */ if (flag & O_APPEND) acc_mode |= MAY_APPEND; /*如果是不是创建文件的话,就调用path_lookup_open函数获得文件的dentry和vfsmount填充nameidata结构体,找到后就直接返回*/ if (!(flag & O_CREAT)) { error = path_lookup_open(dfd, pathname, lookup_flags(flag), nd, flag); /*获得后就直接返回函数*/ if (error) return error; goto ok; } /*如果是要创建文件,我们需要知道父目录,所以加上LOOKUP_PARENT的flag*/ error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode); if (error) return error; /*已经拥有了父目录,我们检查下返回结果,如果最后找到的是目录就返回错误,我们只创建文件不创建目录 */ error = -EISDIR; if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len]) goto exit; /**/ dir = nd->dentry; nd->flags &= ~LOOKUP_PARENT; mutex_lock(&dir->d_inode->i_mutex); /*填充path结构体*/ path.dentry = lookup_hash(nd); path.mnt = nd->mnt; do_last: /*如果获得的参数有问题就返回错误*/ error = PTR_ERR(path.dentry); if (IS_ERR(path.dentry)) { mutex_unlock(&dir->d_inode->i_mutex); goto exit; } if (IS_ERR(nd->intent.open.file)) { mutex_unlock(&dir->d_inode->i_mutex); error = PTR_ERR(nd->intent.open.file); goto exit_dput; } /* 错误的dentry,直接创建文件 */ if (!path.dentry->d_inode) { error = open_namei_create(nd, &path, flag, mode); if (error) goto exit; return 0; } /* * 说明文件已经存在 */ mutex_unlock(&dir->d_inode->i_mutex); audit_inode(pathname, path.dentry->d_inode); /*O_EXCL标志代表如果文件存在就退出*/ error = -EEXIST; if (flag & O_EXCL) goto exit_dput; /*找到真正的挂载点*/ if (__follow_mount(&path)) { error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; } error = -ENOENT; /*说明创建失败*/ if (!path.dentry->d_inode) goto exit_dput; /*处理连接*/ if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link) goto do_link; /*path结构体转成nameidata结构体*/ path_to_nameidata(&path, nd); error = -EISDIR; /*再次检查*/ if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) goto exit; ok: /*写之前的一些检查和准备工作*/ error = may_open(nd, acc_mode, flag); if (error) goto exit; return 0; exit_dput: /*退出前释放path*/ dput_path(&path, nd); exit: if (!IS_ERR(nd->intent.open.file)) release_open_intent(nd); path_release(nd); return error; do_link: /*如果flag有O_NOFOLLOW,说明禁止链接,直接返回错误*/ error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; /*首先找到父目录*/ nd->flags |= LOOKUP_PARENT; /*安全操作,暂时不管*/ error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; /*搜寻,并创建*/ error = __do_follow_link(&path, nd); if (error) { release_open_intent(nd); return error; } nd->flags &= ~LOOKUP_PARENT; /*检验返回结果*/ if (nd->last_type == LAST_BIND) goto ok; error = -EISDIR; if (nd->last_type != LAST_NORM) goto exit; if (nd->last.name[nd->last.len]) { __putname(nd->last.name); goto exit; } error = -ELOOP; /*超出循环最大次数*/ if (count++==32) { __putname(nd->last.name); goto exit; } /*填充返回结果*/ dir = nd->dentry; mutex_lock(&dir->d_inode->i_mutex); path.dentry = lookup_hash(nd); path.mnt = nd->mnt; __putname(nd->last.name); goto do_last; }
open_namei_create
static int open_namei_create(struct nameidata *nd, struct path *path, int flag, int mode) { int error; struct dentry *dir = nd->dentry; /*POSIX权限标准检查*/ if (!IS_POSIXACL(dir->d_inode)) mode &= ~current->fs->umask; /*vfs层调用文件创造*/ error = vfs_create(dir->d_inode, path->dentry, mode, nd); mutex_unlock(&dir->d_inode->i_mutex); dput(nd->dentry); /*创建后放到nameidata里*/ nd->dentry = path->dentry; if (error) return error; /*权限检查,不检查写权限和truncate权限*/ return may_open(nd, 0, flag & ~O_TRUNC); }
vfs_create
int vfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { /*打开前的权限检查*/ int error = may_create(dir, dentry, nd); if (error) return error; /*inode的inode_operation函数表的create函数*/ if (!dir->i_op || !dir->i_op->create) return -EACCES; /* shouldn't it be ENOSYS? */ mode &= S_IALLUGO; mode |= S_IFREG; /*安全检查操作*/ error = security_inode_create(dir, dentry, mode); if (error) return error; DQUOT_INIT(dir); /*创建*/ error = dir->i_op->create(dir, dentry, mode, nd); if (!error) fsnotify_create(dir, dentry); return error; }