diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4799070bc4..db42918d79 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -28918,6 +28918,30 @@ virDomainFSRemove(virDomainDef *def, size_t i) return fs; } +ssize_t +virDomainFSDefFind(virDomainDef *def, + virDomainFSDef *fs) +{ + size_t i = 0; + + for (i = 0; i < def->nfss; i++) { + virDomainFSDef *tmp = def->fss[i]; + + if (fs->dst && STRNEQ_NULLABLE(fs->dst, tmp->dst)) + continue; + + if (fs->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + !virDomainDeviceInfoAddressIsEqual(&fs->info, &tmp->info)) + continue; + + if (fs->info.alias && STRNEQ_NULLABLE(fs->info.alias, tmp->info.alias)) + continue; + + return i; + } + return -1; +} + virDomainFSDef * virDomainGetFilesystemForTarget(virDomainDef *def, const char *target) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index c1871b1757..79a27a0a36 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3765,6 +3765,8 @@ virDomainFSDef *virDomainGetFilesystemForTarget(virDomainDef *def, int virDomainFSInsert(virDomainDef *def, virDomainFSDef *fs); int virDomainFSIndexByName(virDomainDef *def, const char *name); virDomainFSDef *virDomainFSRemove(virDomainDef *def, size_t i); +ssize_t virDomainFSDefFind(virDomainDef *def, + virDomainFSDef *fs); unsigned int virDomainVideoDefaultRAM(const virDomainDef *def, const virDomainVideoType type); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 516b3692b2..c5d788285e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -410,6 +410,7 @@ virDomainFeatureTypeFromString; virDomainFeatureTypeToString; virDomainFSAccessModeTypeToString; virDomainFSCacheModeTypeToString; +virDomainFSDefFind; virDomainFSDefFree; virDomainFSDefNew; virDomainFSDriverTypeToString; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5289b57f04..b113a5bc1e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5206,6 +5206,47 @@ qemuDomainRemoveRedirdevDevice(virQEMUDriver *driver, } +static int +qemuDomainRemoveFSDevice(virQEMUDriver *driver, + virDomainObj *vm, + virDomainFSDef *fs) +{ + g_autofree char *charAlias = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + ssize_t idx; + int rc = 0; + + VIR_DEBUG("Removing FS device %s from domain %p %s", + fs->info.alias, vm, vm->def->name); + + if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_VIRTIOFS) { + charAlias = qemuDomainGetVhostUserChrAlias(fs->info.alias); + + qemuDomainObjEnterMonitor(driver, vm); + + if (qemuMonitorDetachCharDev(priv->mon, charAlias) < 0) + rc = -1; + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + } + + virDomainAuditFS(vm, fs, NULL, "detach", rc == 0); + + if (rc < 0) + return -1; + + if (!fs->sock && fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_VIRTIOFS) + qemuVirtioFSStop(driver, vm, fs); + + if ((idx = virDomainFSDefFind(vm->def, fs)) >= 0) + virDomainFSRemove(vm->def, idx); + qemuDomainReleaseDeviceAddress(vm, &fs->info); + virDomainFSDefFree(fs); + return 0; +} + + static void qemuDomainRemoveAuditDevice(virDomainObj *vm, virDomainDeviceDef *detach, @@ -5244,6 +5285,10 @@ qemuDomainRemoveAuditDevice(virDomainObj *vm, virDomainAuditRedirdev(vm, detach->data.redirdev, "detach", success); break; + case VIR_DOMAIN_DEVICE_FS: + virDomainAuditFS(vm, detach->data.fs, NULL, "detach", success); + break; + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_CONTROLLER: case VIR_DOMAIN_DEVICE_WATCHDOG: @@ -5251,7 +5296,6 @@ qemuDomainRemoveAuditDevice(virDomainObj *vm, /* These devices don't have associated audit logs */ break; - case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: case VIR_DOMAIN_DEVICE_GRAPHICS: @@ -5349,9 +5393,13 @@ qemuDomainRemoveDevice(virQEMUDriver *driver, return -1; break; + case VIR_DOMAIN_DEVICE_FS: + if (qemuDomainRemoveFSDevice(driver, vm, dev->data.fs) < 0) + return -1; + break; + case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LEASE: - case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: case VIR_DOMAIN_DEVICE_GRAPHICS: @@ -6046,6 +6094,31 @@ qemuDomainDetachPrepVsock(virDomainObj *vm, } +static int +qemuDomainDetachPrepFS(virDomainObj *vm, + virDomainFSDef *match, + virDomainFSDef **detach) +{ + ssize_t idx; + + if ((idx = virDomainFSDefFind(vm->def, match)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("matching filesystem not found")); + return -1; + } + + if (vm->def->fss[idx]->fsdriver != VIR_DOMAIN_FS_DRIVER_TYPE_VIRTIOFS) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("only virtiofs filesystems can be hotplugged")); + return -1; + } + + *detach = vm->def->fss[idx]; + + return 0; +} + + static int qemuDomainDetachDeviceLease(virQEMUDriver *driver, virDomainObj *vm, @@ -6167,6 +6240,12 @@ qemuDomainDetachDeviceLive(virDomainObj *vm, break; case VIR_DOMAIN_DEVICE_FS: + if (qemuDomainDetachPrepFS(vm, match->data.fs, + &detach.data.fs) < 0) { + return -1; + } + break; + case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: case VIR_DOMAIN_DEVICE_GRAPHICS: