Commit 91928e0d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-6.15/io_uring-20250322' of git://git.kernel.dk/linux

Pull io_uring updates from Jens Axboe:
 "This is the first of the io_uring pull requests for the 6.15 merge
  window, there will be others once the net tree has gone in. This
  contains:

   - Cleanup and unification of cancelation handling across various
     request types.

   - Improvement for bundles, supporting them both for incrementally
     consumed buffers, and for non-multishot requests.

   - Enable toggling of using iowait while waiting on io_uring events or
     not. Unfortunately this is still tied with CPU frequency boosting
     on short waits, as the scheduler side has not been very receptive
     to splitting the (useless) iowait stat from the cpufreq implied
     boost.

   - Add support for kbuf nodes, enabling zero-copy support for the ublk
     block driver.

   - Various cleanups for resource node handling.

   - Series greatly cleaning up the legacy provided (non-ring based)
     buffers. For years, we've been pushing the ring provided buffers as
     the way to go, and that is what people have been using. Reduce the
     complexity and code associated with legacy provided buffers.

   - Series cleaning up the compat handling.

   - Series improving and cleaning up the recvmsg/sendmsg iovec and msg
     handling.

   - Series of cleanups for io-wq.

   - Start adding a bunch of selftests. The liburing repository
     generally carries feature and regression tests for everything, but
     at least for ublk initially, we'll try and go the route of having
     it in selftests as well. We'll see how this goes, might decide to
     migrate more tests this way in the future.

   - Various little cleanups and fixes"

* tag 'for-6.15/io_uring-20250322' of git://git.kernel.dk/linux: (108 commits)
  selftests: ublk: add stripe target
  selftests: ublk: simplify loop io completion
  selftests: ublk: enable zero copy for null target
  selftests: ublk: prepare for supporting stripe target
  selftests: ublk: move common code into common.c
  selftests: ublk: increase max buffer size to 1MB
  selftests: ublk: add single sqe allocator helper
  selftests: ublk: add generic_01 for verifying sequential IO order
  selftests: ublk: fix starting ublk device
  io_uring: enable toggle of iowait usage when waiting on CQEs
  selftests: ublk: fix write cache implementation
  selftests: ublk: add variable for user to not show test result
  selftests: ublk: don't show `modprobe` failure
  selftests: ublk: add one dependency header
  io_uring/kbuf: enable bundles for incrementally consumed buffers
  Revert "io_uring/rsrc: simplify the bvec iter count calculation"
  selftests: ublk: improve test usability
  selftests: ublk: add stress test for covering IO vs. killing ublk server
  selftests: ublk: add one stress test for covering IO vs. removing device
  selftests: ublk: load/unload ublk_drv when preparing & cleaning up tests
  ...
parents 1e1ba8d2 0f3ebf2d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24397,6 +24397,7 @@ S: Maintained
F:	Documentation/block/ublk.rst
F:	drivers/block/ublk_drv.c
F:	include/uapi/linux/ublk_cmd.h
F:	tools/testing/selftests/ublk/
UBSAN
M:	Kees Cook <kees@kernel.org>
+49 −7
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@
/* private ioctl command mirror */
#define UBLK_CMD_DEL_DEV_ASYNC	_IOC_NR(UBLK_U_CMD_DEL_DEV_ASYNC)

#define UBLK_IO_REGISTER_IO_BUF		_IOC_NR(UBLK_U_IO_REGISTER_IO_BUF)
#define UBLK_IO_UNREGISTER_IO_BUF	_IOC_NR(UBLK_U_IO_UNREGISTER_IO_BUF)

/* All UBLK_F_* have to be included into UBLK_F_ALL */
#define UBLK_F_ALL (UBLK_F_SUPPORT_ZERO_COPY \
		| UBLK_F_URING_CMD_COMP_IN_TASK \
@@ -196,12 +199,14 @@ struct ublk_params_header {

static bool ublk_abort_requests(struct ublk_device *ub, struct ublk_queue *ubq);

static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
		struct ublk_queue *ubq, int tag, size_t offset);
static inline unsigned int ublk_req_build_flags(struct request *req);
static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
						   int tag);
static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
{
	return ub->dev_info.flags & UBLK_F_USER_COPY;
	return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
}

static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
@@ -581,7 +586,7 @@ static void ublk_apply_params(struct ublk_device *ub)

