Skip to content

Commit b91db6a

Browse files
committed
Merge tag 'for-5.15/io_uring-vfs-2021-08-30' of git://git.kernel.dk/linux-block
Pull io_uring mkdirat/symlinkat/linkat support from Jens Axboe: "This adds io_uring support for mkdirat, symlinkat, and linkat" * tag 'for-5.15/io_uring-vfs-2021-08-30' of git://git.kernel.dk/linux-block: io_uring: add support for IORING_OP_LINKAT io_uring: add support for IORING_OP_SYMLINKAT io_uring: add support for IORING_OP_MKDIRAT namei: update do_*() helpers to return ints namei: make do_linkat() take struct filename namei: add getname_uflags() namei: make do_symlinkat() take struct filename namei: make do_mknodat() take struct filename namei: make do_mkdirat() take struct filename namei: change filename_parentat() calling conventions namei: ignore ERR/NULL names in putname()
2 parents 3b629f8 + cf30da9 commit b91db6a

File tree

6 files changed

+348
-110
lines changed

6 files changed

+348
-110
lines changed

fs/exec.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,10 +2070,8 @@ SYSCALL_DEFINE5(execveat,
20702070
const char __user *const __user *, envp,
20712071
int, flags)
20722072
{
2073-
int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
2074-
20752073
return do_execveat(fd,
2076-
getname_flags(filename, lookup_flags, NULL),
2074+
getname_uflags(filename, flags),
20772075
argv, envp, flags);
20782076
}
20792077

@@ -2091,10 +2089,8 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd,
20912089
const compat_uptr_t __user *, envp,
20922090
int, flags)
20932091
{
2094-
int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
2095-
20962092
return compat_do_execveat(fd,
2097-
getname_flags(filename, lookup_flags, NULL),
2093+
getname_uflags(filename, flags),
20982094
argv, envp, flags);
20992095
}
21002096
#endif

fs/internal.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
7171
struct path *path, struct path *root);
7272
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
7373
const char *, unsigned int, struct path *);
74-
long do_rmdir(int dfd, struct filename *name);
75-
long do_unlinkat(int dfd, struct filename *name);
74+
int do_rmdir(int dfd, struct filename *name);
75+
int do_unlinkat(int dfd, struct filename *name);
7676
int may_linkat(struct user_namespace *mnt_userns, struct path *link);
7777
int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
7878
struct filename *newname, unsigned int flags);
79+
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
80+
int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
81+
int do_linkat(int olddfd, struct filename *old, int newdfd,
82+
struct filename *new, int flags);
7983

8084
/*
8185
* namespace.c

fs/io_uring.c

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,29 @@ struct io_unlink {
667667
struct filename *filename;
668668
};
669669

670+
struct io_mkdir {
671+
struct file *file;
672+
int dfd;
673+
umode_t mode;
674+
struct filename *filename;
675+
};
676+
677+
struct io_symlink {
678+
struct file *file;
679+
int new_dfd;
680+
struct filename *oldpath;
681+
struct filename *newpath;
682+
};
683+
684+
struct io_hardlink {
685+
struct file *file;
686+
int old_dfd;
687+
int new_dfd;
688+
struct filename *oldpath;
689+
struct filename *newpath;
690+
int flags;
691+
};
692+
670693
struct io_completion {
671694
struct file *file;
672695
u32 cflags;
@@ -826,6 +849,9 @@ struct io_kiocb {
826849
struct io_shutdown shutdown;
827850
struct io_rename rename;
828851
struct io_unlink unlink;
852+
struct io_mkdir mkdir;
853+
struct io_symlink symlink;
854+
struct io_hardlink hardlink;
829855
/* use only after cleaning per-op data, see io_clean_op() */
830856
struct io_completion compl;
831857
};
@@ -1037,6 +1063,9 @@ static const struct io_op_def io_op_defs[] = {
10371063
},
10381064
[IORING_OP_RENAMEAT] = {},
10391065
[IORING_OP_UNLINKAT] = {},
1066+
[IORING_OP_MKDIRAT] = {},
1067+
[IORING_OP_SYMLINKAT] = {},
1068+
[IORING_OP_LINKAT] = {},
10401069
};
10411070

