Revert "fs: fold open_check_o_direct into do_dentry_open"

This reverts commit cab64df194667dc5d9d786f0a895f647f5501c0d.

Having vfs_open() in some cases drop the reference to
struct file combined with

error = vfs_open(path, f, cred);
if (error) {
put_filp(f);
return ERR_PTR(error);
}
return f;

is flat-out wrong. It used to be

error = vfs_open(path, f, cred);
if (!error) {
/* from now on we need fput() to dispose of f */
error = open_check_o_direct(f);
if (error) {
fput(f);
f = ERR_PTR(error);
}
} else {
put_filp(f);
f = ERR_PTR(error);
}

and sure, having that open_check_o_direct() boilerplate gotten rid of is
nice, but not that way...

Worse, another call chain (via finish_open()) is FUBAR now wrt
FILE_OPENED handling - in that case we get error returned, with file
already hit by fput() *AND* FILE_OPENED not set. Guess what happens in
path_openat(), when it hits

if (!(opened & FILE_OPENED)) {
BUG_ON(!error);
put_filp(file);
}

The root cause of all that crap is that the callers of do_dentry_open()
have no way to tell which way did it fail; while that could be fixed up
(by passing something like int *opened to do_dentry_open() and have it
marked if we'd called ->open()), it's probably much too late in the
cycle to do so right now.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Al Viro and committed by Linus Torvalds af04fadc 4faa9996

Changed files
+33 -19
fs
+1
fs/internal.h
··· 125 125 int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, 126 126 int flag); 127 127 128 + extern int open_check_o_direct(struct file *f); 128 129 extern int vfs_open(const struct path *, struct file *, const struct cred *); 129 130 extern struct file *filp_clone_open(struct file *); 130 131
+6 -1
fs/namei.c
··· 3367 3367 goto out; 3368 3368 *opened |= FILE_OPENED; 3369 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 3373 if (!error && will_truncate) 3372 3374 error = handle_truncate(file); 3373 3375 out: ··· 3449 3447 error = finish_open(file, child, NULL, opened); 3450 3448 if (error) 3451 3449 goto out2; 3450 + error = open_check_o_direct(file); 3451 + if (error) 3452 + fput(file); 3452 3453 out2: 3453 3454 mnt_drop_write(path.mnt); 3454 3455 out:
+26 -18
fs/open.c
··· 724 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 737 static int do_dentry_open(struct file *f, 728 738 struct inode *inode, 729 739 int (*open)(struct inode *, struct file *), ··· 755 745 if (unlikely(f->f_flags & O_PATH)) { 756 746 f->f_mode = FMODE_PATH; 757 747 f->f_op = &empty_fops; 758 - goto done; 748 + return 0; 759 749 } 760 750 761 751 if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { ··· 808 798 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); 809 799 810 800 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); 811 - done: 812 - /* NB: we're sure to have correct a_ops only after f_op->open */ 813 - error = -EINVAL; 814 - if ((f->f_flags & O_DIRECT) && 815 - (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)) 816 - goto out_fput; 801 + 817 802 return 0; 818 803 819 804 cleanup_all: ··· 822 817 f->f_path.mnt = NULL; 823 818 f->f_path.dentry = NULL; 824 819 f->f_inode = NULL; 825 - return error; 826 - out_fput: 827 - fput(f); 828 820 return error; 829 821 } 830 822 ··· 920 918 BUG_ON(!path->mnt); 921 919 922 920 f = get_empty_filp(); 923 - if (IS_ERR(f)) 924 - return f; 925 - 926 - f->f_flags = flags; 927 - error = vfs_open(path, f, cred); 928 - if (error) { 929 - put_filp(f); 930 - return ERR_PTR(error); 921 + if (!IS_ERR(f)) { 922 + f->f_flags = flags; 923 + error = vfs_open(path, f, cred); 924 + if (!error) { 925 + /* from now on we need fput() to dispose of f */ 926 + error = open_check_o_direct(f); 927 + if (error) { 928 + fput(f); 929 + f = ERR_PTR(error); 930 + } 931 + } else { 932 + put_filp(f); 933 + f = ERR_PTR(error); 934 + } 931 935 } 932 936 return f; 933 937 }