[PATCH 1/2] Add RW support for 4k sector size vhdx

2024-11-12 Thread Takeshi Suzuki
Signed-off-by: Takeshi Suzuki 
---
 block/vhdx.c | 76 +++-
 1 file changed, 70 insertions(+), 6 deletions(-)

diff --git a/block/vhdx.c b/block/vhdx.c
index 5aa1a13506..495ddc2815 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -824,8 +824,8 @@ vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
 goto exit;
 }
 
-/* Currently we only support 512 */
-if (s->logical_sector_size != 512) {
+/* Currently we only support 512 and 4096 */
+if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
 ret = -ENOTSUP;
 goto exit;
 }
@@ -1060,7 +1060,7 @@ static int vhdx_open(BlockDriverState *bs, QDict 
*options, int flags,
 
 /* the VHDX spec dictates that virtual_disk_size is always a multiple of
  * logical_sector_size */
-bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits;
+bs->total_sectors = s->virtual_disk_size >> BDRV_SECTOR_BITS;
 
 vhdx_calc_bat_entries(s);
 
@@ -1178,11 +1178,52 @@ vhdx_co_get_info(BlockDriverState *bs, BlockDriverInfo 
*bdi)
 }
 
 
+/*
+ * Converts bdrv sectors to sectors of s->logical_sector_size.
+ */
+static void bdrv_sectors_to_sectors(const int64_t bdrv_sector_num,
+const int bdrv_nb_sectors,
+const BDRVVHDXState *const s,
+int64_t * const out_sector_num,
+int * const out_nb_sectors,
+/* in bytes */
+int * const out_begin_skip,
+/* in bytes */
+int * const out_end_skip) {
+if (bdrv_nb_sectors == 0) {
+*out_nb_sectors = 0;
+return;
+}
+const int64_t begin_off = bdrv_sector_num * BDRV_SECTOR_SIZE;
+const int64_t sector_num = begin_off >> s->logical_sector_size_bits;
+const int begin_skip = begin_off - sector_num * s->logical_sector_size;
+const int64_t end_off = (bdrv_sector_num + bdrv_nb_sectors) *
+BDRV_SECTOR_SIZE;
+const int64_t end_sector_num = (end_off + s->logical_sector_size - 1) >>
+   s->logical_sector_size_bits;
+const int end_skip = end_sector_num * s->logical_sector_size - end_off;
+const int nb_sectors = end_sector_num - sector_num;
+*out_sector_num = sector_num;
+*out_nb_sectors = nb_sectors;
+*out_begin_skip = begin_skip;
+*out_end_skip = end_skip;
+}
+
+
 static int coroutine_fn GRAPH_RDLOCK
 vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
   QEMUIOVector *qiov)
 {
 BDRVVHDXState *s = bs->opaque;
+int begin_skip, end_skip;
+bdrv_sectors_to_sectors(sector_num,
+nb_sectors,
+s,
+§or_num,
+&nb_sectors,
+&begin_skip,
+&end_skip);
+
 int ret = 0;
 VHDXSectorInfo sinfo;
 uint64_t bytes_done = 0;
@@ -1216,9 +1257,16 @@ vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, 
int nb_sectors,
 qemu_iovec_memset(&hd_qiov, 0, 0, sinfo.bytes_avail);
 break;
 case PAYLOAD_BLOCK_FULLY_PRESENT:
+if (bytes_done == 0) {
+sinfo.file_offset += begin_skip;
+sinfo.bytes_avail -= begin_skip;
+}
+if (nb_sectors - sinfo.sectors_avail <= 0) {
+sinfo.bytes_avail -= end_skip;
+}
 qemu_co_mutex_unlock(&s->lock);
 ret = bdrv_co_preadv(bs->file, sinfo.file_offset,
- sinfo.sectors_avail * BDRV_SECTOR_SIZE,
+ sinfo.bytes_avail,
  &hd_qiov, 0);
 qemu_co_mutex_lock(&s->lock);
 if (ret < 0) {
@@ -1336,8 +1384,17 @@ static int coroutine_fn GRAPH_RDLOCK
 vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov, int flags)
 {
-int ret = -ENOTSUP;
 BDRVVHDXState *s = bs->opaque;
+int begin_skip, end_skip;
+bdrv_sectors_to_sectors(sector_num,
+nb_sectors,
+s,
+§or_num,
+&nb_sectors,
+&begin_skip,
+&end_skip);
+
+int ret = -ENOTSUP;
 VHDXSectorInfo sinfo;
 uint64_t bytes_done = 0;
 uint64_t bat_entry = 0;
@@ -1451,9 +1508,16 @@ vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, 
int nb_sectors,
   sinfo.bytes_avail);
 }
 /* block exists, so we can just overwrite it */
