]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: track removability as a QmpDriveFlags bit and expose add_block_device
authorChristian Brauner <brauner@kernel.org>
Fri, 1 May 2026 11:34:06 +0000 (13:34 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 6 May 2026 08:30:17 +0000 (10:30 +0200)
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>
src/vmspawn/vmspawn-qmp.c
src/vmspawn/vmspawn-qmp.h

index d09576213a1633f88f9080304d59eee936cb6aff..52d9e11b9f89eb88a5b4630c29b1329102719604 100644 (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))
index d8403520c9afebee4654a51e9656d719c0cf899e..a2f929732086ecda7eb64c12b37e8c4b7842b440 100644 (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);