[PATCH v2 1/1] virtio: blk: support block sizes exceeding 512 bytes
    Andre Przywara 
    andre.przywara at arm.com
       
    Thu Oct  9 17:21:41 CEST 2025
    
    
  
On Wed, 8 Oct 2025 23:23:17 +0200
Heinrich Schuchardt <heinrich.schuchardt at canonical.com> wrote:
Hi Heinrich,
thanks for the quick reply!
> On 10/8/25 17:39, Andre Przywara wrote:
> > On Sat, 30 Aug 2025 22:39:54 +0200
> > Heinrich Schuchardt <heinrich.schuchardt at canonical.com> wrote:
> > 
> > Hi Heinrich,
> >   
> >> QEMU allows to specify the logical block size via parameter
> >> logical_block_size of a virtio-blk-device.
> >>
> >> The communication channel via virtqueues remains based on 512 byte blocks
> >> even if the logical_block_size is larger.
> >>
> >> Consider the logical block size in the block device driver.
> >>
> >> Reported-by: Emil Renner Berthing <emil.renner.berthing at canonical.com>
> >> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt at canonical.com>
> >> ---
> >> v2:
> >> 	remove superfluous include linux/err.h
> >> ---
> >>   drivers/virtio/virtio_blk.c | 25 ++++++++++++++++++++++---
> >>   1 file changed, 22 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
> >> index 2f999fc8bbe..4224e3c17f4 100644
> >> --- a/drivers/virtio/virtio_blk.c
> >> +++ b/drivers/virtio/virtio_blk.c
> >> @@ -12,10 +12,17 @@
> >>   #include <virtio_types.h>
> >>   #include <virtio.h>
> >>   #include <virtio_ring.h>
> >> +#include <linux/log2.h>
> >>   #include "virtio_blk.h"
> >>   
> >> +/**
> >> + * struct virtio_blk_priv - private date for virtio block device
> >> + */
> >>   struct virtio_blk_priv {
> >> +	/** @virtqueue - virtqueue to process */
> >>   	struct virtqueue *vq;
> >> +	/** @blksz_shift - log2 of block size divided by 512 */
> >> +	u32 blksz_shift;
> >>   };
> >>   
> >>   static const u32 feature[] = {
> >> @@ -71,6 +78,8 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector,
> >>   	u8 status;
> >>   	int ret;
> >>   
> >> +	sector <<= priv->blksz_shift;
> >> +	blkcnt <<= priv->blksz_shift;
> >>   	virtio_blk_init_header_sg(dev, sector, type, &out_hdr, &hdr_sg);
> >>   	sgs[num_out++] = &hdr_sg;
> >>   
> >> @@ -109,7 +118,7 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector,
> >>   		;
> >>   	log_debug("done\n");
> >>   
> >> -	return status == VIRTIO_BLK_S_OK ? blkcnt : -EIO;
> >> +	return status == VIRTIO_BLK_S_OK ? blkcnt >> priv->blksz_shift : -EIO;
> >>   }
> >>   
> >>   static ulong virtio_blk_read(struct udevice *dev, lbaint_t start,
> >> @@ -177,15 +186,25 @@ static int virtio_blk_probe(struct udevice *dev)
> >>   	struct blk_desc *desc = dev_get_uclass_plat(dev);
> >>   	u64 cap;
> >>   	int ret;
> >> +	u32 blk_size;
> >>   
> >>   	ret = virtio_find_vqs(dev, 1, &priv->vq);
> >>   	if (ret)
> >>   		return ret;
> >>   
> >> -	desc->blksz = 512;
> >> -	desc->log2blksz = 9;
> >>   	virtio_cread(dev, struct virtio_blk_config, capacity, &cap);
> >>   	desc->lba = cap;
> >> +	if (!virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) {  
> > 
> > Is that actually the right condition check? I would assume that we only
> > query the blk_size field if the feature bit is *set*, not when it's
> > cleared?
> > We see a failure (virtio block device not registering), because blk_size is
> > 0 on the Arm FVP fast model, which is fine I think because the feature bit
> > is clear as well.
> > 
> > Cheers,
> > Andre  
> 
> Hello Andre,
> 
> Thanks for sharing your test results.
> 
> Looking at these QEMU lines, I think the evaluated feature flag is correct:
> 
> pc-bios/s390-ccw/virtio.h:163:
> uint32_t blk_size; /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
> 
> include/standard-headers/linux/virtio_blk.h:72-73:
> /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
> __virtio32 blk_size;
> 
> virtio_has_feature() cannot detect a feature if is not in the feature 
> set of the U-Boot driver. See function virtio_uclass_child_pre_probe():
> 
>      uc_priv->features = driver_features_legacy & device_features;
> 
> VIRTIO_BLK_F_BLK_SIZE is missing in the feature set of virtio_blk.
> The not in front of virtio_has_feature() is wrong.
Ah, indeed a double whammy: the feature bit was filtered, AND the logic
twisted, that's why it worked.
I applied your patch, and tested with the FVP and with QEMU, trying both
block sizes there: seems to work fine now.
Are you going to send a proper patch (since you have it already)?
If so, add: Reported-by: Debbie Horsfall <debbie.horsfall at arm.com>,
because she found the issue.
Thanks!
Andre
> 
> Could you, please, retest with this diff:
> 
> diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
> index 4224e3c17f4..ec2e28b54f7 100644
> --- a/drivers/virtio/virtio_blk.c
> +++ b/drivers/virtio/virtio_blk.c
> @@ -26,6 +26,7 @@ struct virtio_blk_priv {
>   };
> 
>   static const u32 feature[] = {
> +       VIRTIO_BLK_F_BLK_SIZE,
>          VIRTIO_BLK_F_WRITE_ZEROES
>   };
> 
> @@ -194,7 +195,7 @@ static int virtio_blk_probe(struct udevice *dev)
> 
>          virtio_cread(dev, struct virtio_blk_config, capacity, &cap);
>          desc->lba = cap;
> -       if (!virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) {
> +       if (virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) {
>                  virtio_cread(dev, struct virtio_blk_config, blk_size, 
> &blk_size);
>                  desc->blksz = blk_size;
>                  if (!is_power_of_2(blk_size) || desc->blksz < 512)
> 
> Best regards
> 
> Heinrich
> 
> >   
> >> +		virtio_cread(dev, struct virtio_blk_config, blk_size, &blk_size);
> >> +		desc->blksz = blk_size;
> >> +		if (!is_power_of_2(blk_size) || desc->blksz < 512)
> >> +			return -EIO;
> >> +	} else {
> >> +		desc->blksz = 512;
> >> +	}
> >> +	desc->log2blksz = LOG2(desc->blksz);
> >> +	priv->blksz_shift = desc->log2blksz - 9;
> >> +	desc->lba >>= priv->blksz_shift;
> >>   
> >>   	return 0;
> >>   }  
> >   
> 
    
    
More information about the U-Boot
mailing list