Loading fs/namei.c +55 −89 Original line number Original line 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, static int atomic_open(struct nameidata *nd, struct dentry *dentry, struct path *path, struct file *file, struct path *path, struct file *file, const struct open_flags *op, const struct open_flags *op, bool got_write, bool need_lookup, int open_flag, umode_t mode, int *opened) int *opened) { { struct inode *dir = nd->path.dentry->d_inode; struct inode *dir = nd->path.dentry->d_inode; unsigned open_flag = op->open_flag; umode_t mode; int error; int error; int acc_mode; int acc_mode; int create_error = 0; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; bool excl; 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); excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); if (excl) if (excl) open_flag &= ~O_TRUNC; 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) if (nd->flags & LOOKUP_DIRECTORY) open_flag |= O_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, error = dir->i_op->atomic_open(dir, dentry, file, open_to_namei_flags(open_flag), open_to_namei_flags(open_flag), mode, opened); mode, opened); if (error < 0) { if (error < 0) if (create_error && error == -ENOENT) error = create_error; goto out; goto out; } if (error) { /* returned 1, that is */ if (error) { /* returned 1, that is */ if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { 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) if (*opened & FILE_CREATED) fsnotify_create(dir, dentry); 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: out: dput(dentry); dput(dentry); return error; 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 dentry *dir = nd->path.dentry; struct inode *dir_inode = dir->d_inode; struct inode *dir_inode = dir->d_inode; int open_flag = op->open_flag; struct dentry *dentry; struct dentry *dentry; int error; int error, create_error = 0; bool need_lookup = false; bool need_lookup = false; umode_t mode = op->mode; if (unlikely(IS_DEADDIR(dir_inode))) if (unlikely(IS_DEADDIR(dir_inode))) return -ENOENT; return -ENOENT; Loading @@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path, goto out_no_open; 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) { if (dir_inode->i_op->atomic_open) { return atomic_open(nd, dentry, path, file, op, got_write, error = atomic_open(nd, dentry, path, file, op, open_flag, need_lookup, opened); mode, opened); if (unlikely(error == -ENOENT) && create_error) error = create_error; return error; } } no_open: if (need_lookup) { if (need_lookup) { BUG_ON(dentry->d_inode); dentry = lookup_real(dir_inode, dentry, nd->flags); dentry = lookup_real(dir_inode, dentry, nd->flags); if (IS_ERR(dentry)) if (IS_ERR(dentry)) return PTR_ERR(dentry); return PTR_ERR(dentry); } } /* Negative dentry, just create the file */ /* Negative dentry, just create the file */ if (!dentry->d_inode && (op->open_flag & O_CREAT)) { if (!dentry->d_inode && (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; } *opened |= FILE_CREATED; *opened |= FILE_CREATED; audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); 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) { if (!dir_inode->i_op->create) { error = -EACCES; error = -EACCES; goto out_dput; goto out_dput; } } error = dir_inode->i_op->create(dir_inode, dentry, mode, error = dir_inode->i_op->create(dir_inode, dentry, mode, op->open_flag & O_EXCL); open_flag & O_EXCL); if (error) if (error) goto out_dput; goto out_dput; fsnotify_create(dir_inode, dentry); fsnotify_create(dir_inode, dentry); } } if (unlikely(create_error) && !dentry->d_inode) { error = create_error; goto out_dput; } out_no_open: out_no_open: path->dentry = dentry; path->dentry = dentry; path->mnt = nd->path.mnt; path->mnt = nd->path.mnt; Loading Loading
fs/namei.c +55 −89 Original line number Original line 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, static int atomic_open(struct nameidata *nd, struct dentry *dentry, struct path *path, struct file *file, struct path *path, struct file *file, const struct open_flags *op, const struct open_flags *op, bool got_write, bool need_lookup, int open_flag, umode_t mode, int *opened) int *opened) { { struct inode *dir = nd->path.dentry->d_inode; struct inode *dir = nd->path.dentry->d_inode; unsigned open_flag = op->open_flag; umode_t mode; int error; int error; int acc_mode; int acc_mode; int create_error = 0; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; struct dentry *const DENTRY_NOT_SET = (void *) -1UL; bool excl; 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); excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); if (excl) if (excl) open_flag &= ~O_TRUNC; 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) if (nd->flags & LOOKUP_DIRECTORY) open_flag |= O_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, error = dir->i_op->atomic_open(dir, dentry, file, open_to_namei_flags(open_flag), open_to_namei_flags(open_flag), mode, opened); mode, opened); if (error < 0) { if (error < 0) if (create_error && error == -ENOENT) error = create_error; goto out; goto out; } if (error) { /* returned 1, that is */ if (error) { /* returned 1, that is */ if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { 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) if (*opened & FILE_CREATED) fsnotify_create(dir, dentry); 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: out: dput(dentry); dput(dentry); return error; 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 dentry *dir = nd->path.dentry; struct inode *dir_inode = dir->d_inode; struct inode *dir_inode = dir->d_inode; int open_flag = op->open_flag; struct dentry *dentry; struct dentry *dentry; int error; int error, create_error = 0; bool need_lookup = false; bool need_lookup = false; umode_t mode = op->mode; if (unlikely(IS_DEADDIR(dir_inode))) if (unlikely(IS_DEADDIR(dir_inode))) return -ENOENT; return -ENOENT; Loading @@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path, goto out_no_open; 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) { if (dir_inode->i_op->atomic_open) { return atomic_open(nd, dentry, path, file, op, got_write, error = atomic_open(nd, dentry, path, file, op, open_flag, need_lookup, opened); mode, opened); if (unlikely(error == -ENOENT) && create_error) error = create_error; return error; } } no_open: if (need_lookup) { if (need_lookup) { BUG_ON(dentry->d_inode); dentry = lookup_real(dir_inode, dentry, nd->flags); dentry = lookup_real(dir_inode, dentry, nd->flags); if (IS_ERR(dentry)) if (IS_ERR(dentry)) return PTR_ERR(dentry); return PTR_ERR(dentry); } } /* Negative dentry, just create the file */ /* Negative dentry, just create the file */ if (!dentry->d_inode && (op->open_flag & O_CREAT)) { if (!dentry->d_inode && (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; } *opened |= FILE_CREATED; *opened |= FILE_CREATED; audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); 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) { if (!dir_inode->i_op->create) { error = -EACCES; error = -EACCES; goto out_dput; goto out_dput; } } error = dir_inode->i_op->create(dir_inode, dentry, mode, error = dir_inode->i_op->create(dir_inode, dentry, mode, op->open_flag & O_EXCL); open_flag & O_EXCL); if (error) if (error) goto out_dput; goto out_dput; fsnotify_create(dir_inode, dentry); fsnotify_create(dir_inode, dentry); } } if (unlikely(create_error) && !dentry->d_inode) { error = create_error; goto out_dput; } out_no_open: out_no_open: path->dentry = dentry; path->dentry = dentry; path->mnt = nd->path.mnt; path->mnt = nd->path.mnt; Loading