diff options
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 153 |
1 files changed, 82 insertions, 71 deletions
diff --git a/fs/namei.c b/fs/namei.c index d95249dd527c..59c8a669081a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -371,7 +371,7 @@ struct filename *complete_getname(struct delayed_filename *v) * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -static int check_acl(struct mnt_idmap *idmap, +static int check_acl(const struct mnt_idmap *idmap, struct inode *inode, int mask) { #ifdef CONFIG_FS_POSIX_ACL @@ -435,7 +435,7 @@ static inline bool no_acl_inode(struct inode *inode) * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -static int acl_permission_check(struct mnt_idmap *idmap, +static int acl_permission_check(const struct mnt_idmap *idmap, struct inode *inode, int mask) { unsigned int mode = inode->i_mode; @@ -518,7 +518,7 @@ static int acl_permission_check(struct mnt_idmap *idmap, * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int generic_permission(struct mnt_idmap *idmap, struct inode *inode, +int generic_permission(const struct mnt_idmap *idmap, struct inode *inode, int mask) { int ret; @@ -575,7 +575,7 @@ EXPORT_SYMBOL(generic_permission); * flag in inode->i_opflags, that says "this has not special * permission function, use the fast case". */ -static inline int do_inode_permission(struct mnt_idmap *idmap, +static inline int do_inode_permission(const struct mnt_idmap *idmap, struct inode *inode, int mask) { if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { @@ -625,7 +625,7 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) * * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. */ -int inode_permission(struct mnt_idmap *idmap, +int inode_permission(const struct mnt_idmap *idmap, struct inode *inode, int mask) { int retval; @@ -680,7 +680,7 @@ EXPORT_SYMBOL(inode_permission); * on IOP_FASTPERM can still get the optimization if they set IOP_FASTPERM_MAY_EXEC * on their directory inodes. */ -static __always_inline int lookup_inode_permission_may_exec(struct mnt_idmap *idmap, +static __always_inline int lookup_inode_permission_may_exec(const struct mnt_idmap *idmap, struct inode *inode, int mask) { /* Lookup already checked this to return -ENOTDIR */ @@ -1273,7 +1273,7 @@ fs_initcall(init_fs_namei_sysctls); */ static inline int may_follow_link(struct nameidata *nd, const struct inode *inode) { - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; vfsuid_t vfsuid; if (!sysctl_protected_symlinks) @@ -1314,7 +1314,7 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod * * Otherwise returns true. */ -static bool safe_hardlink_source(struct mnt_idmap *idmap, +static bool safe_hardlink_source(const struct mnt_idmap *idmap, struct inode *inode) { umode_t mode = inode->i_mode; @@ -1357,7 +1357,7 @@ static bool safe_hardlink_source(struct mnt_idmap *idmap, * * Returns 0 if successful, -ve on error. */ -int may_linkat(struct mnt_idmap *idmap, const struct path *link) +int may_linkat(const struct mnt_idmap *idmap, const struct path *link) { struct inode *inode = link->dentry->d_inode; @@ -1407,7 +1407,7 @@ int may_linkat(struct mnt_idmap *idmap, const struct path *link) * * Returns 0 if the open is allowed, -ve on error. */ -static int may_create_in_sticky(struct mnt_idmap *idmap, struct nameidata *nd, +static int may_create_in_sticky(const struct mnt_idmap *idmap, struct nameidata *nd, struct inode *const inode) { umode_t dir_mode = nd->dir_mode; @@ -1933,7 +1933,7 @@ static noinline struct dentry *lookup_slow(const struct qstr *name, struct inode *inode = dir->d_inode; struct dentry *res; inode_lock_shared(inode); - res = __lookup_slow(name, dir, flags); + res = __lookup_slow(name, dir, flags | LOOKUP_SHARED); inode_unlock_shared(inode); return res; } @@ -1947,12 +1947,12 @@ static struct dentry *lookup_slow_killable(const struct qstr *name, if (inode_lock_shared_killable(inode)) return ERR_PTR(-EINTR); - res = __lookup_slow(name, dir, flags); + res = __lookup_slow(name, dir, flags | LOOKUP_SHARED); inode_unlock_shared(inode); return res; } -static inline int may_lookup(struct mnt_idmap *idmap, +static inline int may_lookup(const struct mnt_idmap *idmap, struct nameidata *restrict nd) { int err, mask; @@ -2596,7 +2596,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) /* At this point we know we have a real path component. */ for(;;) { - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; const char *link; unsigned long lastword; @@ -2946,8 +2946,8 @@ struct dentry *start_dirop(struct dentry *parent, struct qstr *name, * end_dirop - signal completion of a dirop * @de: the dentry which was returned by start_dirop or similar. * - * If the de is an error, nothing happens. Otherwise any lock taken to - * protect the dentry is dropped and the dentry itself is release (dput()). + * If the @de is an error, nothing happens. Otherwise any lock taken to + * protect the dentry is dropped and the dentry itself is released (dput()). */ void end_dirop(struct dentry *de) { @@ -3111,7 +3111,7 @@ int lookup_noperm_common(struct qstr *qname, struct dentry *base) return 0; } -static int lookup_one_common(struct mnt_idmap *idmap, +static int lookup_one_common(const struct mnt_idmap *idmap, struct qstr *qname, struct dentry *base) { int err; @@ -3190,7 +3190,7 @@ EXPORT_SYMBOL(lookup_noperm); * * The caller must hold base->i_rwsem. */ -struct dentry *lookup_one(struct mnt_idmap *idmap, struct qstr *name, +struct dentry *lookup_one(const struct mnt_idmap *idmap, struct qstr *name, struct dentry *base) { struct dentry *dentry; @@ -3210,7 +3210,7 @@ EXPORT_SYMBOL(lookup_one); /** * lookup_one_unlocked - lookup single pathname component * @idmap: idmap of the mount the lookup is performed from - * @name: qstr olding pathname component to lookup + * @name: qstr holding pathname component to lookup * @base: base directory to lookup from * * This can be used for in-kernel filesystem clients such as file servers. @@ -3223,7 +3223,7 @@ EXPORT_SYMBOL(lookup_one); * - ERR_PTR(-ENOENT) if parent has been removed, or * - ERR_PTR(-EACCES) if parent directory is not searchable. */ -struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap, struct qstr *name, +struct dentry *lookup_one_unlocked(const struct mnt_idmap *idmap, struct qstr *name, struct dentry *base) { int err; @@ -3243,7 +3243,7 @@ EXPORT_SYMBOL(lookup_one_unlocked); /** * lookup_one_positive_killable - lookup single pathname component * @idmap: idmap of the mount the lookup is performed from - * @name: qstr olding pathname component to lookup + * @name: qstr holding pathname component to lookup * @base: base directory to lookup from * * This helper will yield ERR_PTR(-ENOENT) on negatives. The helper returns @@ -3259,11 +3259,11 @@ EXPORT_SYMBOL(lookup_one_unlocked); * the i_rwsem itself if necessary. If a fatal signal is pending or * delivered, it will return %-EINTR if the lock is needed. * - * Returns: A dentry, possibly negative, or + * Returns: A positive dentry, or * - same errors as lookup_one_unlocked() or * - ERR_PTR(-EINTR) if a fatal signal is pending. */ -struct dentry *lookup_one_positive_killable(struct mnt_idmap *idmap, +struct dentry *lookup_one_positive_killable(const struct mnt_idmap *idmap, struct qstr *name, struct dentry *base) { @@ -3306,7 +3306,7 @@ EXPORT_SYMBOL(lookup_one_positive_killable); * - ERR_PTR(-ENOENT) if the name could not be found, or * - same errors as lookup_one_unlocked(). */ -struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap, +struct dentry *lookup_one_positive_unlocked(const struct mnt_idmap *idmap, struct qstr *name, struct dentry *base) { @@ -3381,7 +3381,7 @@ struct dentry *lookup_noperm_positive_unlocked(struct qstr *name, EXPORT_SYMBOL(lookup_noperm_positive_unlocked); /** - * start_creating - prepare to create a given name with permission checking + * start_creating - prepare to access or create a given name with permission checking * @idmap: idmap of the mount * @parent: directory in which to prepare to create the name * @name: the name to be created @@ -3396,7 +3396,7 @@ EXPORT_SYMBOL(lookup_noperm_positive_unlocked); * * Returns: a negative or positive dentry, or an error. */ -struct dentry *start_creating(struct mnt_idmap *idmap, struct dentry *parent, +struct dentry *start_creating(const struct mnt_idmap *idmap, struct dentry *parent, struct qstr *name) { int err = lookup_one_common(idmap, name, parent); @@ -3413,8 +3413,8 @@ EXPORT_SYMBOL(start_creating); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing - * an object from a directory. Permission checking (MAY_EXEC) is performed + * Locks are taken and a lookup is performed prior to removing an object + * from a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * * If the name doesn't exist, an error is returned. @@ -3423,7 +3423,7 @@ EXPORT_SYMBOL(start_creating); * * Returns: a positive dentry, or an error. */ -struct dentry *start_removing(struct mnt_idmap *idmap, struct dentry *parent, +struct dentry *start_removing(const struct mnt_idmap *idmap, struct dentry *parent, struct qstr *name) { int err = lookup_one_common(idmap, name, parent); @@ -3440,7 +3440,7 @@ EXPORT_SYMBOL(start_removing); * @parent: directory in which to prepare to create the name * @name: the name to be created * - * Locks are taken and a lookup in performed prior to creating + * Locks are taken and a lookup is performed prior to creating * an object in a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * @@ -3451,7 +3451,7 @@ EXPORT_SYMBOL(start_removing); * * Returns: a negative or positive dentry, or an error. */ -struct dentry *start_creating_killable(struct mnt_idmap *idmap, +struct dentry *start_creating_killable(const struct mnt_idmap *idmap, struct dentry *parent, struct qstr *name) { @@ -3469,7 +3469,7 @@ EXPORT_SYMBOL(start_creating_killable); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing + * Locks are taken and a lookup is performed prior to removing * an object from a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * @@ -3482,7 +3482,7 @@ EXPORT_SYMBOL(start_creating_killable); * * Returns: a positive dentry, or an error. */ -struct dentry *start_removing_killable(struct mnt_idmap *idmap, +struct dentry *start_removing_killable(const struct mnt_idmap *idmap, struct dentry *parent, struct qstr *name) { @@ -3499,7 +3499,7 @@ EXPORT_SYMBOL(start_removing_killable); * @parent: directory in which to prepare to create the name * @name: the name to be created * - * Locks are taken and a lookup in performed prior to creating + * Locks are taken and a lookup is performed prior to creating * an object in a directory. * * If the name already exists, a positive dentry is returned. @@ -3522,7 +3522,7 @@ EXPORT_SYMBOL(start_creating_noperm); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing + * Locks are taken and a lookup is performed prior to removing * an object from a directory. * * If the name doesn't exist, an error is returned. @@ -3543,11 +3543,11 @@ struct dentry *start_removing_noperm(struct dentry *parent, EXPORT_SYMBOL(start_removing_noperm); /** - * start_creating_dentry - prepare to create a given dentry - * @parent: directory from which dentry should be removed - * @child: the dentry to be removed + * start_creating_dentry - prepare to access or create a given dentry + * @parent: directory of dentry + * @child: the dentry to be prepared * - * A lock is taken to protect the dentry again other dirops and + * A lock is taken to protect the dentry against other dirops and * the validity of the dentry is checked: correct parent and still hashed. * * If the dentry is valid and negative a reference is taken and @@ -3580,7 +3580,7 @@ EXPORT_SYMBOL(start_creating_dentry); * @parent: directory from which dentry should be removed * @child: the dentry to be removed * - * A lock is taken to protect the dentry again other dirops and + * A lock is taken to protect the dentry against other dirops and * the validity of the dentry is checked: correct parent and still hashed. * * If the dentry is valid and positive, a reference is taken and @@ -3642,7 +3642,7 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, } EXPORT_SYMBOL(user_path_at); -int __check_sticky(struct mnt_idmap *idmap, struct inode *dir, +int __check_sticky(const struct mnt_idmap *idmap, struct inode *dir, struct inode *inode) { kuid_t fsuid = current_fsuid(); @@ -3675,7 +3675,7 @@ EXPORT_SYMBOL(__check_sticky); * 11. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ -int may_delete_dentry(struct mnt_idmap *idmap, struct inode *dir, +int may_delete_dentry(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *victim, bool isdir) { struct inode *inode = d_backing_inode(victim); @@ -3728,7 +3728,7 @@ EXPORT_SYMBOL(may_delete_dentry); * 4. We should have write and exec permissions on dir * 5. We can't do it if dir is immutable (done in permission()) */ -int may_create_dentry(struct mnt_idmap *idmap, +int may_create_dentry(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *child) { audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); @@ -4142,7 +4142,7 @@ EXPORT_SYMBOL(end_renaming); * * Returns: mode to be passed to the filesystem */ -static inline umode_t vfs_prepare_mode(struct mnt_idmap *idmap, +static inline umode_t vfs_prepare_mode(const struct mnt_idmap *idmap, const struct inode *dir, umode_t mode, umode_t mask_perms, umode_t type) { @@ -4174,7 +4174,7 @@ static inline umode_t vfs_prepare_mode(struct mnt_idmap *idmap, * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode, +int vfs_create(const struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode, struct delegated_inode *di) { struct inode *dir = d_inode(dentry->d_parent); @@ -4228,7 +4228,7 @@ bool may_open_dev(const struct path *path) !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV); } -static int may_open(struct mnt_idmap *idmap, const struct path *path, +static int may_open(const struct mnt_idmap *idmap, const struct path *path, int acc_mode, int flag) { struct dentry *dentry = path->dentry; @@ -4287,7 +4287,7 @@ static int may_open(struct mnt_idmap *idmap, const struct path *path, return 0; } -static int handle_truncate(struct mnt_idmap *idmap, struct file *filp) +static int handle_truncate(const struct mnt_idmap *idmap, struct file *filp) { const struct path *path = &filp->f_path; struct inode *inode = path->dentry->d_inode; @@ -4312,7 +4312,7 @@ static inline int open_to_namei_flags(int flag) return flag; } -static int may_o_create(struct mnt_idmap *idmap, +static int may_o_create(const struct mnt_idmap *idmap, const struct path *dir, struct dentry *dentry, umode_t mode) { @@ -4432,7 +4432,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, const struct open_flags *op) { struct delegated_inode delegated_inode = { }; - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; struct dentry *dir = nd->path.dentry; struct inode *dir_inode = dir->d_inode; int open_flag; @@ -4440,12 +4440,14 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, int error, create_error; umode_t mode; bool got_write; + unsigned int shared_flag; retry: open_flag = op->open_flag; got_write = false; mode = op->mode; create_error = 0; + shared_flag = (open_flag & O_CREAT) ? 0 : LOOKUP_SHARED; if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { got_write = !mnt_want_write(nd->path.mnt); @@ -4454,10 +4456,10 @@ retry: * a different error; we'll be dropping this one anyway. */ } - if (open_flag & O_CREAT) - inode_lock(dir_inode); - else + if (shared_flag) inode_lock_shared(dir_inode); + else + inode_lock(dir_inode); if (unlikely(IS_DEADDIR(dir_inode))) { dentry = ERR_PTR(-ENOENT); @@ -4526,7 +4528,7 @@ retry: if (d_in_lookup(dentry)) { struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry, - nd->flags); + nd->flags | shared_flag); d_lookup_done(dentry); if (unlikely(res)) { if (IS_ERR(res)) { @@ -4574,10 +4576,10 @@ out: if (file->f_mode & FMODE_OPENED) fsnotify_open(file); } - if ((open_flag & O_CREAT) || create_error) - inode_unlock(dir_inode); - else + if (shared_flag) inode_unlock_shared(dir_inode); + else + inode_unlock(dir_inode); if (got_write) mnt_drop_write(nd->path.mnt); @@ -4789,7 +4791,8 @@ finish_lookup: static int do_open(struct nameidata *nd, struct file *file, const struct open_flags *op) { - struct mnt_idmap *idmap; + struct vfsmount *mnt; + const struct mnt_idmap *idmap; int open_flag = op->open_flag; bool do_truncate; int acc_mode; @@ -4830,11 +4833,17 @@ static int do_open(struct nameidata *nd, error = mnt_want_write(nd->path.mnt); if (error) return error; + /* + * A dedicated reference is needed because after the call to + * vfs_open_consume() we no longer own the reference in nd->path.mnt + * while we need to undo write acess below. + */ + mnt = mntget(nd->path.mnt); do_truncate = true; } error = may_open(idmap, &nd->path, acc_mode, open_flag); if (!error && !(file->f_mode & FMODE_OPENED)) - error = vfs_open(&nd->path, file); + error = vfs_open_consume(&nd->path, file); if (!error) error = security_file_post_open(file, op->acc_mode); if (!error && do_truncate) @@ -4843,8 +4852,10 @@ static int do_open(struct nameidata *nd, WARN_ON(1); error = -EINVAL; } - if (do_truncate) - mnt_drop_write(nd->path.mnt); + if (do_truncate) { + mnt_drop_write(mnt); + mntput(mnt); + } return error; } @@ -4863,7 +4874,7 @@ static int do_open(struct nameidata *nd, * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_tmpfile(struct mnt_idmap *idmap, +int vfs_tmpfile(const struct mnt_idmap *idmap, const struct path *parentpath, struct file *file, umode_t mode) { @@ -4921,7 +4932,7 @@ int vfs_tmpfile(struct mnt_idmap *idmap, * hence this is only for kernel internal use, and must not be installed into * file tables or such. */ -struct file *kernel_tmpfile_open(struct mnt_idmap *idmap, +struct file *kernel_tmpfile_open(const struct mnt_idmap *idmap, const struct path *parentpath, umode_t mode, int open_flag, const struct cred *cred) @@ -5169,7 +5180,7 @@ struct file *dentry_create(struct path *path, int flags, umode_t mode, struct dentry *orig_dentry = dentry; struct dentry *dir = dentry->d_parent; struct inode *dir_inode = d_inode(dir); - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; int error, create_error; file = alloc_empty_file(flags, cred); @@ -5238,7 +5249,7 @@ EXPORT_SYMBOL(dentry_create); * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir, +int vfs_mknod(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev, struct delegated_inode *delegated_inode) { @@ -5296,7 +5307,7 @@ int filename_mknodat(int dfd, struct filename *name, umode_t mode, unsigned int dev) { struct delegated_inode di = { }; - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; struct dentry *dentry; struct path path; int error; @@ -5380,7 +5391,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d * * In case of an error the dentry is dput() and an ERR_PTR() is returned. */ -struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, +struct dentry *vfs_mkdir(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, struct delegated_inode *delegated_inode) { @@ -5487,7 +5498,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, +int vfs_rmdir(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, struct delegated_inode *delegated_inode) { int error = may_delete_dentry(idmap, dir, dentry, true); @@ -5622,7 +5633,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname) * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir, +int vfs_unlink(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, struct delegated_inode *delegated_inode) { struct inode *target = dentry->d_inode; @@ -5772,7 +5783,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir, +int vfs_symlink(const struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *oldname, struct delegated_inode *delegated_inode) { @@ -5874,7 +5885,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap, +int vfs_link(struct dentry *old_dentry, const struct mnt_idmap *idmap, struct inode *dir, struct dentry *new_dentry, struct delegated_inode *delegated_inode) { @@ -5951,7 +5962,7 @@ EXPORT_SYMBOL(vfs_link); int filename_linkat(int olddfd, struct filename *old, int newdfd, struct filename *new, int flags) { - struct mnt_idmap *idmap; + const struct mnt_idmap *idmap; struct dentry *new_dentry; struct path old_path, new_path; struct delegated_inode delegated_inode = { }; |
