xref: /openbmc/linux/io_uring/fs.c (revision ed869aee)
111aeb714SJens Axboe // SPDX-License-Identifier: GPL-2.0
211aeb714SJens Axboe #include <linux/kernel.h>
311aeb714SJens Axboe #include <linux/errno.h>
411aeb714SJens Axboe #include <linux/fs.h>
511aeb714SJens Axboe #include <linux/file.h>
611aeb714SJens Axboe #include <linux/mm.h>
711aeb714SJens Axboe #include <linux/slab.h>
811aeb714SJens Axboe #include <linux/namei.h>
911aeb714SJens Axboe #include <linux/io_uring.h>
1011aeb714SJens Axboe 
1111aeb714SJens Axboe #include <uapi/linux/io_uring.h>
1211aeb714SJens Axboe 
1311aeb714SJens Axboe #include "../fs/internal.h"
1411aeb714SJens Axboe 
1511aeb714SJens Axboe #include "io_uring.h"
1611aeb714SJens Axboe #include "fs.h"
1711aeb714SJens Axboe 
1811aeb714SJens Axboe struct io_rename {
1911aeb714SJens Axboe 	struct file			*file;
2011aeb714SJens Axboe 	int				old_dfd;
2111aeb714SJens Axboe 	int				new_dfd;
2211aeb714SJens Axboe 	struct filename			*oldpath;
2311aeb714SJens Axboe 	struct filename			*newpath;
2411aeb714SJens Axboe 	int				flags;
2511aeb714SJens Axboe };
2611aeb714SJens Axboe 
2711aeb714SJens Axboe struct io_unlink {
2811aeb714SJens Axboe 	struct file			*file;
2911aeb714SJens Axboe 	int				dfd;
3011aeb714SJens Axboe 	int				flags;
3111aeb714SJens Axboe 	struct filename			*filename;
3211aeb714SJens Axboe };
3311aeb714SJens Axboe 
3411aeb714SJens Axboe struct io_mkdir {
3511aeb714SJens Axboe 	struct file			*file;
3611aeb714SJens Axboe 	int				dfd;
3711aeb714SJens Axboe 	umode_t				mode;
3811aeb714SJens Axboe 	struct filename			*filename;
3911aeb714SJens Axboe };
4011aeb714SJens Axboe 
4111aeb714SJens Axboe struct io_link {
4211aeb714SJens Axboe 	struct file			*file;
4311aeb714SJens Axboe 	int				old_dfd;
4411aeb714SJens Axboe 	int				new_dfd;
4511aeb714SJens Axboe 	struct filename			*oldpath;
4611aeb714SJens Axboe 	struct filename			*newpath;
4711aeb714SJens Axboe 	int				flags;
4811aeb714SJens Axboe };
4911aeb714SJens Axboe 
io_renameat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)5011aeb714SJens Axboe int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
5111aeb714SJens Axboe {
52f2ccb5aeSStefan Metzmacher 	struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
5311aeb714SJens Axboe 	const char __user *oldf, *newf;
5411aeb714SJens Axboe 
5511aeb714SJens Axboe 	if (sqe->buf_index || sqe->splice_fd_in)
5611aeb714SJens Axboe 		return -EINVAL;
5711aeb714SJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
5811aeb714SJens Axboe 		return -EBADF;
5911aeb714SJens Axboe 
6011aeb714SJens Axboe 	ren->old_dfd = READ_ONCE(sqe->fd);
6111aeb714SJens Axboe 	oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
6211aeb714SJens Axboe 	newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
6311aeb714SJens Axboe 	ren->new_dfd = READ_ONCE(sqe->len);
6411aeb714SJens Axboe 	ren->flags = READ_ONCE(sqe->rename_flags);
6511aeb714SJens Axboe 
6611aeb714SJens Axboe 	ren->oldpath = getname(oldf);
6711aeb714SJens Axboe 	if (IS_ERR(ren->oldpath))
6811aeb714SJens Axboe 		return PTR_ERR(ren->oldpath);
6911aeb714SJens Axboe 
7011aeb714SJens Axboe 	ren->newpath = getname(newf);
7111aeb714SJens Axboe 	if (IS_ERR(ren->newpath)) {
7211aeb714SJens Axboe 		putname(ren->oldpath);
7311aeb714SJens Axboe 		return PTR_ERR(ren->newpath);
7411aeb714SJens Axboe 	}
7511aeb714SJens Axboe 
7611aeb714SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
77aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
7811aeb714SJens Axboe 	return 0;
7911aeb714SJens Axboe }
8011aeb714SJens Axboe 
io_renameat(struct io_kiocb * req,unsigned int issue_flags)8111aeb714SJens Axboe int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
8211aeb714SJens Axboe {
83f2ccb5aeSStefan Metzmacher 	struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
8411aeb714SJens Axboe 	int ret;
8511aeb714SJens Axboe 
86aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
8711aeb714SJens Axboe 
8811aeb714SJens Axboe 	ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
8911aeb714SJens Axboe 				ren->newpath, ren->flags);
9011aeb714SJens Axboe 
9111aeb714SJens Axboe 	req->flags &= ~REQ_F_NEED_CLEANUP;
9211aeb714SJens Axboe 	io_req_set_res(req, ret, 0);
9311aeb714SJens Axboe 	return IOU_OK;
9411aeb714SJens Axboe }
9511aeb714SJens Axboe 
io_renameat_cleanup(struct io_kiocb * req)9611aeb714SJens Axboe void io_renameat_cleanup(struct io_kiocb *req)
9711aeb714SJens Axboe {
98f2ccb5aeSStefan Metzmacher 	struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
9911aeb714SJens Axboe 
10011aeb714SJens Axboe 	putname(ren->oldpath);
10111aeb714SJens Axboe 	putname(ren->newpath);
10211aeb714SJens Axboe }
10311aeb714SJens Axboe 
io_unlinkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)10411aeb714SJens Axboe int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
10511aeb714SJens Axboe {
106f2ccb5aeSStefan Metzmacher 	struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
10711aeb714SJens Axboe 	const char __user *fname;
10811aeb714SJens Axboe 
10911aeb714SJens Axboe 	if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
11011aeb714SJens Axboe 		return -EINVAL;
11111aeb714SJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
11211aeb714SJens Axboe 		return -EBADF;
11311aeb714SJens Axboe 
11411aeb714SJens Axboe 	un->dfd = READ_ONCE(sqe->fd);
11511aeb714SJens Axboe 
11611aeb714SJens Axboe 	un->flags = READ_ONCE(sqe->unlink_flags);
11711aeb714SJens Axboe 	if (un->flags & ~AT_REMOVEDIR)
11811aeb714SJens Axboe 		return -EINVAL;
11911aeb714SJens Axboe 
12011aeb714SJens Axboe 	fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
12111aeb714SJens Axboe 	un->filename = getname(fname);
12211aeb714SJens Axboe 	if (IS_ERR(un->filename))
12311aeb714SJens Axboe 		return PTR_ERR(un->filename);
12411aeb714SJens Axboe 
12511aeb714SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
126aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
12711aeb714SJens Axboe 	return 0;
12811aeb714SJens Axboe }
12911aeb714SJens Axboe 
io_unlinkat(struct io_kiocb * req,unsigned int issue_flags)13011aeb714SJens Axboe int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
13111aeb714SJens Axboe {
132f2ccb5aeSStefan Metzmacher 	struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
13311aeb714SJens Axboe 	int ret;
13411aeb714SJens Axboe 
135aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
13611aeb714SJens Axboe 
13711aeb714SJens Axboe 	if (un->flags & AT_REMOVEDIR)
13811aeb714SJens Axboe 		ret = do_rmdir(un->dfd, un->filename);
13911aeb714SJens Axboe 	else
14011aeb714SJens Axboe 		ret = do_unlinkat(un->dfd, un->filename);
14111aeb714SJens Axboe 
14211aeb714SJens Axboe 	req->flags &= ~REQ_F_NEED_CLEANUP;
14311aeb714SJens Axboe 	io_req_set_res(req, ret, 0);
14411aeb714SJens Axboe 	return IOU_OK;
14511aeb714SJens Axboe }
14611aeb714SJens Axboe 
io_unlinkat_cleanup(struct io_kiocb * req)14711aeb714SJens Axboe void io_unlinkat_cleanup(struct io_kiocb *req)
14811aeb714SJens Axboe {
149f2ccb5aeSStefan Metzmacher 	struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
15011aeb714SJens Axboe 
15111aeb714SJens Axboe 	putname(ul->filename);
15211aeb714SJens Axboe }
15311aeb714SJens Axboe 
io_mkdirat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)15411aeb714SJens Axboe int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
15511aeb714SJens Axboe {
156f2ccb5aeSStefan Metzmacher 	struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
15711aeb714SJens Axboe 	const char __user *fname;
15811aeb714SJens Axboe 
15911aeb714SJens Axboe 	if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
16011aeb714SJens Axboe 		return -EINVAL;
16111aeb714SJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
16211aeb714SJens Axboe 		return -EBADF;
16311aeb714SJens Axboe 
16411aeb714SJens Axboe 	mkd->dfd = READ_ONCE(sqe->fd);
16511aeb714SJens Axboe 	mkd->mode = READ_ONCE(sqe->len);
16611aeb714SJens Axboe 
16711aeb714SJens Axboe 	fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
16811aeb714SJens Axboe 	mkd->filename = getname(fname);
16911aeb714SJens Axboe 	if (IS_ERR(mkd->filename))
17011aeb714SJens Axboe 		return PTR_ERR(mkd->filename);
17111aeb714SJens Axboe 
17211aeb714SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
173aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
17411aeb714SJens Axboe 	return 0;
17511aeb714SJens Axboe }
17611aeb714SJens Axboe 
io_mkdirat(struct io_kiocb * req,unsigned int issue_flags)17711aeb714SJens Axboe int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
17811aeb714SJens Axboe {
179f2ccb5aeSStefan Metzmacher 	struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
18011aeb714SJens Axboe 	int ret;
18111aeb714SJens Axboe 
182aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
18311aeb714SJens Axboe 
18411aeb714SJens Axboe 	ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
18511aeb714SJens Axboe 
18611aeb714SJens Axboe 	req->flags &= ~REQ_F_NEED_CLEANUP;
18711aeb714SJens Axboe 	io_req_set_res(req, ret, 0);
18811aeb714SJens Axboe 	return IOU_OK;
18911aeb714SJens Axboe }
19011aeb714SJens Axboe 
io_mkdirat_cleanup(struct io_kiocb * req)19111aeb714SJens Axboe void io_mkdirat_cleanup(struct io_kiocb *req)
19211aeb714SJens Axboe {
193f2ccb5aeSStefan Metzmacher 	struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
19411aeb714SJens Axboe 
19511aeb714SJens Axboe 	putname(md->filename);
19611aeb714SJens Axboe }
19711aeb714SJens Axboe 
io_symlinkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)19811aeb714SJens Axboe int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
19911aeb714SJens Axboe {
200f2ccb5aeSStefan Metzmacher 	struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
20111aeb714SJens Axboe 	const char __user *oldpath, *newpath;
20211aeb714SJens Axboe 
20311aeb714SJens Axboe 	if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
20411aeb714SJens Axboe 		return -EINVAL;
20511aeb714SJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
20611aeb714SJens Axboe 		return -EBADF;
20711aeb714SJens Axboe 
20811aeb714SJens Axboe 	sl->new_dfd = READ_ONCE(sqe->fd);
20911aeb714SJens Axboe 	oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
21011aeb714SJens Axboe 	newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
21111aeb714SJens Axboe 
21211aeb714SJens Axboe 	sl->oldpath = getname(oldpath);
21311aeb714SJens Axboe 	if (IS_ERR(sl->oldpath))
21411aeb714SJens Axboe 		return PTR_ERR(sl->oldpath);
21511aeb714SJens Axboe 
21611aeb714SJens Axboe 	sl->newpath = getname(newpath);
21711aeb714SJens Axboe 	if (IS_ERR(sl->newpath)) {
21811aeb714SJens Axboe 		putname(sl->oldpath);
21911aeb714SJens Axboe 		return PTR_ERR(sl->newpath);
22011aeb714SJens Axboe 	}
22111aeb714SJens Axboe 
22211aeb714SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
223aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
22411aeb714SJens Axboe 	return 0;
22511aeb714SJens Axboe }
22611aeb714SJens Axboe 
io_symlinkat(struct io_kiocb * req,unsigned int issue_flags)22711aeb714SJens Axboe int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
22811aeb714SJens Axboe {
229f2ccb5aeSStefan Metzmacher 	struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
23011aeb714SJens Axboe 	int ret;
23111aeb714SJens Axboe 
232aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
23311aeb714SJens Axboe 
23411aeb714SJens Axboe 	ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
23511aeb714SJens Axboe 
23611aeb714SJens Axboe 	req->flags &= ~REQ_F_NEED_CLEANUP;
23711aeb714SJens Axboe 	io_req_set_res(req, ret, 0);
23811aeb714SJens Axboe 	return IOU_OK;
23911aeb714SJens Axboe }
24011aeb714SJens Axboe 
io_linkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)24111aeb714SJens Axboe int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
24211aeb714SJens Axboe {
243f2ccb5aeSStefan Metzmacher 	struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
24411aeb714SJens Axboe 	const char __user *oldf, *newf;
24511aeb714SJens Axboe 
246a52d4f65SJens Axboe 	if (sqe->buf_index || sqe->splice_fd_in)
24711aeb714SJens Axboe 		return -EINVAL;
24811aeb714SJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
24911aeb714SJens Axboe 		return -EBADF;
25011aeb714SJens Axboe 
25111aeb714SJens Axboe 	lnk->old_dfd = READ_ONCE(sqe->fd);
25211aeb714SJens Axboe 	lnk->new_dfd = READ_ONCE(sqe->len);
25311aeb714SJens Axboe 	oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
25411aeb714SJens Axboe 	newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
25511aeb714SJens Axboe 	lnk->flags = READ_ONCE(sqe->hardlink_flags);
25611aeb714SJens Axboe 
257*ed869aeeSCharles Mirabile 	lnk->oldpath = getname_uflags(oldf, lnk->flags);
25811aeb714SJens Axboe 	if (IS_ERR(lnk->oldpath))
25911aeb714SJens Axboe 		return PTR_ERR(lnk->oldpath);
26011aeb714SJens Axboe 
26111aeb714SJens Axboe 	lnk->newpath = getname(newf);
26211aeb714SJens Axboe 	if (IS_ERR(lnk->newpath)) {
26311aeb714SJens Axboe 		putname(lnk->oldpath);
26411aeb714SJens Axboe 		return PTR_ERR(lnk->newpath);
26511aeb714SJens Axboe 	}
26611aeb714SJens Axboe 
26711aeb714SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
268aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
26911aeb714SJens Axboe 	return 0;
27011aeb714SJens Axboe }
27111aeb714SJens Axboe 
io_linkat(struct io_kiocb * req,unsigned int issue_flags)27211aeb714SJens Axboe int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
27311aeb714SJens Axboe {
274f2ccb5aeSStefan Metzmacher 	struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
27511aeb714SJens Axboe 	int ret;
27611aeb714SJens Axboe 
277aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
27811aeb714SJens Axboe 
27911aeb714SJens Axboe 	ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
28011aeb714SJens Axboe 				lnk->newpath, lnk->flags);
28111aeb714SJens Axboe 
28211aeb714SJens Axboe 	req->flags &= ~REQ_F_NEED_CLEANUP;
28311aeb714SJens Axboe 	io_req_set_res(req, ret, 0);
28411aeb714SJens Axboe 	return IOU_OK;
28511aeb714SJens Axboe }
28611aeb714SJens Axboe 
io_link_cleanup(struct io_kiocb * req)28711aeb714SJens Axboe void io_link_cleanup(struct io_kiocb *req)
28811aeb714SJens Axboe {
289f2ccb5aeSStefan Metzmacher 	struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
29011aeb714SJens Axboe 
29111aeb714SJens Axboe 	putname(sl->oldpath);
29211aeb714SJens Axboe 	putname(sl->newpath);
29311aeb714SJens Axboe }
294