diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index bc3d00f89c..b4ffef919a 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -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; }