aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-03 14:01:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-03 14:01:28 -0400
commit325e14f97e0c92735d10d9922cbb73ad521de4c4 (patch)
tree13a23482def9abbf5717b9d531218f751c8aea4b
parent874cd339acdfe734b5418e36e3ad40fd4c573155 (diff)
parentaf04fadcaa932d2d804699409d9d96dd5d85ce7f (diff)
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro. - fix io_destroy()/aio_complete() race - the vfs_open() change to get rid of open_check_o_direct() boilerplate was nice, but buggy. Al has a patch avoiding a revert, but that's definitely not a last-day fodder, so for now revert it is... * 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: Revert "fs: fold open_check_o_direct into do_dentry_open" fix io_destroy()/aio_complete() race
-rw-r--r--fs/aio.c3
-rw-r--r--fs/internal.h1
-rw-r--r--fs/namei.c7
-rw-r--r--fs/open.c44
4 files changed, 34 insertions, 21 deletions
diff --git a/fs/aio.c b/fs/aio.c
index 8061d9787e54..49f53516eef0 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -634,9 +634,8 @@ static void free_ioctx_users(struct percpu_ref *ref)
634 while (!list_empty(&ctx->active_reqs)) { 634 while (!list_empty(&ctx->active_reqs)) {
635 req = list_first_entry(&ctx->active_reqs, 635 req = list_first_entry(&ctx->active_reqs,
636 struct aio_kiocb, ki_list); 636 struct aio_kiocb, ki_list);
637
638 list_del_init(&req->ki_list);
639 kiocb_cancel(req); 637 kiocb_cancel(req);
638 list_del_init(&req->ki_list);
640 } 639 }
641 640
642 spin_unlock_irq(&ctx->ctx_lock); 641 spin_unlock_irq(&ctx->ctx_lock);
diff --git a/fs/internal.h b/fs/internal.h
index e08972db0303..980d005b21b4 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -125,6 +125,7 @@ int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
125int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, 125int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
126 int flag); 126 int flag);
127 127
128extern int open_check_o_direct(struct file *f);
128extern int vfs_open(const struct path *, struct file *, const struct cred *); 129extern int vfs_open(const struct path *, struct file *, const struct cred *);
129extern struct file *filp_clone_open(struct file *); 130extern struct file *filp_clone_open(struct file *);
130 131
diff --git a/fs/namei.c b/fs/namei.c
index 186bd2464fd5..4eb916996345 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3367,7 +3367,9 @@ finish_open_created:
3367 goto out; 3367 goto out;
3368 *opened |= FILE_OPENED; 3368 *opened |= FILE_OPENED;
3369opened: 3369opened:
3370 error = ima_file_check(file, op->acc_mode, *opened); 3370 error = open_check_o_direct(file);
3371 if (!error)
3372 error = ima_file_check(file, op->acc_mode, *opened);
3371 if (!error && will_truncate) 3373 if (!error && will_truncate)
3372 error = handle_truncate(file); 3374 error = handle_truncate(file);
3373out: 3375out:
@@ -3447,6 +3449,9 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
3447 error = finish_open(file, child, NULL, opened); 3449 error = finish_open(file, child, NULL, opened);
3448 if (error) 3450 if (error)
3449 goto out2; 3451 goto out2;
3452 error = open_check_o_direct(file);
3453 if (error)
3454 fput(file);
3450out2: 3455out2:
3451 mnt_drop_write(path.mnt); 3456 mnt_drop_write(path.mnt);
3452out: 3457out:
diff --git a/fs/open.c b/fs/open.c
index c5ee7cd60424..d0e955b558ad 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -724,6 +724,16 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
724 return ksys_fchown(fd, user, group); 724 return ksys_fchown(fd, user, group);
725} 725}
726 726
727int open_check_o_direct(struct file *f)
728{
729 /* NB: we're sure to have correct a_ops only after f_op->open */
730 if (f->f_flags & O_DIRECT) {
731 if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
732 return -EINVAL;
733 }
734 return 0;
735}
736
727static int do_dentry_open(struct file *f, 737static int do_dentry_open(struct file *f,
728 struct inode *inode, 738 struct inode *inode,
729 int (*open)(struct inode *, struct file *), 739 int (*open)(struct inode *, struct file *),
@@ -745,7 +755,7 @@ static int do_dentry_open(struct file *f,
745 if (unlikely(f->f_flags & O_PATH)) { 755 if (unlikely(f->f_flags & O_PATH)) {
746 f->f_mode = FMODE_PATH; 756 f->f_mode = FMODE_PATH;
747 f->f_op = &empty_fops; 757 f->f_op = &empty_fops;
748 goto done; 758 return 0;
749 } 759 }
750 760
751 if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { 761 if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
@@ -798,12 +808,7 @@ static int do_dentry_open(struct file *f,
798 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); 808 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
799 809
800 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); 810 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
801done: 811
802 /* NB: we're sure to have correct a_ops only after f_op->open */
803 error = -EINVAL;
804 if ((f->f_flags & O_DIRECT) &&
805 (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO))
806 goto out_fput;
807 return 0; 812 return 0;
808 813
809cleanup_all: 814cleanup_all:
@@ -818,9 +823,6 @@ cleanup_file:
818 f->f_path.dentry = NULL; 823 f->f_path.dentry = NULL;
819 f->f_inode = NULL; 824 f->f_inode = NULL;
820 return error; 825 return error;
821out_fput:
822 fput(f);
823 return error;
824} 826}
825 827
826/** 828/**
@@ -918,14 +920,20 @@ struct file *dentry_open(const struct path *path, int flags,
918 BUG_ON(!path->mnt); 920 BUG_ON(!path->mnt);
919 921
920 f = get_empty_filp(); 922 f = get_empty_filp();
921 if (IS_ERR(f)) 923 if (!IS_ERR(f)) {
922 return f; 924 f->f_flags = flags;
923 925 error = vfs_open(path, f, cred);
924 f->f_flags = flags; 926 if (!error) {
925 error = vfs_open(path, f, cred); 927 /* from now on we need fput() to dispose of f */
926 if (error) { 928 error = open_check_o_direct(f);
927 put_filp(f); 929 if (error) {
928 return ERR_PTR(error); 930 fput(f);
931 f = ERR_PTR(error);
932 }
933 } else {
934 put_filp(f);
935 f = ERR_PTR(error);
936 }
929 } 937 }
930 return f; 938 return f;
931} 939}