Commit e34a02dc authored by Dmitry Kadashev's avatar Dmitry Kadashev Committed by Jens Axboe
Browse files

io_uring: add support for IORING_OP_MKDIRAT



IORING_OP_MKDIRAT behaves like mkdirat(2) and takes the same flags
and arguments.

Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarDmitry Kadashev <dkadashev@gmail.com>
Acked-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20210708063447.3556403-10-dkadashev@gmail.com


[axboe: add splice_fd_in check]
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 45f30dab
Loading
Loading
Loading
Loading
+60 −0
Original line number Diff line number Diff line
@@ -662,6 +662,13 @@ struct io_unlink {
	struct filename			*filename;
};

struct io_mkdir {
	struct file			*file;
	int				dfd;
	umode_t				mode;
	struct filename			*filename;
};

struct io_completion {
	struct file			*file;
	u32				cflags;
@@ -821,6 +828,7 @@ struct io_kiocb {
		struct io_shutdown	shutdown;
		struct io_rename	rename;
		struct io_unlink	unlink;
		struct io_mkdir		mkdir;
		/* use only after cleaning per-op data, see io_clean_op() */
		struct io_completion	compl;
	};
@@ -1032,6 +1040,7 @@ static const struct io_op_def io_op_defs[] = {
	},
	[IORING_OP_RENAMEAT] = {},
	[IORING_OP_UNLINKAT] = {},
	[IORING_OP_MKDIRAT] = {},
};

/* requests with any of those set should undergo io_disarm_next() */
@@ -3603,6 +3612,49 @@ static int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
	return 0;
}

static int io_mkdirat_prep(struct io_kiocb *req,
			    const struct io_uring_sqe *sqe)
{
	struct io_mkdir *mkd = &req->mkdir;
	const char __user *fname;

	if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
		return -EINVAL;
	if (sqe->ioprio || sqe->off || sqe->rw_flags || sqe->buf_index ||
	    sqe->splice_fd_in)
		return -EINVAL;
	if (unlikely(req->flags & REQ_F_FIXED_FILE))
		return -EBADF;

	mkd->dfd = READ_ONCE(sqe->fd);
	mkd->mode = READ_ONCE(sqe->len);

	fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
	mkd->filename = getname(fname);
	if (IS_ERR(mkd->filename))
		return PTR_ERR(mkd->filename);

	req->flags |= REQ_F_NEED_CLEANUP;
	return 0;
}

static int io_mkdirat(struct io_kiocb *req, int issue_flags)
{
	struct io_mkdir *mkd = &req->mkdir;
	int ret;

	if (issue_flags & IO_URING_F_NONBLOCK)
		return -EAGAIN;

	ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);

	req->flags &= ~REQ_F_NEED_CLEANUP;
	if (ret < 0)
		req_set_fail(req);
	io_req_complete(req, ret);
	return 0;
}

static int io_shutdown_prep(struct io_kiocb *req,
			    const struct io_uring_sqe *sqe)
{
@@ -6000,6 +6052,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
		return io_renameat_prep(req, sqe);
	case IORING_OP_UNLINKAT:
		return io_unlinkat_prep(req, sqe);
	case IORING_OP_MKDIRAT:
		return io_mkdirat_prep(req, sqe);
	}

	printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6163,6 +6217,9 @@ static void io_clean_op(struct io_kiocb *req)
		case IORING_OP_UNLINKAT:
			putname(req->unlink.filename);
			break;
		case IORING_OP_MKDIRAT:
			putname(req->mkdir.filename);
			break;
		}
	}
	if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6291,6 +6348,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
	case IORING_OP_UNLINKAT:
		ret = io_unlinkat(req, issue_flags);
		break;
	case IORING_OP_MKDIRAT:
		ret = io_mkdirat(req, issue_flags);
		break;
	default:
		ret = -EINVAL;
		break;
+1 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ enum {
	IORING_OP_SHUTDOWN,
	IORING_OP_RENAMEAT,
	IORING_OP_UNLINKAT,
	IORING_OP_MKDIRAT,

	/* this goes last, obviously */
	IORING_OP_LAST,