10421071
/* requests with any of those set should undergo io_disarm_next() */
@@ -3680,6 +3709,149 @@ static int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
36803709
return 0;
36813710
}
36823711

3712+
static int io_mkdirat_prep(struct io_kiocb *req,
3713+
const struct io_uring_sqe *sqe)
3714+
{
3715+
struct io_mkdir *mkd = &req->mkdir;
3716+
const char __user *fname;
3717+
3718+
if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
3719+
return -EINVAL;
3720+
if (sqe->ioprio || sqe->off || sqe->rw_flags || sqe->buf_index ||
3721+
sqe->splice_fd_in)
3722+
return -EINVAL;
3723+
if (unlikely(req->flags & REQ_F_FIXED_FILE))
3724+
return -EBADF;
3725+
3726+
mkd->dfd = READ_ONCE(sqe->fd);
3727+
mkd->mode = READ_ONCE(sqe->len);
3728+
3729+
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
3730+
mkd->filename = getname(fname);
3731+
if (IS_ERR(mkd->filename))
3732+
return PTR_ERR(mkd->filename);
3733+
3734+
req->flags |= REQ_F_NEED_CLEANUP;
3735+
return 0;
3736+
}
3737+
3738+
static int io_mkdirat(struct io_kiocb *req, int issue_flags)
3739+
{
3740+
struct io_mkdir *mkd = &req->mkdir;
3741+
int ret;
3742+
3743+
if (issue_flags & IO_URING_F_NONBLOCK)
3744+
return -EAGAIN;
3745+
3746+
ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
3747+
3748+
req->flags &= ~REQ_F_NEED_CLEANUP;
3749+
if (ret < 0)
3750+
req_set_fail(req);
3751+
io_req_complete(req, ret);
3752+
return 0;
3753+
}
3754+
3755+
static int io_symlinkat_prep(struct io_kiocb *req,
3756+
const struct io_uring_sqe *sqe)
3757+
{
3758+
struct io_symlink *sl = &req->symlink;
3759+
const char __user *oldpath, *newpath;
3760+
3761+
if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
3762+
return -EINVAL;
3763+
if (sqe->ioprio || sqe->len || sqe->rw_flags || sqe->buf_index ||
3764+
sqe->splice_fd_in)
3765+
return -EINVAL;
3766+
if (unlikely(req->flags & REQ_F_FIXED_FILE))
3767+
return -EBADF;
3768+
3769+
sl->new_dfd = READ_ONCE(sqe->fd);
3770+
oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
3771+
newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
3772+
3773+
sl->oldpath = getname(oldpath);
3774+
if (IS_ERR(sl->oldpath))
3775+
return PTR_ERR(sl->oldpath);
3776+
3777+
sl->newpath = getname(newpath);
3778+
if (IS_ERR(sl->newpath)) {
3779+
putname(sl->oldpath);
3780+
return PTR_ERR(sl->newpath);
3781+
}
3782+
3783+
req->flags |= REQ_F_NEED_CLEANUP;
3784+
return 0;
3785+
}
3786+
3787+
static int io_symlinkat(struct io_kiocb *req, int issue_flags)
3788+
{
3789+
struct io_symlink *sl = &req->symlink;
3790+
int ret;
3791+
3792+
if (issue_flags & IO_URING_F_NONBLOCK)
3793+
return -EAGAIN;
3794+
3795+
ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
3796+
3797+
req->flags &= ~REQ_F_NEED_CLEANUP;
3798+
if (ret < 0)
3799+
req_set_fail(req);
3800+
io_req_complete(req, ret);
3801+
return 0;
3802+
}
3803+
3804+
static int io_linkat_prep(struct io_kiocb *req,
3805+
const struct io_uring_sqe *sqe)
3806+
{
3807+
struct io_hardlink *lnk = &req->hardlink;
3808+
const char __user *oldf, *newf;
3809+
3810+
if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
3811+
return -EINVAL;
3812+
if (sqe->ioprio || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
3813+
return -EINVAL;
3814+
if (unlikely(req->flags & REQ_F_FIXED_FILE))
3815+
return -EBADF;
3816+
3817+
lnk->old_dfd = READ_ONCE(sqe->fd);
3818+
lnk->new_dfd = READ_ONCE(sqe->len);
3819+
oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
3820+
newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
3821+
lnk->flags = READ_ONCE(sqe->hardlink_flags);
3822+
3823+
lnk->oldpath = getname(oldf);
3824+
if (IS_ERR(lnk->oldpath))
3825+
return PTR_ERR(lnk->oldpath);
3826+
3827+
lnk->newpath = getname(newf);
3828+
if (IS_ERR(lnk->newpath)) {
3829+
putname(lnk->oldpath);
3830+
return PTR_ERR(lnk->newpath);
3831+
}
3832+
3833+
req->flags |= REQ_F_NEED_CLEANUP;
3834+
return 0;
3835+
}
3836+
3837+
static int io_linkat(struct io_kiocb *req, int issue_flags)
3838+
{
3839+
struct io_hardlink *lnk = &req->hardlink;
3840+
int ret;
3841+
3842+
if (issue_flags & IO_URING_F_NONBLOCK)
3843+
return -EAGAIN;
3844+
3845+
ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
3846+
lnk->newpath, lnk->flags);
3847+
3848+
req->flags &= ~REQ_F_NEED_CLEANUP;
3849+
if (ret < 0)
3850+
req_set_fail(req);
3851+
io_req_complete(req, ret);
3852+
return 0;
3853+
}
3854+
36833855
static int io_shutdown_prep(struct io_kiocb *req,
36843856
const struct io_uring_sqe *sqe)
36853857
{
@@ -6169,6 +6341,12 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
61696341
return io_renameat_prep(req, sqe);
61706342
case IORING_OP_UNLINKAT:
61716343
return io_unlinkat_prep(req, sqe);
6344+
case IORING_OP_MKDIRAT:
6345+
return io_mkdirat_prep(req, sqe);
6346+
case IORING_OP_SYMLINKAT:
6347+
return io_symlinkat_prep(req, sqe);
6348+
case IORING_OP_LINKAT:
6349+
return io_linkat_prep(req, sqe);
61726350
}
61736351