static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
{
	return ubq->flags & UBLK_F_USER_COPY;
	return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
}

static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
@@ -1747,6 +1752,42 @@ static inline void ublk_prep_cancel(struct io_uring_cmd *cmd,
	io_uring_cmd_mark_cancelable(cmd, issue_flags);
}

static void ublk_io_release(void *priv)
{
	struct request *rq = priv;
	struct ublk_queue *ubq = rq->mq_hctx->driver_data;

	ublk_put_req_ref(ubq, rq);
}

static int ublk_register_io_buf(struct io_uring_cmd *cmd,
				struct ublk_queue *ubq, unsigned int tag,
				unsigned int index, unsigned int issue_flags)
{
	struct ublk_device *ub = cmd->file->private_data;
	struct request *req;
	int ret;

	req = __ublk_check_and_get_req(ub, ubq, tag, 0);
	if (!req)
		return -EINVAL;

	ret = io_buffer_register_bvec(cmd, req, ublk_io_release, index,
				      issue_flags);
	if (ret) {
		ublk_put_req_ref(ubq, req);
		return ret;
	}

	return 0;
}

static int ublk_unregister_io_buf(struct io_uring_cmd *cmd,
				  unsigned int index, unsigned int issue_flags)
{
	return io_buffer_unregister_bvec(cmd, index, issue_flags);
}

static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
			       unsigned int issue_flags,
			       const struct ublksrv_io_cmd *ub_cmd)
@@ -1798,6 +1839,10 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,

	ret = -EINVAL;
	switch (_IOC_NR(cmd_op)) {
	case UBLK_IO_REGISTER_IO_BUF:
		return ublk_register_io_buf(cmd, ubq, tag, ub_cmd->addr, issue_flags);
	case UBLK_IO_UNREGISTER_IO_BUF:
		return ublk_unregister_io_buf(cmd, ub_cmd->addr, issue_flags);
	case UBLK_IO_FETCH_REQ:
		/* UBLK_IO_FETCH_REQ is only allowed before queue is setup */
		if (ublk_queue_ready(ubq)) {
@@ -2459,7 +2504,7 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
		 * buffer by pwrite() to ublk char device, which can't be
		 * used for unprivileged device
		 */
		if (info.flags & UBLK_F_USER_COPY)
		if (info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY))
			return -EINVAL;
	}

@@ -2527,9 +2572,6 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
		goto out_free_dev_number;
	}

	/* We are not ready to support zero copy */
	ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;

	ub->dev_info.nr_hw_queues = min_t(unsigned int,
			ub->dev_info.nr_hw_queues, nr_cpu_ids);
	ublk_align_max_io_size(ub);
@@ -2863,7 +2905,7 @@ static int ublk_ctrl_get_features(struct io_uring_cmd *cmd)
{
	const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe);
	void __user *argp = (void __user *)(unsigned long)header->addr;
	u64 features = UBLK_F_ALL & ~UBLK_F_SUPPORT_ZERO_COPY;
	u64 features = UBLK_F_ALL;

	if (header->len != UBLK_FEATURES_LEN || !header->addr)
		return -EINVAL;
+7 −5
Original line number Diff line number Diff line
@@ -114,7 +114,8 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,

static int nvme_map_user_request(struct request *req, u64 ubuffer,
		unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
		struct io_uring_cmd *ioucmd, unsigned int flags)
		struct io_uring_cmd *ioucmd, unsigned int flags,
		unsigned int iou_issue_flags)
{
	struct request_queue *q = req->q;
	struct nvme_ns *ns = q->queuedata;
@@ -146,7 +147,8 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
			goto out;
		}
		ret = io_uring_cmd_import_fixed(ubuffer, bufflen,
				rq_data_dir(req), &iter, ioucmd);
				rq_data_dir(req), &iter, ioucmd,
				iou_issue_flags);
		if (ret < 0)
			goto out;
		ret = blk_rq_map_user_iov(q, req, NULL, &iter, GFP_KERNEL);
@@ -198,7 +200,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
	req->timeout = timeout;
	if (ubuffer && bufflen) {
		ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer,
				meta_len, NULL, flags);
				meta_len, NULL, flags, 0);
		if (ret)
			return ret;
	}
