Skip to content

Commit 325e14f

Browse files
committed
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
2 parents 874cd33 + af04fad commit 325e14f

File tree

4 files changed

+34
-21
lines changed

4 files changed

+34
-21
lines changed

fs/aio.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,9 +634,8 @@ static void free_ioctx_users(struct percpu_ref *ref)
634634
while (!list_empty(&ctx->active_reqs)) {
635635
req = list_first_entry(&ctx->active_reqs,
636636
struct aio_kiocb, ki_list);
637-
638-
list_del_init(&req->ki_list);
639637
kiocb_cancel(req);
638+
list_del_init(&req->ki_list);
640639
}
641640

642641
spin_unlock_irq(&ctx->ctx_lock);

fs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
125125
int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
126126
int flag);
127127

128+
extern int open_check_o_direct(struct file *f);
128129
extern int vfs_open(const struct path *, struct file *, const struct cred *);
129130
extern struct file *filp_clone_open(struct file *);
130131

fs/namei.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3367,7 +3367,9 @@ static int do_last(struct nameidata *nd,
33673367
goto out;
33683368
*opened |= FILE_OPENED;
33693369
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);
33713373
if (!error && will_truncate)
33723374
error = handle_truncate(file);
33733375
out:
@@ -3447,6 +3449,9 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
34473449
error = finish_open(file, child, NULL, opened);
34483450
if (error)
34493451
goto out2;
3452+
error = open_check_o_direct(file);
3453+
if (error)
3454+
fput(file);
34503455
out2:
34513456
mnt_drop_write(path.mnt);
34523457
out:

fs/open.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,16 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
724724
return ksys_fchown(fd, user, group);
725725
}
726726

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+
727737
static int do_dentry_open(struct file *f,
728738
struct inode *inode,
729739
int (*open)(struct inode *, struct file *),
@@ -745,7 +755,7 @@ static int do_dentry_open(struct file *f,
745755
if (unlikely(f->f_flags & O_PATH)) {
746756
f->f_mode = FMODE_PATH;
747757
f->f_op = &empty_fops;
748-
goto done;
758+
return 0;
749759
}
750760

751761
if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
@@ -798,12 +808,7 @@ static int do_dentry_open(struct file *f,
798808
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
799809

800810
file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
801-
done:
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;
811+
807812
return 0;
808813

809814
cleanup_all:
@@ -818,9 +823,6 @@ static int do_dentry_open(struct file *f,
818823
f->f_path.dentry = NULL;
819824
f->f_inode = NULL;
820825
return error;
821-
out_fput:
822-
fput(f);
823-
return error;
824826
}
825827

826828
/**
@@ -918,14 +920,20 @@ struct file *dentry_open(const struct path *path, int flags,
918920
BUG_ON(!path->mnt);
919921

920922
f = get_empty_filp();
921-
if (IS_ERR(f))
922-
return f;
923-
924-
f->f_flags = flags;
925-
error = vfs_open(path, f, cred);
926-
if (error) {
927-
put_filp(f);
928-
return ERR_PTR(error);
923+
if (!IS_ERR(f)) {
924+
f->f_flags = flags;
925+
error = vfs_open(path, f, cred);
926+
if (!error) {
927+
/* from now on we need fput() to dispose of f */
928+
error = open_check_o_direct(f);
929+
if (error) {
930+
fput(f);
931+
f = ERR_PTR(error);
932+
}
933+
} else {
934+
put_filp(f);
935+
f = ERR_PTR(error);
936+
}
929937
}
930938
return f;
931939
}

0 commit comments

Comments
 (0)