61746352
printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6332,6 +6510,17 @@ static void io_clean_op(struct io_kiocb *req)
63326510
case IORING_OP_UNLINKAT:
63336511
putname(req->unlink.filename);
63346512
break;
6513+
case IORING_OP_MKDIRAT:
6514+
putname(req->mkdir.filename);
6515+
break;
6516+
case IORING_OP_SYMLINKAT:
6517+
putname(req->symlink.oldpath);
6518+
putname(req->symlink.newpath);
6519+
break;
6520+
case IORING_OP_LINKAT:
6521+
putname(req->hardlink.oldpath);
6522+
putname(req->hardlink.newpath);
6523+
break;
63356524
}
63366525
}
63376526
if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6460,6 +6649,15 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
64606649
case IORING_OP_UNLINKAT:
64616650
ret = io_unlinkat(req, issue_flags);
64626651
break;
6652+
case IORING_OP_MKDIRAT:
6653+
ret = io_mkdirat(req, issue_flags);
6654+
break;
6655+
case IORING_OP_SYMLINKAT:
6656+
ret = io_symlinkat(req, issue_flags);
6657+
break;
6658+
case IORING_OP_LINKAT:
6659+
ret = io_linkat(req, issue_flags);
6660+
break;
64636661
default:
64646662
ret = -EINVAL;
64656663
break;

0 commit comments

Comments
 (0)