diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-03 14:01:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-03 14:01:28 -0400 |
commit | 325e14f97e0c92735d10d9922cbb73ad521de4c4 (patch) | |
tree | 13a23482def9abbf5717b9d531218f751c8aea4b | |
parent | 874cd339acdfe734b5418e36e3ad40fd4c573155 (diff) | |
parent | af04fadcaa932d2d804699409d9d96dd5d85ce7f (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.c | 3 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/namei.c | 7 | ||||
-rw-r--r-- | fs/open.c | 44 |
4 files changed, 34 insertions, 21 deletions
@@ -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); | |||
125 | int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, | 125 | int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, |
126 | int flag); | 126 | int flag); |
127 | 127 | ||
128 | extern int open_check_o_direct(struct file *f); | ||
128 | extern int vfs_open(const struct path *, struct file *, const struct cred *); | 129 | extern int vfs_open(const struct path *, struct file *, const struct cred *); |
129 | extern struct file *filp_clone_open(struct file *); | 130 | extern 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; |
3369 | opened: | 3369 | opened: |
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); |
3373 | out: | 3375 | out: |
@@ -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); | ||
3450 | out2: | 3455 | out2: |
3451 | mnt_drop_write(path.mnt); | 3456 | mnt_drop_write(path.mnt); |
3452 | out: | 3457 | out: |
@@ -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 | ||
727 | int 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 | |||
727 | static int do_dentry_open(struct file *f, | 737 | static 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); |
801 | done: | 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 | ||
809 | cleanup_all: | 814 | cleanup_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; |
821 | out_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 | } |