domain_validate: Move memdevice address conflict check into a separate function

At the end of virDomainMemoryDefValidate() there's a code that
checks whether two virtio-mem/virtio-pmem devices don't overlap.
Separate this code into its own function
(virDomainMemoryDefCheckConflict()).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
Michal Privoznik 2023-11-02 16:05:46 +01:00
parent 784a63c189
commit 3d017fb651

View File

@ -2217,15 +2217,96 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev)
}
static int
virDomainMemoryDefCheckConflict(const virDomainMemoryDef *mem,
const virDomainDef *def)
{
unsigned long long thisStart = 0;
unsigned long long thisEnd = 0;
size_t i;
switch (mem->model) {
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
thisStart = mem->target.virtio_pmem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
thisStart = mem->target.virtio_mem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
}
if (thisStart == 0) {
return 0;
}
/* thisStart and thisEnd are in bytes, mem->size in kibibytes */
thisEnd = thisStart + mem->size * 1024;
for (i = 0; i < def->nmems; i++) {
const virDomainMemoryDef *other = def->mems[i];
unsigned long long otherStart = 0;
if (other == mem)
continue;
/* In case we're updating an existing memory device (e.g. virtio-mem),
* then pointers will be different. But addresses and aliases are the
* same. However, STREQ_NULLABLE() returns true if both strings are
* NULL which is not what we want. */
if (virDomainDeviceInfoAddressIsEqual(&other->info,
&mem->info)) {
continue;
}
if (mem->info.alias &&
STREQ_NULLABLE(other->info.alias,
mem->info.alias)) {
continue;
}
switch (other->model) {
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
continue;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
otherStart = other->target.virtio_pmem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
otherStart = other->target.virtio_mem.address;
break;
}
if (otherStart == 0)
continue;
if (thisStart <= otherStart && thisEnd > otherStart) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("memory device address [0x%1$llx:0x%2$llx] overlaps with other memory device (0x%3$llx)"),
thisStart, thisEnd, otherStart);
return -1;
}
}
return 0;
}
static int
virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
const virDomainDef *def)
{
const long pagesize = virGetSystemPageSize();
unsigned long long thpSize;
unsigned long long thisStart = 0;
unsigned long long thisEnd = 0;
size_t i;
/* Guest NUMA nodes are continuous and indexed from zero. */
if (mem->targetNode != -1) {
@ -2307,7 +2388,6 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
pagesize);
return -1;
}
thisStart = mem->target.virtio_pmem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
@ -2351,7 +2431,6 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
_("memory device address must be aligned to blocksize"));
return -1;
}
thisStart = mem->target.virtio_mem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
@ -2373,62 +2452,8 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
return -1;
}
if (thisStart == 0) {
return 0;
}
/* thisStart and thisEnd are in bytes, mem->size in kibibytes */
thisEnd = thisStart + mem->size * 1024;
for (i = 0; i < def->nmems; i++) {
const virDomainMemoryDef *other = def->mems[i];
unsigned long long otherStart = 0;
if (other == mem)
continue;
/* In case we're updating an existing memory device (e.g. virtio-mem),
* then pointers will be different. But addresses and aliases are the
* same. However, STREQ_NULLABLE() returns true if both strings are
* NULL which is not what we want. */
if (virDomainDeviceInfoAddressIsEqual(&other->info,
&mem->info)) {
continue;
}
if (mem->info.alias &&
STREQ_NULLABLE(other->info.alias,
mem->info.alias)) {
continue;
}
switch (other->model) {
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
continue;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
otherStart = other->target.virtio_pmem.address;
break;
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
otherStart = other->target.virtio_mem.address;
break;
}
if (otherStart == 0)
continue;
if (thisStart <= otherStart && thisEnd > otherStart) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("memory device address [0x%1$llx:0x%2$llx] overlaps with other memory device (0x%3$llx)"),
thisStart, thisEnd, otherStart);
return -1;
}
}
if (virDomainMemoryDefCheckConflict(mem, def) < 0)
return -1;
return 0;
}