@@ -514,10 +516,10 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
		return PTR_ERR(req);
	req->timeout = d.timeout_ms ? msecs_to_jiffies(d.timeout_ms) : 0;

	if (d.addr && d.data_len) {
	if (d.data_len) {
		ret = nvme_map_user_request(req, d.addr,
			d.data_len, nvme_to_user_ptr(d.metadata),
			d.metadata_len, ioucmd, vec);
			d.metadata_len, ioucmd, vec, issue_flags);
		if (ret)
			return ret;
	}
+14 −3
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

#include <uapi/linux/io_uring.h>
#include <linux/io_uring_types.h>
#include <linux/blk-mq.h>

/* only top 8 bits of sqe->uring_cmd_flags for kernel internal use */
#define IORING_URING_CMD_CANCELABLE	(1U << 30)
@@ -39,7 +40,9 @@ static inline void io_uring_cmd_private_sz_check(size_t cmd_sz)

#if defined(CONFIG_IO_URING)
int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
			      struct iov_iter *iter, void *ioucmd);
			      struct iov_iter *iter,
			      struct io_uring_cmd *ioucmd,
			      unsigned int issue_flags);

/*
 * Completes the request, i.e. posts an io_uring CQE and deallocates @ioucmd
@@ -66,8 +69,10 @@ void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
void io_uring_cmd_issue_blocking(struct io_uring_cmd *ioucmd);

#else
static inline int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
			      struct iov_iter *iter, void *ioucmd)
static inline int
io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
			  struct iov_iter *iter, struct io_uring_cmd *ioucmd,
			  unsigned int issue_flags)
{
	return -EOPNOTSUPP;
}
@@ -123,4 +128,10 @@ static inline struct io_uring_cmd_data *io_uring_cmd_get_async_data(struct io_ur
	return cmd_to_io_kiocb(cmd)->async_data;
}

int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
			    void (*release)(void *), unsigned int index,
			    unsigned int issue_flags);
int io_buffer_unregister_bvec(struct io_uring_cmd *cmd, unsigned int index,
			      unsigned int issue_flags);

#endif /* _LINUX_IO_URING_CMD_H */
+15 −5
Original line number Diff line number Diff line
@@ -292,6 +292,8 @@ struct io_ring_ctx {

		struct io_file_table	file_table;
		struct io_rsrc_data	buf_table;
		struct io_alloc_cache	node_cache;
		struct io_alloc_cache	imu_cache;

		struct io_submit_state	submit_state;

@@ -360,7 +362,6 @@ struct io_ring_ctx {

	spinlock_t		completion_lock;

	struct list_head	io_buffers_comp;
	struct list_head	cq_overflow_list;

	struct hlist_head	waitid_list;
@@ -379,8 +380,6 @@ struct io_ring_ctx {
	unsigned int		file_alloc_start;
	unsigned int		file_alloc_end;

	struct list_head	io_buffers_cache;

	/* Keep this last, we don't need it for the fast path */
	struct wait_queue_head		poll_wq;
	struct io_restriction		restrictions;
@@ -439,8 +438,15 @@ struct io_ring_ctx {
	struct io_mapped_region		param_region;
};

/*
 * Token indicating function is called in task work context:
 * ctx->uring_lock is held and any completions generated will be flushed.
 * ONLY core io_uring.c should instantiate this struct.
 */
struct io_tw_state {
};
/* Alias to use in code that doesn't instantiate struct io_tw_state */
typedef struct io_tw_state io_tw_token_t;

enum {
	REQ_F_FIXED_FILE_BIT	= IOSQE_FIXED_FILE_BIT,
@@ -566,7 +572,7 @@ enum {
	REQ_F_HAS_METADATA	= IO_REQ_FLAG(REQ_F_HAS_METADATA_BIT),
};

typedef void (*io_req_tw_func_t)(struct io_kiocb *req, struct io_tw_state *ts);
typedef void (*io_req_tw_func_t)(struct io_kiocb *req, io_tw_token_t tw);

struct io_task_work {
	struct llist_node		node;
@@ -601,7 +607,11 @@ static inline void io_kiocb_cmd_sz_check(size_t cmd_sz)
	io_kiocb_cmd_sz_check(sizeof(cmd_type)) , \
	((cmd_type *)&(req)->cmd) \
)
#define cmd_to_io_kiocb(ptr)	((struct io_kiocb *) ptr)

static inline struct io_kiocb *cmd_to_io_kiocb(void *ptr)
{
	return ptr;
}

struct io_kiocb {
	union {
Loading