+   

[PATCH 2/2] Add iotest for 4k sector size vhdx

2024-11-12 Thread Takeshi Suzuki
See
https://github.com/takeshibaconsuzuki/qemu/blob/vhdx_4k_rw/tests/qemu-iotests/sample_images/4k.vhdx.bz2
for binary file.

Signed-off-by: Takeshi Suzuki 
---
 tests/qemu-iotests/315   |  65 +++
 tests/qemu-iotests/315.out   |  20 ++
 tests/qemu-iotests/sample_images/4k.vhdx.bz2 | Bin 0 -> 37834 bytes
 3 files changed, 85 insertions(+)
 create mode 100644 tests/qemu-iotests/315
 create mode 100644 tests/qemu-iotests/315.out
 create mode 100644 tests/qemu-iotests/sample_images/4k.vhdx.bz2

diff --git a/tests/qemu-iotests/315 b/tests/qemu-iotests/315
new file mode 100644
index 00..e5c4978c8c
--- /dev/null
+++ b/tests/qemu-iotests/315
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+# group: rw quick
+#
+# Test VHDX read/write from a 4k sector size sample image created with Hyper-V
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see .
+#
+
+# creator
+owner=takeshibaconsuz...@gmail.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1   # failure is the default!
+
+_cleanup()
+{
+_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt vhdx
+_supported_proto generic
+_supported_os Linux
+
+_use_sample_img 4k.vhdx.bz2
+
+echo
+echo "=== Verify pattern 0xaa, 1024MB - 1088MB ==="
+$QEMU_IO -r -c "read -pP 0xaa 1024M 64M" "$TEST_IMG" | _filter_qemu_io
+echo
+echo "=== Verify pattern 0x00, 1088MB - 1152MB ==="
+$QEMU_IO -r -c "read -pP 0x00 1088M 64M" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== Verify pattern write, 0xbb 1072MB - 1104MB ==="
+$QEMU_IO -c "write -pP 0xbb 1072M 32M" "$TEST_IMG" | _filter_qemu_io
+# first verify we didn't write where we should not have
+$QEMU_IO -r -c "read -pP 0xaa 1024M 48M" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -r -c "read -pP 0x00 1104M 48M" "$TEST_IMG" | _filter_qemu_io
+# now verify what we should have actually written
+$QEMU_IO -r -c "read -pP 0xbb 1072M 32M" "$TEST_IMG" | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/315.out b/tests/qemu-iotests/315.out
new file mode 100644
index 00..31dd48b223
--- /dev/null
+++ b/tests/qemu-iotests/315.out
@@ -0,0 +1,20 @@
+QA output created by 315
+
+=== Verify pattern 0xaa, 1024MB - 1088MB ===
+read 67108864/67108864 bytes at offset 1073741824
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify pattern 0x00, 1088MB - 1152MB ===
+read 67108864/67108864 bytes at offset 1140850688
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify pattern write, 0xbb 1072MB - 1104MB ===
+wrote 33554432/33554432 bytes at offset 1124073472
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 50331648/50331648 bytes at offset 1073741824
+48 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 50331648/50331648 bytes at offset 1157627904
+48 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 33554432/33554432 bytes at offset 1124073472
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/sample_images/4k.vhdx.bz2 
b/tests/qemu-iotests/sample_images/4k.vhdx.bz2
new file mode 100644
index 00..6cc10919ab
Binary files /dev/null and b/tests/qemu-iotests/sample_images/4k.vhdx.bz2 differ
-- 
2.34.1




[PATCH 0/2] Add RW support for 4k sector size vhdx

2024-11-12 Thread Takeshi Suzuki
The first patch adds support to read and write VHDX images with 4k logical
sector sizes. This is done by internally converting bdrv sectors of size 512 to
logical sectors. VHDX image creation with 4k logical sector size is NOT
implemented.

The second patch adds an iotest which reads and writes to a VHDX image with 4k
logical sector size.

Takeshi Suzuki (2):
  Add RW support for 4k sector size vhdx
  Add iotest for 4k sector size vhdx

 block/vhdx.c |  76 +--
 tests/qemu-iotests/315   |  65 
 tests/qemu-iotests/315.out   |  20 +
 tests/qemu-iotests/sample_images/4k.vhdx.bz2 | Bin 0 -> 37834 bytes
 4 files changed, 155 insertions(+), 6 deletions(-)
 create mode 100644 tests/qemu-iotests/315
 create mode 100644 tests/qemu-iotests/315.out
 create mode 100644 tests/qemu-iotests/sample_images/4k.vhdx.bz2

-- 
2.34.1