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

io_uring: add support for IORING_OP_SYMLINKAT

parent e34a02dc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ int may_linkat(struct user_namespace *mnt_userns, struct path *link);
int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
		 struct filename *newname, unsigned int flags);
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
int do_symlinkat(struct filename *from, int newdfd, struct filename *to);

/*
 * namespace.c
+67 −0
Original line number Diff line number Diff line
@@ -669,6 +669,13 @@ struct io_mkdir {
	struct filename			*filename;
};

struct io_symlink {
	struct file			*file;
	int				new_dfd;
	struct filename			*oldpath;
	struct filename			*newpath;
};

struct io_completion {
	struct file			*file;
	u32				cflags;
@@ -829,6 +836,7 @@ struct io_kiocb {
		struct io_rename	rename;
		struct io_unlink	unlink;
		struct io_mkdir		mkdir;
		struct io_symlink	symlink;
		/* use only after cleaning per-op data, see io_clean_op() */
		struct io_completion	compl;
	};
@@ -1041,6 +1049,7 @@ static const struct io_op_def io_op_defs[] = {
	[IORING_OP_RENAMEAT] = {},
	[IORING_OP_UNLINKAT] = {},
	[IORING_OP_MKDIRAT] = {},
	[IORING_OP_SYMLINKAT] = {},
};

/* requests with any of those set should undergo io_disarm_next() */
@@ -3655,6 +3664,55 @@ static int io_mkdirat(struct io_kiocb *req, int issue_flags)
	return 0;
}

static int io_symlinkat_prep(struct io_kiocb *req,
			    const struct io_uring_sqe *sqe)
{
	struct io_symlink *sl = &req->symlink;
	const char __user *oldpath, *newpath;

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

	sl->new_dfd = READ_ONCE(sqe->fd);
	oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
	newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));

	sl->oldpath = getname(oldpath);
	if (IS_ERR(sl->oldpath))
		return PTR_ERR(sl->oldpath);

	sl->newpath = getname(newpath);
	if (IS_ERR(sl->newpath)) {
		putname(sl->oldpath);
		return PTR_ERR(sl->newpath);
	}

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

static int io_symlinkat(struct io_kiocb *req, int issue_flags)
{
	struct io_symlink *sl = &req->symlink;
	int ret;

	if (issue_flags & IO_URING_F_NONBLOCK)
		return -EAGAIN;

	ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);

	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)
{
@@ -6054,6 +6112,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
		return io_unlinkat_prep(req, sqe);
	case IORING_OP_MKDIRAT:
		return io_mkdirat_prep(req, sqe);
	case IORING_OP_SYMLINKAT:
		return io_symlinkat_prep(req, sqe);
	}

	printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6220,6 +6280,10 @@ static void io_clean_op(struct io_kiocb *req)
		case IORING_OP_MKDIRAT:
			putname(req->mkdir.filename);
			break;
		case IORING_OP_SYMLINKAT:
			putname(req->symlink.oldpath);
			putname(req->symlink.newpath);
			break;
		}
	}
	if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6351,6 +6415,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
	case IORING_OP_MKDIRAT:
		ret = io_mkdirat(req, issue_flags);
		break;
	case IORING_OP_SYMLINKAT:
		ret = io_symlinkat(req, issue_flags);
		break;
	default:
		ret = -EINVAL;
		break;
+1 −2
Original line number Diff line number Diff line
@@ -4223,8 +4223,7 @@ int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
}
EXPORT_SYMBOL(vfs_symlink);

static int do_symlinkat(struct filename *from, int newdfd,
		  struct filename *to)
int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
{
	int error;
	struct dentry *dentry;
+1 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ enum {
	IORING_OP_RENAMEAT,
	IORING_OP_UNLINKAT,
	IORING_OP_MKDIRAT,
	IORING_OP_SYMLINKAT,

	/* this goes last, obviously */
	IORING_OP_LAST,