Loading fs/namei.c +55 −89 Original line number Diff line number Diff line Loading @@ -2824,63 +2824,19 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) static int atomic_open(struct nameidata *nd, struct dentry *dentry, struct path *path, struct file *file, const struct open_flags *op, bool got_write, bool need_lookup, int open_flag, umode_t mode, int *opened) { struct inode *dir = nd->path.dentry->d_inode; unsigned open_flag = op->open_flag; umode_t mode; int error; int acc_mode; int create_error = 0; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; bool excl; BUG_ON(dentry->d_inode); mode = op->mode; if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) mode &= ~current_umask(); excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); if (excl) open_flag &= ~O_TRUNC; /* * Checking write permission is tricky, bacuse we don't know if we are * going to actually need it: O_CREAT opens should work as long as the * file exists. But checking existence breaks atomicity. The trick is * to check access and if not granted clear O_CREAT from the flags. * * Another problem is returing the "right" error value (e.g. for an * O_EXCL open we want to return EEXIST not EROFS). */ if (open_flag & O_CREAT) { if (unlikely(!got_write)) { create_error = -EROFS; if (open_flag & (O_EXCL | O_TRUNC)) { /* Fall back and fail with the right error */ goto no_open; } /* No side effects, safe to clear O_CREAT */ open_flag &= ~O_CREAT; } else { create_error = may_o_create(&nd->path, dentry, mode); if (create_error) { if (open_flag & O_EXCL) goto no_open; open_flag &= ~O_CREAT; } } } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && unlikely(!got_write)) { /* * No O_CREATE -> atomicity not a requirement -> fall * back to lookup + open */ goto no_open; } if (nd->flags & LOOKUP_DIRECTORY) open_flag |= O_DIRECTORY; Loading @@ -2889,11 +2845,8 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, error = dir->i_op->atomic_open(dir, dentry, file, open_to_namei_flags(open_flag), mode, opened); if (error < 0) { if (create_error && error == -ENOENT) error = create_error; if (error < 0) goto out; } if (error) { /* returned 1, that is */ if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { Loading @@ -2906,7 +2859,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, } if (*opened & FILE_CREATED) fsnotify_create(dir, dentry); goto looked_up; path->dentry = dentry; path->mnt = nd->path.mnt; return 1; } /* Loading @@ -2925,21 +2880,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, out: dput(dentry); return error; no_open: if (need_lookup) { dentry = lookup_real(dir, dentry, nd->flags); if (IS_ERR(dentry)) return PTR_ERR(dentry); } looked_up: if (create_error && !dentry->d_inode) { error = create_error; goto out; } path->dentry = dentry; path->mnt = nd->path.mnt; return 1; } /* Loading Loading @@ -2967,9 +2907,11 @@ static int lookup_open(struct nameidata *nd, struct path *path, { struct dentry *dir = nd->path.dentry; struct inode *dir_inode = dir->d_inode; int open_flag = op->open_flag; struct dentry *dentry; int error; int error, create_error = 0; bool need_lookup = false; umode_t mode = op->mode; if (unlikely(IS_DEADDIR(dir_inode))) return -ENOENT; Loading @@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path, goto out_no_open; } /* * Checking write permission is tricky, bacuse we don't know if we are * going to actually need it: O_CREAT opens should work as long as the * file exists. But checking existence breaks atomicity. The trick is * to check access and if not granted clear O_CREAT from the flags. * * Another problem is returing the "right" error value (e.g. for an * O_EXCL open we want to return EEXIST not EROFS). */ if (open_flag & O_CREAT) { if (!IS_POSIXACL(dir->d_inode)) mode &= ~current_umask(); if (unlikely(!got_write)) { create_error = -EROFS; open_flag &= ~O_CREAT; if (open_flag & (O_EXCL | O_TRUNC)) goto no_open; /* No side effects, safe to clear O_CREAT */ } else { create_error = may_o_create(&nd->path, dentry, mode); if (create_error) { open_flag &= ~O_CREAT; if (open_flag & O_EXCL) goto no_open; } } } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && unlikely(!got_write)) { /* * No O_CREATE -> atomicity not a requirement -> fall * back to lookup + open */ goto no_open; } if (dir_inode->i_op->atomic_open) { return atomic_open(nd, dentry, path, file, op, got_write, need_lookup, opened); error = atomic_open(nd, dentry, path, file, op, open_flag, mode, opened); if (unlikely(error == -ENOENT) && create_error) error = create_error; return error; } no_open: if (need_lookup) { BUG_ON(dentry->d_inode); dentry = lookup_real(dir_inode, dentry, nd->flags); if (IS_ERR(dentry)) return PTR_ERR(dentry); } /* Negative dentry, just create the file */ if (!dentry->d_inode && (op->open_flag & O_CREAT)) { umode_t mode = op->mode; if (!IS_POSIXACL(dir->d_inode)) mode &= ~current_umask(); /* * This write is needed to ensure that a * rw->ro transition does not occur between * the time when the file is created and when * a permanent write count is taken through * the 'struct file' in finish_open(). */ if (!got_write) { error = -EROFS; goto out_dput; } if (!dentry->d_inode && (open_flag & O_CREAT)) { *opened |= FILE_CREATED; audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); error = may_o_create(&nd->path, dentry, mode); if (error) goto out_dput; if (!dir_inode->i_op->create) { error = -EACCES; goto out_dput; } error = dir_inode->i_op->create(dir_inode, dentry, mode, op->open_flag & O_EXCL); open_flag & O_EXCL); if (error) goto out_dput; fsnotify_create(dir_inode, dentry); } if (unlikely(create_error) && !dentry->d_inode) { error = create_error; goto out_dput; } out_no_open: path->dentry = dentry; path->mnt = nd->path.mnt; Loading Loading
fs/namei.c +55 −89 Original line number Diff line number Diff line Loading @@ -2824,63 +2824,19 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) static int atomic_open(struct nameidata *nd, struct dentry *dentry, struct path *path, struct file *file, const struct open_flags *op, bool got_write, bool need_lookup, int open_flag, umode_t mode, int *opened) { struct inode *dir = nd->path.dentry->d_inode; unsigned open_flag = op->open_flag; umode_t mode; int error; int acc_mode; int create_error = 0; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; bool excl; BUG_ON(dentry->d_inode); mode = op->mode; if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) mode &= ~current_umask(); excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); if (excl) open_flag &= ~O_TRUNC; /* * Checking write permission is tricky, bacuse we don't know if we are * going to actually need it: O_CREAT opens should work as long as the * file exists. But checking existence breaks atomicity. The trick is * to check access and if not granted clear O_CREAT from the flags. * * Another problem is returing the "right" error value (e.g. for an * O_EXCL open we want to return EEXIST not EROFS). */ if (open_flag & O_CREAT) { if (unlikely(!got_write)) { create_error = -EROFS; if (open_flag & (O_EXCL | O_TRUNC)) { /* Fall back and fail with the right error */ goto no_open; } /* No side effects, safe to clear O_CREAT */ open_flag &= ~O_CREAT; } else { create_error = may_o_create(&nd->path, dentry, mode); if (create_error) { if (open_flag & O_EXCL) goto no_open; open_flag &= ~O_CREAT; } } } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && unlikely(!got_write)) { /* * No O_CREATE -> atomicity not a requirement -> fall * back to lookup + open */ goto no_open; } if (nd->flags & LOOKUP_DIRECTORY) open_flag |= O_DIRECTORY; Loading @@ -2889,11 +2845,8 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, error = dir->i_op->atomic_open(dir, dentry, file, open_to_namei_flags(open_flag), mode, opened); if (error < 0) { if (create_error && error == -ENOENT) error = create_error; if (error < 0) goto out; } if (error) { /* returned 1, that is */ if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { Loading @@ -2906,7 +2859,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, } if (*opened & FILE_CREATED) fsnotify_create(dir, dentry); goto looked_up; path->dentry = dentry; path->mnt = nd->path.mnt; return 1; } /* Loading @@ -2925,21 +2880,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, out: dput(dentry); return error; no_open: if (need_lookup) { dentry = lookup_real(dir, dentry, nd->flags); if (IS_ERR(dentry)) return PTR_ERR(dentry); } looked_up: if (create_error && !dentry->d_inode) { error = create_error; goto out; } path->dentry = dentry; path->mnt = nd->path.mnt; return 1; } /* Loading Loading @@ -2967,9 +2907,11 @@ static int lookup_open(struct nameidata *nd, struct path *path, { struct dentry *dir = nd->path.dentry; struct inode *dir_inode = dir->d_inode; int open_flag = op->open_flag; struct dentry *dentry; int error; int error, create_error = 0; bool need_lookup = false; umode_t mode = op->mode; if (unlikely(IS_DEADDIR(dir_inode))) return -ENOENT; Loading @@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path, goto out_no_open; } /* * Checking write permission is tricky, bacuse we don't know if we are * going to actually need it: O_CREAT opens should work as long as the * file exists. But checking existence breaks atomicity. The trick is * to check access and if not granted clear O_CREAT from the flags. * * Another problem is returing the "right" error value (e.g. for an * O_EXCL open we want to return EEXIST not EROFS). */ if (open_flag & O_CREAT) { if (!IS_POSIXACL(dir->d_inode)) mode &= ~current_umask(); if (unlikely(!got_write)) { create_error = -EROFS; open_flag &= ~O_CREAT; if (open_flag & (O_EXCL | O_TRUNC)) goto no_open; /* No side effects, safe to clear O_CREAT */ } else { create_error = may_o_create(&nd->path, dentry, mode); if (create_error) { open_flag &= ~O_CREAT; if (open_flag & O_EXCL) goto no_open; } } } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && unlikely(!got_write)) { /* * No O_CREATE -> atomicity not a requirement -> fall * back to lookup + open */ goto no_open; } if (dir_inode->i_op->atomic_open) { return atomic_open(nd, dentry, path, file, op, got_write, need_lookup, opened); error = atomic_open(nd, dentry, path, file, op, open_flag, mode, opened); if (unlikely(error == -ENOENT) && create_error) error = create_error; return error; } no_open: if (need_lookup) { BUG_ON(dentry->d_inode); dentry = lookup_real(dir_inode, dentry, nd->flags); if (IS_ERR(dentry)) return PTR_ERR(dentry); } /* Negative dentry, just create the file */ if (!dentry->d_inode && (op->open_flag & O_CREAT)) { umode_t mode = op->mode; if (!IS_POSIXACL(dir->d_inode)) mode &= ~current_umask(); /* * This write is needed to ensure that a * rw->ro transition does not occur between * the time when the file is created and when * a permanent write count is taken through * the 'struct file' in finish_open(). */ if (!got_write) { error = -EROFS; goto out_dput; } if (!dentry->d_inode && (open_flag & O_CREAT)) { *opened |= FILE_CREATED; audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); error = may_o_create(&nd->path, dentry, mode); if (error) goto out_dput; if (!dir_inode->i_op->create) { error = -EACCES; goto out_dput; } error = dir_inode->i_op->create(dir_inode, dentry, mode, op->open_flag & O_EXCL); open_flag & O_EXCL); if (error) goto out_dput; fsnotify_create(dir_inode, dentry); } if (unlikely(create_error) && !dentry->d_inode) { error = create_error; goto out_dput; } out_no_open: path->dentry = dentry; path->mnt = nd->path.mnt; Loading