Linux block layer
 help / color / mirror / Atom feed
From: Ming Lei <tom.leiming@gmail.com>
To: Caleb Sander Mateos <csander@purestorage.com>
Cc: Jens Axboe <axboe@kernel.dk>,
	linux-block@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 5/6] ublk: add UBLK_F_IO_DESC_SIZE
Date: Thu, 30 Jul 2026 10:14:20 -0500	[thread overview]
Message-ID: <amtqTIZiUgOrSJmg@fedora-laptop> (raw)
In-Reply-To: <20260729012951.3744582-6-csander@purestorage.com>

On Tue, Jul 28, 2026 at 07:29:50PM -0600, Caleb Sander Mateos wrote:
> ublk passes the parameters of incoming I/O in memory shared between the
> kernel ublk driver and userspace ublk server in struct ublksrv_io_desc.
> The size of this struct is currently fixed to 24 bytes, which has been
> an obstacle to extending it with additional fields [1]. Additionally,
> with multiple ublk server threads handling I/Os from the same ublk queue
> (possible with UBLK_F_PER_IO_DAEMON or UBLK_F_BATCH_IO), false sharing
> results from adjacent io_descs sharing the same cache line.
> 
> Add a ublk feature UBLK_F_IO_DESC_SIZE to allow a ublk server to
> override the size of each io_desc. The size must be at least 24 and a
> multiple of 8 to store a properly-aligned struct ublksrv_io_desc. The
> struct ublksrv_io_desc is located at the beginning of each io_desc and
> the remainder is padding. The mmap() performed for each queue must have
> a length of queue_depth * io_desc_size, rounded up to the page size. The
> mmap() offset must be q_id * UBLK_MAX_QUEUE_DEPTH * io_desc_size, also
> rounded up to the page size.
> 
> [1]: https://lore.kernel.org/linux-block/aV8QfvaNO5P6vOs6@fedora/
> 
> Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
> ---
>  drivers/block/ublk_drv.c      | 35 ++++++++++++++++++++++++-----------
>  include/uapi/linux/ublk_cmd.h |  5 ++++-
>  2 files changed, 28 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 46f5ab13f87e..1da45e382253 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -87,11 +87,12 @@
>  		| UBLK_F_BUF_REG_OFF_DAEMON \
>  		| (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) ? UBLK_F_INTEGRITY : 0) \
>  		| UBLK_F_SAFE_STOP_DEV \
>  		| UBLK_F_BATCH_IO \
>  		| UBLK_F_NO_AUTO_PART_SCAN \
> -		| UBLK_F_SHMEM_ZC)
> +		| UBLK_F_SHMEM_ZC \
> +		| UBLK_F_IO_DESC_SIZE)
>  
>  #define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
>  		| UBLK_F_USER_RECOVERY_REISSUE \
>  		| UBLK_F_USER_RECOVERY_FAIL_IO)
>  
> @@ -237,10 +238,11 @@ struct ublk_io {
>  } ____cacheline_aligned_in_smp;
>  
>  struct ublk_queue {
>  	u16 q_id;
>  	u16 q_depth;
> +	u16 io_desc_size;
>  
>  	unsigned long flags;
>  	struct ublksrv_io_desc *io_cmd_buf;
>  
>  	bool force_abort;
> @@ -403,11 +405,11 @@ static inline void ublk_io_evts_deinit(struct ublk_queue *q)
>  }
>  
>  static inline struct ublksrv_io_desc *
>  ublk_get_iod(const struct ublk_queue *ubq, u16 tag)
>  {
> -	return &ubq->io_cmd_buf[tag];
> +	return (void *)ubq->io_cmd_buf + tag * (size_t)ubq->io_desc_size;
>  }
>  
>  static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
>  {
>  	return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
> @@ -1246,23 +1248,24 @@ static inline struct ublksrv_io_desc *
>  ublk_queue_cmd_buf(struct ublk_device *ub, u16 q_id)
>  {
>  	return ublk_get_queue(ub, q_id)->io_cmd_buf;
>  }
>  
> -static inline int __ublk_queue_cmd_buf_size(u16 depth)
> +static inline size_t __ublk_queue_cmd_buf_size(const struct ublk_device *ub,
> +					       u16 depth)
>  {
> -	return round_up(depth * sizeof(struct ublksrv_io_desc), PAGE_SIZE);
> +	return round_up(depth * (size_t)ub->dev_info.io_desc_size, PAGE_SIZE);
>  }
>  
> -static inline int ublk_queue_cmd_buf_size(struct ublk_device *ub)
> +static inline size_t ublk_queue_cmd_buf_size(const struct ublk_device *ub)
>  {
> -	return __ublk_queue_cmd_buf_size(ub->dev_info.queue_depth);
> +	return __ublk_queue_cmd_buf_size(ub, ub->dev_info.queue_depth);
>  }
>  
> -static int ublk_max_cmd_buf_size(void)
> +static size_t ublk_max_cmd_buf_size(const struct ublk_device *ub)
>  {
> -	return __ublk_queue_cmd_buf_size(UBLK_MAX_QUEUE_DEPTH);
> +	return __ublk_queue_cmd_buf_size(ub, UBLK_MAX_QUEUE_DEPTH);
>  }
>  
>  /*
>   * Should I/O outstanding to the ublk server when it exits be reissued?
>   * If not, outstanding I/O will get errors.
> @@ -2648,11 +2651,11 @@ static int ublk_ch_release(struct inode *inode, struct file *filp)
>  /* map pre-allocated per-queue cmd buffer to ublksrv daemon */
>  static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma)
>  {
>  	struct ublk_device *ub = filp->private_data;
>  	size_t sz = vma->vm_end - vma->vm_start;
> -	unsigned max_sz = ublk_max_cmd_buf_size();
> +	size_t max_sz = ublk_max_cmd_buf_size(ub);
>  	unsigned long pfn, end, phys_off = vma->vm_pgoff << PAGE_SHIFT;
>  	int ret = 0;
>  	u16 q_id;
>  
>  	spin_lock(&ub->lock);
> @@ -4174,11 +4177,11 @@ static const struct file_operations ublk_ch_batch_io_fops = {
>  	.mmap = ublk_ch_mmap,
>  };
>  
>  static void __ublk_deinit_queue(struct ublk_device *ub, struct ublk_queue *ubq)
>  {
> -	int size;
> +	size_t size;
>  	u16 i;
>  
>  	size = ublk_queue_cmd_buf_size(ub);
>  
>  	for (i = 0; i < ubq->q_depth; i++) {
> @@ -4227,11 +4230,12 @@ static int ublk_init_queue(struct ublk_device *ub, u16 q_id)
>  	u16 depth = ub->dev_info.queue_depth;
>  	gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
>  	struct ublk_queue *ubq;
>  	struct page *page;
>  	int numa_node;
> -	int size, ret;
> +	size_t size;
> +	int ret;
>  	u16 i;
>  
>  	/* Determine NUMA node based on queue's CPU affinity */
>  	numa_node = ublk_get_queue_numa_node(ub, q_id);
>  
> @@ -4252,10 +4256,11 @@ static int ublk_init_queue(struct ublk_device *ub, u16 q_id)
>  	if (!page) {
>  		kvfree(ubq);
>  		return -ENOMEM;
>  	}
>  	ubq->io_cmd_buf = page_address(page);
> +	ubq->io_desc_size = ub->dev_info.io_desc_size;
>  
>  	for (i = 0; i < ubq->q_depth; i++)
>  		spin_lock_init(&ubq->ios[i].lock);
>  
>  	if (ublk_dev_support_batch_io(ub)) {
> @@ -4736,10 +4741,18 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
>  
>  	/* User copy is required to access integrity buffer */
>  	if (info.flags & UBLK_F_INTEGRITY && !(info.flags & UBLK_F_USER_COPY))
>  		return -EINVAL;
>  
> +	if (info.flags & UBLK_F_IO_DESC_SIZE) {
> +		if (info.io_desc_size < sizeof(struct ublksrv_io_desc) ||
> +		    info.io_desc_size % _Alignof(struct ublksrv_io_desc))
> +			return -EINVAL;
> +	} else {
> +		info.io_desc_size = sizeof(struct ublksrv_io_desc);
> +	}
> +

No upper bound on io_desc_size.

Also Missing selftest update — this causes generic_13 failure.

New feature needs sanity test to show it working at least.

Thanks,
Ming

  reply	other threads:[~2026-07-30 15:14 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-29  1:29 [PATCH 0/6] ublk: io_desc optimizations Caleb Sander Mateos
2026-07-29  1:29 ` [PATCH 1/6] ublk: consistently use u16 for queue and tag numbers Caleb Sander Mateos
2026-07-29 14:51   ` Ming Lei
2026-07-29  1:29 ` [PATCH 2/6] ublk: remove struct ublk_zoned_report_desc's operation field Caleb Sander Mateos
2026-07-29 14:58   ` Ming Lei
2026-07-29  1:29 ` [PATCH 3/6] ublk: split request validation from io_desc init Caleb Sander Mateos
2026-07-30 14:37   ` Ming Lei
2026-07-29  1:29 ` [PATCH 4/6] ublk: initialize io_desc on daemon task Caleb Sander Mateos
2026-07-30 15:10   ` Ming Lei
2026-07-29  1:29 ` [PATCH 5/6] ublk: add UBLK_F_IO_DESC_SIZE Caleb Sander Mateos
2026-07-30 15:14   ` Ming Lei [this message]
2026-07-30 15:52     ` Caleb Sander Mateos
2026-07-29  1:29 ` [PATCH 6/6] ublk: lift need_map check out of ublk_{,un}map_io() Caleb Sander Mateos
2026-07-30 15:17   ` Ming Lei
2026-07-30 15:54   ` Caleb Sander Mateos

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=amtqTIZiUgOrSJmg@fedora-laptop \
    --to=tom.leiming@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=csander@purestorage.com \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox