From 47c4ecd4d6f10a66a1a3aafa690da45152067017 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Mon, 20 Jul 2026 02:21:25 +0800 Subject: [PATCH] fix(drivers): query real HVC block capacity instead of hardcoding 512 GiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arcbox_hvc_blk hardcoded set_capacity to (sector_t)1<<30 (512 GiB) with 'VMM validates sector range' — but that only bounds I/O; the size the kernel and filesystem see was simply wrong. docker.img is an 8 TiB sparse file whose Btrfs metadata is grown to the visible size on each boot. Under VZ the guest saw 8 TiB; switching to the HV backend exposed only the hardcoded 512 GiB, so Btrfs refused to mount the data disk (open_ctree failed: total_bytes should be at most 549755813888 but found 8796093022208), permanently breaking Docker until the engine was switched back. Add ARCBOX_HVC_BLK_CAPACITY (0xC2000004) and query it per device, using the host's real capacity_sectors. Falls back to the previous fixed size when the host predates the call, so old-host/new-guest is unchanged. --- drivers/arcbox_hvc_blk.c | 51 +++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/arcbox_hvc_blk.c b/drivers/arcbox_hvc_blk.c index 64e3440..026f25c 100644 --- a/drivers/arcbox_hvc_blk.c +++ b/drivers/arcbox_hvc_blk.c @@ -7,10 +7,11 @@ * on the host file, bypassing VirtIO queues entirely. * * SMCCC function IDs (vendor-specific range): - * 0xC2000000 ARCBOX_HVC_PROBE -- returns number of block devices - * 0xC2000001 ARCBOX_HVC_BLK_READ -- synchronous pread - * 0xC2000002 ARCBOX_HVC_BLK_WRITE -- synchronous pwrite - * 0xC2000003 ARCBOX_HVC_BLK_FLUSH -- fsync + * 0xC2000000 ARCBOX_HVC_PROBE -- returns number of block devices + * 0xC2000001 ARCBOX_HVC_BLK_READ -- synchronous pread + * 0xC2000002 ARCBOX_HVC_BLK_WRITE -- synchronous pwrite + * 0xC2000003 ARCBOX_HVC_BLK_FLUSH -- fsync + * 0xC2000004 ARCBOX_HVC_BLK_CAPACITY -- device capacity in 512B sectors */ #include @@ -19,11 +20,18 @@ #include #include -#define ARCBOX_HVC_PROBE 0xC2000000 -#define ARCBOX_HVC_BLK_READ 0xC2000001 -#define ARCBOX_HVC_BLK_WRITE 0xC2000002 -#define ARCBOX_HVC_BLK_FLUSH 0xC2000003 -#define ARCBOX_HVC_SECTOR 512 +#define ARCBOX_HVC_PROBE 0xC2000000 +#define ARCBOX_HVC_BLK_READ 0xC2000001 +#define ARCBOX_HVC_BLK_WRITE 0xC2000002 +#define ARCBOX_HVC_BLK_FLUSH 0xC2000003 +#define ARCBOX_HVC_BLK_CAPACITY 0xC2000004 +#define ARCBOX_HVC_SECTOR 512 + +/* + * Fallback capacity for hosts that predate ARCBOX_HVC_BLK_CAPACITY: the old + * fixed placeholder (512 GiB in sectors). Only used when the query fails. + */ +#define ARCBOX_HVC_DEFAULT_SECTORS ((sector_t)1 << 30) #define DRIVER_NAME "arcbox_hvc_blk" #define MAX_DEVICES 8 @@ -58,6 +66,24 @@ static int arcbox_hvc_flush(unsigned int idx) return (long)res.a0 < 0 ? (int)(long)res.a0 : 0; } +/* + * Query the device's real capacity in sectors. Returns the fixed fallback if + * the host is older than ARCBOX_HVC_BLK_CAPACITY (negative/zero result), so an + * old host keeps its previous behavior; a current host reports the true size, + * which the guest must honor or Btrfs will reject a data disk whose metadata + * records a larger size. + */ +static sector_t arcbox_hvc_capacity(unsigned int idx) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_hvc(ARCBOX_HVC_BLK_CAPACITY, idx, 0, 0, 0, 0, 0, 0, &res); + + if ((long)res.a0 <= 0) + return ARCBOX_HVC_DEFAULT_SECTORS; + return (sector_t)res.a0; +} + static blk_status_t arcbox_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { @@ -153,8 +179,11 @@ static int arcbox_probe_one(int idx) disk->fops = &arcbox_fops; snprintf(disk->disk_name, DISK_NAME_LEN, "arcboxhvc%d", idx); - /* Large default capacity — VMM validates sector range. */ - set_capacity(disk, (sector_t)1 << 30); + /* Use the host-reported capacity so the guest sees the true disk size. + * A hardcoded value that undershoots the backing file silently corrupts + * a Btrfs data disk whose metadata records the real (larger) size. + */ + set_capacity(disk, arcbox_hvc_capacity(idx)); err = add_disk(disk); if (err) {