From b4e7a7a88b5d060650094b8d3454bc521d669f6a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 8 Jun 2018 11:17:54 -0400 Subject: drm_mode_create_lease_ioctl(): fix open-coded filp_clone_open() Failure of ->open() should *not* be followed by fput(). Fixed by using filp_clone_open(), which gets the cleanups right. Cc: stable@vger.kernel.org Acked-by: Linus Torvalds Signed-off-by: Al Viro --- include/linux/fs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 5c91108846db..aa9b4c169ed2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2422,6 +2422,7 @@ extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int, umode_t); extern struct file * dentry_open(const struct path *, int, const struct cred *); +extern struct file *filp_clone_open(struct file *); extern int filp_close(struct file *, fl_owner_t id); extern struct filename *getname_flags(const char __user *, int, int *); -- cgit v1.2.3 From 19f391eb05b8b005f2907ddc8f284487b446abf3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 8 Jun 2018 11:19:32 -0400 Subject: turn filp_clone_open() into inline wrapper for dentry_open() it's exactly the same thing as dentry_open(&file->f_path, file->f_flags, file->f_cred) ... and rename it to file_clone_open(), while we are at it. 'filp' naming convention is bogus; sure, it's "file pointer", but we generally don't do that kind of Hungarian notation. Some of the instances have too many callers to touch, but this one has only two, so let's sanitize it while we can... Acked-by: Linus Torvalds Signed-off-by: Al Viro --- drivers/gpu/drm/drm_lease.c | 2 +- fs/binfmt_misc.c | 2 +- fs/open.c | 20 -------------------- include/linux/fs.h | 5 ++++- 4 files changed, 6 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index d638c0fb3418..b54fb78a283c 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -553,7 +553,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, /* Clone the lessor file to create a new file for us */ DRM_DEBUG_LEASE("Allocating lease file\n"); - lessee_file = filp_clone_open(lessor_file); + lessee_file = file_clone_open(lessor_file); if (IS_ERR(lessee_file)) { ret = PTR_ERR(lessee_file); goto out_lessee; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 4b5fff31ef27..aa4a7a23ff99 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -205,7 +205,7 @@ static int load_misc_binary(struct linux_binprm *bprm) goto error; if (fmt->flags & MISC_FMT_OPEN_FILE) { - interp_file = filp_clone_open(fmt->interp_file); + interp_file = file_clone_open(fmt->interp_file); if (!IS_ERR(interp_file)) deny_write_access(interp_file); } else { diff --git a/fs/open.c b/fs/open.c index d0e955b558ad..76c56966e297 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1063,26 +1063,6 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, } EXPORT_SYMBOL(file_open_root); -struct file *filp_clone_open(struct file *oldfile) -{ - struct file *file; - int retval; - - file = get_empty_filp(); - if (IS_ERR(file)) - return file; - - file->f_flags = oldfile->f_flags; - retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred); - if (retval) { - put_filp(file); - return ERR_PTR(retval); - } - - return file; -} -EXPORT_SYMBOL(filp_clone_open); - long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; diff --git a/include/linux/fs.h b/include/linux/fs.h index aa9b4c169ed2..c4ca4c9c1130 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2422,7 +2422,10 @@ extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int, umode_t); extern struct file * dentry_open(const struct path *, int, const struct cred *); -extern struct file *filp_clone_open(struct file *); +static inline struct file *file_clone_open(struct file *file) +{ + return dentry_open(&file->f_path, file->f_flags, file->f_cred); +} extern int filp_close(struct file *, fl_owner_t id); extern struct filename *getname_flags(const char __user *, int, int *); -- cgit v1.2.3 From c9c554f21490bbc96cc554f80024d27d09670480 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Jul 2018 14:19:04 -0400 Subject: alloc_file(): switch to passing O_... flags instead of FMODE_... mode ... so that it could set both ->f_flags and ->f_mode, without callers having to set ->f_flags manually. Signed-off-by: Al Viro --- drivers/misc/cxl/api.c | 3 +-- drivers/scsi/cxlflash/ocxl_hw.c | 3 +-- fs/aio.c | 8 ++------ fs/anon_inodes.c | 3 +-- fs/file_table.c | 17 +++++++++-------- fs/hugetlbfs/inode.c | 3 +-- fs/pipe.c | 8 ++++---- include/linux/file.h | 2 +- ipc/shm.c | 8 ++++---- mm/memfd.c | 2 +- mm/shmem.c | 3 +-- net/socket.c | 3 +-- 12 files changed, 27 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 6b16946f9b05..0b5cb6cf91a0 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -102,12 +102,11 @@ static struct file *cxl_getfile(const char *name, path.mnt = mntget(cxl_vfs_mount); d_instantiate(path.dentry, inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) { path_put(&path); goto err_fs; } - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; return file; diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 497a68389461..99bb393a8a34 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -129,7 +129,7 @@ static struct file *ocxlflash_getfile(struct device *dev, const char *name, path.mnt = mntget(ocxlflash_vfs_mount); d_instantiate(path.dentry, inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) { rc = PTR_ERR(file); dev_err(dev, "%s: alloc_file failed rc=%d\n", @@ -138,7 +138,6 @@ static struct file *ocxlflash_getfile(struct device *dev, const char *name, goto err3; } - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; out: return file; diff --git a/fs/aio.c b/fs/aio.c index e1d20124ec0e..9eea53887d6c 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -234,13 +234,9 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) path.mnt = mntget(aio_mnt); d_instantiate(path.dentry, inode); - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &aio_ring_fops); - if (IS_ERR(file)) { + file = alloc_file(&path, O_RDWR, &aio_ring_fops); + if (IS_ERR(file)) path_put(&path); - return file; - } - - file->f_flags = O_RDWR; return file; } diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 3168ee4e77f4..6b235ab1df6c 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -102,12 +102,11 @@ struct file *anon_inode_getfile(const char *name, d_instantiate(path.dentry, anon_inode_inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; return file; diff --git a/fs/file_table.c b/fs/file_table.c index eee7cf629e52..086c3f5ec31a 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -153,10 +153,10 @@ over: * alloc_file - allocate and initialize a 'struct file' * * @path: the (dentry, vfsmount) pair for the new file - * @mode: the mode with which the new file will be opened + * @flags: O_... flags with which the new file will be opened * @fop: the 'struct file_operations' for the new file */ -struct file *alloc_file(const struct path *path, fmode_t mode, +struct file *alloc_file(const struct path *path, int flags, const struct file_operations *fop) { struct file *file; @@ -165,19 +165,20 @@ struct file *alloc_file(const struct path *path, fmode_t mode, if (IS_ERR(file)) return file; + file->f_mode = OPEN_FMODE(flags); + file->f_flags = flags; file->f_path = *path; file->f_inode = path->dentry->d_inode; file->f_mapping = path->dentry->d_inode->i_mapping; file->f_wb_err = filemap_sample_wb_err(file->f_mapping); - if ((mode & FMODE_READ) && + if ((file->f_mode & FMODE_READ) && likely(fop->read || fop->read_iter)) - mode |= FMODE_CAN_READ; - if ((mode & FMODE_WRITE) && + file->f_mode |= FMODE_CAN_READ; + if ((file->f_mode & FMODE_WRITE) && likely(fop->write || fop->write_iter)) - mode |= FMODE_CAN_WRITE; - file->f_mode = mode; + file->f_mode |= FMODE_CAN_WRITE; file->f_op = fop; - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(path->dentry->d_inode); return file; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index d508c7844681..71aed47422e2 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -1375,8 +1375,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, inode->i_size = size; clear_nlink(inode); - file = alloc_file(&path, FMODE_WRITE | FMODE_READ, - &hugetlbfs_file_operations); + file = alloc_file(&path, O_RDWR, &hugetlbfs_file_operations); if (IS_ERR(file)) goto out_dentry; /* inode is already attached */ diff --git a/fs/pipe.c b/fs/pipe.c index 9405e455f5b1..1909422e5a78 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -760,16 +760,17 @@ int create_pipe_files(struct file **res, int flags) d_instantiate(path.dentry, inode); - f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops); + f = alloc_file(&path, O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)), + &pipefifo_fops); if (IS_ERR(f)) { err = PTR_ERR(f); goto err_dentry; } - f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)); f->private_data = inode->i_pipe; - res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops); + res[0] = alloc_file(&path, O_RDONLY | (flags & O_NONBLOCK), + &pipefifo_fops); if (IS_ERR(res[0])) { put_pipe_info(inode, inode->i_pipe); fput(f); @@ -778,7 +779,6 @@ int create_pipe_files(struct file **res, int flags) path_get(&path); res[0]->private_data = inode->i_pipe; - res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK); res[1] = f; return 0; diff --git a/include/linux/file.h b/include/linux/file.h index 279720db984a..6d34a1262b31 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -18,7 +18,7 @@ struct file_operations; struct vfsmount; struct dentry; struct path; -extern struct file *alloc_file(const struct path *, fmode_t mode, +extern struct file *alloc_file(const struct path *, int flags, const struct file_operations *fop); static inline void fput_light(struct file *file, int fput_needed) diff --git a/ipc/shm.c b/ipc/shm.c index 051a3e1fb8df..c702abd578a7 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1362,7 +1362,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, struct ipc_namespace *ns; struct shm_file_data *sfd; struct path path; - fmode_t f_mode; + int f_flags; unsigned long populate = 0; err = -EINVAL; @@ -1395,11 +1395,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, if (shmflg & SHM_RDONLY) { prot = PROT_READ; acc_mode = S_IRUGO; - f_mode = FMODE_READ; + f_flags = O_RDONLY; } else { prot = PROT_READ | PROT_WRITE; acc_mode = S_IRUGO | S_IWUGO; - f_mode = FMODE_READ | FMODE_WRITE; + f_flags = O_RDWR; } if (shmflg & SHM_EXEC) { prot |= PROT_EXEC; @@ -1449,7 +1449,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, goto out_nattch; } - file = alloc_file(&path, f_mode, + file = alloc_file(&path, f_flags, is_file_hugepages(shp->shm_file) ? &shm_file_operations_huge : &shm_file_operations); diff --git a/mm/memfd.c b/mm/memfd.c index 27069518e3c5..2bb5e257080e 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -326,7 +326,7 @@ SYSCALL_DEFINE2(memfd_create, goto err_fd; } file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; - file->f_flags |= O_RDWR | O_LARGEFILE; + file->f_flags |= O_LARGEFILE; if (flags & MFD_ALLOW_SEALING) { file_seals = memfd_file_seals_ptr(file); diff --git a/mm/shmem.c b/mm/shmem.c index 2cab84403055..84844e52bf24 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3942,8 +3942,7 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name, l if (IS_ERR(res)) goto put_path; - res = alloc_file(&path, FMODE_WRITE | FMODE_READ, - &shmem_file_operations); + res = alloc_file(&path, O_RDWR, &shmem_file_operations); if (IS_ERR(res)) goto put_path; diff --git a/net/socket.c b/net/socket.c index 8a109012608a..2cdbe8f71b7f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -411,7 +411,7 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) d_instantiate(path.dentry, SOCK_INODE(sock)); - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, + file = alloc_file(&path, O_RDWR | (flags & O_NONBLOCK), &socket_file_ops); if (IS_ERR(file)) { /* drop dentry, keep inode for a bit */ @@ -423,7 +423,6 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) } sock->file = file; - file->f_flags = O_RDWR | (flags & O_NONBLOCK); file->private_data = sock; return file; } -- cgit v1.2.3 From e3f20ae21079ecac282df65d83865c5771f4bca0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Jul 2018 13:25:29 -0400 Subject: security_file_open(): lose cred argument Acked-by: Linus Torvalds Signed-off-by: Al Viro --- fs/open.c | 2 +- include/linux/security.h | 5 ++--- security/security.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/open.c b/fs/open.c index 0a9f00b7f3d5..4c65edefa487 100644 --- a/fs/open.c +++ b/fs/open.c @@ -776,7 +776,7 @@ static int do_dentry_open(struct file *f, goto cleanup_all; } - error = security_file_open(f, f->f_cred); + error = security_file_open(f); if (error) goto cleanup_all; diff --git a/include/linux/security.h b/include/linux/security.h index 63030c85ee19..88d30fc975e7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -309,7 +309,7 @@ void security_file_set_fowner(struct file *file); int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig); int security_file_receive(struct file *file); -int security_file_open(struct file *file, const struct cred *cred); +int security_file_open(struct file *file); int security_task_alloc(struct task_struct *task, unsigned long clone_flags); void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); @@ -858,8 +858,7 @@ static inline int security_file_receive(struct file *file) return 0; } -static inline int security_file_open(struct file *file, - const struct cred *cred) +static inline int security_file_open(struct file *file) { return 0; } diff --git a/security/security.c b/security/security.c index 68f46d849abe..235b35f58a65 100644 --- a/security/security.c +++ b/security/security.c @@ -970,11 +970,11 @@ int security_file_receive(struct file *file) return call_int_hook(file_receive, 0, file); } -int security_file_open(struct file *file, const struct cred *cred) +int security_file_open(struct file *file) { int ret; - ret = call_int_hook(file_open, 0, file, cred); + ret = call_int_hook(file_open, 0, file, file->f_cred); if (ret) return ret; -- cgit v1.2.3 From 9481769208b5e39b871ae4e89f5328c776ec38dc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Jul 2018 14:13:18 -0400 Subject: ->file_open(): lose cred argument Acked-by: Linus Torvalds Signed-off-by: Al Viro --- include/linux/lsm_hooks.h | 2 +- security/apparmor/lsm.c | 4 ++-- security/security.c | 2 +- security/selinux/hooks.c | 4 ++-- security/smack/smack_lsm.c | 6 +++--- security/tomoyo/tomoyo.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 8f1131c8dd54..a8ee106b865d 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1569,7 +1569,7 @@ union security_list_options { int (*file_send_sigiotask)(struct task_struct *tsk, struct fown_struct *fown, int sig); int (*file_receive)(struct file *file); - int (*file_open)(struct file *file, const struct cred *cred); + int (*file_open)(struct file *file); int (*task_alloc)(struct task_struct *task, unsigned long clone_flags); void (*task_free)(struct task_struct *task); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 74f17376202b..8b8b70620bbe 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -395,7 +395,7 @@ static int apparmor_inode_getattr(const struct path *path) return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR); } -static int apparmor_file_open(struct file *file, const struct cred *cred) +static int apparmor_file_open(struct file *file) { struct aa_file_ctx *fctx = file_ctx(file); struct aa_label *label; @@ -414,7 +414,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) return 0; } - label = aa_get_newest_cred_label(cred); + label = aa_get_newest_cred_label(file->f_cred); if (!unconfined(label)) { struct inode *inode = file_inode(file); struct path_cond cond = { inode->i_uid, inode->i_mode }; diff --git a/security/security.c b/security/security.c index 235b35f58a65..5dce67070cdf 100644 --- a/security/security.c +++ b/security/security.c @@ -974,7 +974,7 @@ int security_file_open(struct file *file) { int ret; - ret = call_int_hook(file_open, 0, file, file->f_cred); + ret = call_int_hook(file_open, 0, file); if (ret) return ret; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2b5ee5fbd652..18006be15713 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3862,7 +3862,7 @@ static int selinux_file_receive(struct file *file) return file_has_perm(cred, file, file_to_av(file)); } -static int selinux_file_open(struct file *file, const struct cred *cred) +static int selinux_file_open(struct file *file) { struct file_security_struct *fsec; struct inode_security_struct *isec; @@ -3886,7 +3886,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred) * new inode label or new policy. * This check is not redundant - do not remove. */ - return file_path_has_perm(cred, file, open_file_to_av(file)); + return file_path_has_perm(file->f_cred, file, open_file_to_av(file)); } /* task security operations */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7ad226018f51..e7b6c012431d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1927,9 +1927,9 @@ static int smack_file_receive(struct file *file) * * Returns 0 */ -static int smack_file_open(struct file *file, const struct cred *cred) +static int smack_file_open(struct file *file) { - struct task_smack *tsp = cred->security; + struct task_smack *tsp = file->f_cred->security; struct inode *inode = file_inode(file); struct smk_audit_info ad; int rc; @@ -1937,7 +1937,7 @@ static int smack_file_open(struct file *file, const struct cred *cred) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad); - rc = smk_bu_credfile(cred, file, MAY_READ, rc); + rc = smk_bu_credfile(file->f_cred, file, MAY_READ, rc); return rc; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 213b8c593668..9f932e2d6852 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -320,7 +320,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_file_open(struct file *f, const struct cred *cred) +static int tomoyo_file_open(struct file *f) { int flags = f->f_flags; /* Don't check read permission here if called from do_execve(). */ -- cgit v1.2.3 From f5d11409e61dadf1f9af91b22bbedc28a60a2e2c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Jul 2018 02:35:08 -0400 Subject: introduce FMODE_OPENED basically, "is that instance set up enough for regular fput(), or do we want put_filp() for that one". NOTE: the only alloc_file() caller that could be followed by put_filp() is in arch/ia64/kernel/perfmon.c, which is (Kconfig-level) broken. Acked-by: Linus Torvalds Signed-off-by: Al Viro --- fs/file_table.c | 1 + fs/open.c | 3 ++- include/linux/fs.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/file_table.c b/fs/file_table.c index 705f486f7007..d664d10acfeb 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -176,6 +176,7 @@ struct file *alloc_file(const struct path *path, int flags, if ((file->f_mode & FMODE_WRITE) && likely(fop->write || fop->write_iter)) file->f_mode |= FMODE_CAN_WRITE; + file->f_mode |= FMODE_OPENED; file->f_op = fop; if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(path->dentry->d_inode); diff --git a/fs/open.c b/fs/open.c index 4c65edefa487..f3c6cb6a57b9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -749,7 +749,7 @@ static int do_dentry_open(struct file *f, f->f_wb_err = filemap_sample_wb_err(f->f_mapping); if (unlikely(f->f_flags & O_PATH)) { - f->f_mode = FMODE_PATH; + f->f_mode = FMODE_PATH | FMODE_OPENED; f->f_op = &empty_fops; return 0; } @@ -793,6 +793,7 @@ static int do_dentry_open(struct file *f, if (error) goto cleanup_all; } + f->f_mode |= FMODE_OPENED; if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); if ((f->f_mode & FMODE_READ) && diff --git a/include/linux/fs.h b/include/linux/fs.h index c4ca4c9c1130..05f34726e29c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -148,6 +148,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* Has write method(s) */ #define FMODE_CAN_WRITE ((__force fmode_t)0x40000) +#define FMODE_OPENED ((__force fmode_t)0x80000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) -- cgit v1.2.3 From 4d27f3266f14e4d1d13125ce32cb49a40f3122c3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Jul 2018 11:14:39 -0400 Subject: fold put_filp() into fput() Just check FMODE_OPENED in __fput() and be done with that... Acked-by: Linus Torvalds Signed-off-by: Al Viro --- fs/file_table.c | 15 +++++---------- fs/namei.c | 4 ++-- fs/open.c | 11 +++-------- include/linux/file.h | 1 - 4 files changed, 10 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/fs/file_table.c b/fs/file_table.c index d664d10acfeb..9b70ed2bbc4e 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -192,6 +192,9 @@ static void __fput(struct file *file) struct vfsmount *mnt = file->f_path.mnt; struct inode *inode = file->f_inode; + if (unlikely(!(file->f_mode & FMODE_OPENED))) + goto out; + might_sleep(); fsnotify_close(file); @@ -221,12 +224,10 @@ static void __fput(struct file *file) put_write_access(inode); __mnt_drop_write(mnt); } - file->f_path.dentry = NULL; - file->f_path.mnt = NULL; - file->f_inode = NULL; - file_free(file); dput(dentry); mntput(mnt); +out: + file_free(file); } static LLIST_HEAD(delayed_fput_list); @@ -301,12 +302,6 @@ void __fput_sync(struct file *file) EXPORT_SYMBOL(fput); -void put_filp(struct file *file) -{ - if (atomic_long_dec_and_test(&file->f_count)) - file_free(file); -} - void __init files_init(void) { filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, diff --git a/fs/namei.c b/fs/namei.c index 3cf02804d5ff..503c4b968415 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3531,7 +3531,7 @@ static struct file *path_openat(struct nameidata *nd, s = path_init(nd, flags); if (IS_ERR(s)) { - put_filp(file); + fput(file); return ERR_CAST(s); } while (!(error = link_path_walk(s, nd)) && @@ -3547,7 +3547,7 @@ static struct file *path_openat(struct nameidata *nd, out2: if (!(opened & FILE_OPENED)) { BUG_ON(!error); - put_filp(file); + fput(file); } if (unlikely(error)) { if (error == -EOPENSTALE) { diff --git a/fs/open.c b/fs/open.c index f3c6cb6a57b9..3d09b823f12b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -921,15 +921,10 @@ struct file *dentry_open(const struct path *path, int flags, f = alloc_empty_file(flags, cred); if (!IS_ERR(f)) { error = vfs_open(path, f); - if (!error) { - /* from now on we need fput() to dispose of f */ + if (!error) error = open_check_o_direct(f); - if (error) { - fput(f); - f = ERR_PTR(error); - } - } else { - put_filp(f); + if (error) { + fput(f); f = ERR_PTR(error); } } diff --git a/include/linux/file.h b/include/linux/file.h index 6d34a1262b31..aed45d69811e 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -78,7 +78,6 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern void set_close_on_exec(unsigned int fd, int flag); extern bool get_close_on_exec(unsigned int fd); -extern void put_filp(struct file *); extern int get_unused_fd_flags(unsigned flags); extern void put_unused_fd(unsigned int fd); -- cgit v1.2.3 From 2abc77af89e17582db9039293c8ac881c8c96d79 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 12 Jul 2018 11:18:42 -0400 Subject: new helper: open_with_fake_path() open a file by given inode, faking ->f_path. Use with shitloads of caution - at the very least you'd damn better make sure that some dentry alias of that inode is pinned down by the path in question. Again, this is no general-purpose interface and I hope it will eventually go away. Right now overlayfs wants something like that, but nothing else should. Any out-of-tree code with bright idea of using this one *will* eventually get hurt, with zero notice and great delight on my part. I refuse to use EXPORT_SYMBOL_GPL(), especially in situations when it's really EXPORT_SYMBOL_DONT_USE_IT(), but don't take that export as "you are welcome to use it". Signed-off-by: Al Viro --- fs/open.c | 18 ++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 20 insertions(+) (limited to 'include/linux') diff --git a/fs/open.c b/fs/open.c index ee893240d199..dd15711eb658 100644 --- a/fs/open.c +++ b/fs/open.c @@ -925,6 +925,24 @@ struct file *dentry_open(const struct path *path, int flags, } EXPORT_SYMBOL(dentry_open); +struct file *open_with_fake_path(const struct path *path, int flags, + struct inode *inode, const struct cred *cred) +{ + struct file *f = alloc_empty_file(flags, cred); + if (!IS_ERR(f)) { + int error; + + f->f_path = *path; + error = do_dentry_open(f, inode, NULL); + if (error) { + fput(f); + f = ERR_PTR(error); + } + } + return f; +} +EXPORT_SYMBOL(open_with_fake_path); + static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; diff --git a/include/linux/fs.h b/include/linux/fs.h index 05f34726e29c..4ff7b7012186 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2424,6 +2424,8 @@ extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int, umode_t); extern struct file * dentry_open(const struct path *, int, const struct cred *); +extern struct file * open_with_fake_path(const struct path *, int, + struct inode*, const struct cred *); static inline struct file *file_clone_open(struct file *file) { return dentry_open(&file->f_path, file->f_flags, file->f_cred); -- cgit v1.2.3