vmspawn: track removability as a QmpDriveFlags bit and expose add_block_device

Drives attached at boot via the existing CLI options (--image,
--extra-drive) must not be detachable at runtime via the upcoming
RemoveStorage Varlink method, while drives added at runtime via
AddStorage must be. Track this distinction with a new QMP_DRIVE_REMOVABLE
property flag — placed alongside QMP_DRIVE_BLOCK_DEVICE, not in the
transient BlockDeviceStateFlags state-machine, since "may be removed"
is a permanent property of the drive.

vmspawn_qmp_remove_block_device() now early-rejects unknown ids with
io.systemd.MachineInstance.NoSuchStorage and immutable drives with
io.systemd.MachineInstance.StorageImmutable.

vmspawn_qmp_add_block_device() loses its 'static' qualifier and gets a
declaration in the header, so the runtime hotplug path
(vmspawn-bind-volume.c, next) can dispatch into it directly.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-05-06 10:30:17 +02:00
parent aa02ad284e
commit 0e911e4164
2 changed files with 7 additions and 4 deletions
+5 -4
View File
@@ -826,7 +826,7 @@ static int on_add_device_add_complete(
return 0;
if (d->link) {
(void) sd_varlink_replybo(d->link, SD_JSON_BUILD_PAIR_STRING("id", d->id));
(void) sd_varlink_reply(d->link, NULL);
d->link = sd_varlink_unref(d->link);
}
@@ -882,7 +882,7 @@ static int qmp_setup_scsi_controller(VmspawnQmpBridge *bridge, const char *pcie_
return 0;
}
static int vmspawn_qmp_add_block_device(VmspawnQmpBridge *bridge, DriveInfo *drive) {
int vmspawn_qmp_add_block_device(VmspawnQmpBridge *bridge, DriveInfo *drive) {
int r;
assert(bridge);
@@ -989,7 +989,6 @@ static int qmp_setup_regular_drive(VmspawnQmpBridge *bridge, DriveInfo *drive) {
assert(bridge);
assert(drive);
assert(drive->fd >= 0);
assert(!drive->id);
return vmspawn_qmp_add_block_device(bridge, drive);
}
@@ -1028,7 +1027,9 @@ int vmspawn_qmp_remove_block_device(VmspawnQmpBridge *bridge, sd_varlink *link,
DriveInfo *drive = hashmap_get(bridge->block_devices, id);
if (!drive)
return reply_qmp_error(link, "Unknown block device id", -ENOENT);
return sd_varlink_error(link, "io.systemd.MachineInstance.NoSuchStorage", NULL);
if (!FLAGS_SET(drive->flags, QMP_DRIVE_REMOVABLE))
return sd_varlink_error(link, "io.systemd.MachineInstance.StorageImmutable", NULL);
if (!FLAGS_SET(drive->state, BLOCK_DEVICE_STATE_BLOCKDEV_ADDED))
return reply_qmp_error(link, "Block device add pending", -EBUSY);
if (FLAGS_SET(drive->state, BLOCK_DEVICE_STATE_REMOVE_PENDING))
+2
View File
@@ -72,6 +72,7 @@ typedef enum QmpDriveFlags {
QMP_DRIVE_BOOT = 1u << 4,
QMP_DRIVE_IO_URING = 1u << 5,
QMP_DRIVE_DISCARD_NO_UNREF = 1u << 6, /* qcow2 only */
QMP_DRIVE_REMOVABLE = 1u << 7, /* may be detached at runtime via RemoveStorage */
} QmpDriveFlags;
typedef enum BlockDeviceStateFlags {
@@ -177,5 +178,6 @@ int vmspawn_qmp_setup_drives(VmspawnQmpBridge *bridge, DriveInfos *drives);
int vmspawn_qmp_setup_network(VmspawnQmpBridge *bridge, NetworkInfo *network);
int vmspawn_qmp_setup_virtiofs(VmspawnQmpBridge *bridge, const VirtiofsInfos *virtiofs);
int vmspawn_qmp_setup_vsock(VmspawnQmpBridge *bridge, VsockInfo *vsock);
int vmspawn_qmp_add_block_device(VmspawnQmpBridge *bridge, DriveInfo *drive);
int vmspawn_qmp_remove_block_device(VmspawnQmpBridge *bridge, sd_varlink *link, const char *id);
int vmspawn_qmp_dispatch_device_deleted(VmspawnQmpBridge *bridge, sd_json_variant *data);