We cannot simply use the guest logical block size on the host; we need to ask the protocol driver about the minimum required alignment.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- block.c | 26 ++++++++++++++++++++++++-- block.h | 1 + block/raw-posix.c | 3 ++- block_int.h | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index d015887..aba92ad 100644 --- a/block.c +++ b/block.c @@ -476,7 +476,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename, bs->sg = 0; bs->open_flags = flags; bs->growable = 0; - bs->buffer_alignment = 512; + bs->buffer_alignment = 0; pstrcpy(bs->filename, sizeof(bs->filename), filename); bs->backing_file[0] = '\0'; @@ -1361,6 +1361,27 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) } /** + * Required buffer alignment for a file or device. Return < 0 if error or unknown. + */ +int bdrv_get_alignment(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (bs->buffer_alignment == 0) { + if (drv->bdrv_get_alignment) { + bs->buffer_alignment = drv->bdrv_get_alignment(bs); + } else if (bs->file) { + bs->buffer_alignment = bdrv_get_alignment(bs->file); + } else { + bs->buffer_alignment = BDRV_SECTOR_SIZE; + } + } + return bs->buffer_alignment; +} + +/** * Length of a file in bytes. Return < 0 if error or unknown. */ int64_t bdrv_getlength(BlockDriverState *bs) @@ -3025,7 +3046,8 @@ void bdrv_set_buffer_alignment(BlockDriverState *bs, int align) void *qemu_blockalign(BlockDriverState *bs, size_t size) { - return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size); + int alignment = bs ? bdrv_get_alignment(bs) : 512; + return qemu_memalign(alignment, size); } void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) diff --git a/block.h b/block.h index a826059..5fa632c 100644 --- a/block.h +++ b/block.h @@ -294,6 +294,7 @@ int bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, char *options, uint64_t img_size, int flags); +int bdrv_get_alignment(BlockDriverState *bs); void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); diff --git a/block/raw-posix.c b/block/raw-posix.c index a3de373..3482fc8 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -301,10 +301,11 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) */ static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) { + int alignment = bdrv_get_alignment(bs); int i; for (i = 0; i < qiov->niov; i++) { - if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) { + if ((uintptr_t) qiov->iov[i].iov_base % alignment) { return 0; } } diff --git a/block_int.h b/block_int.h index 77c0187..6caf063 100644 --- a/block_int.h +++ b/block_int.h @@ -113,6 +113,7 @@ struct BlockDriver { const char *protocol_name; int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int (*bdrv_get_alignment)(BlockDriverState *bs); int64_t (*bdrv_getlength)(BlockDriverState *bs); int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, -- 1.7.7.1