diff --git a/tools/include/xen-tools/common-macros.h b/tools/include/xen-tools/common-macros.h index 9e27991782..88b4a0e5a6 100644 --- a/tools/include/xen-tools/common-macros.h +++ b/tools/include/xen-tools/common-macros.h @@ -69,6 +69,7 @@ #endif #define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ROUNDDOWN(x, a) ((x) & ~((a) - 1)) #define MASK_EXTR(v, m) (((v) & (m)) / ((m) & -(m))) #define MASK_INSR(v, m) (((v) * ((m) & -(m))) & (m)) diff --git a/tools/tests/numa/test-numa.c b/tools/tests/numa/test-numa.c index ed91a2824f..51cc0475c7 100644 --- a/tools/tests/numa/test-numa.c +++ b/tools/tests/numa/test-numa.c @@ -154,6 +154,51 @@ int main(int argc, char **argv) { .start = 0x183f8800000ULL, .end = 0x183faabffffULL }, }, }, + /* Found on a pre-production system. */ + { + .affinity = { + { .nid = 0, .start = 0x00000000000ULL, .end = 0x000afffffffULL }, + { .nid = 0, .start = 0x00100000000ULL, .end = 0x0fc4fffffffULL }, + { .nid = 0, .start = 0x10000000000ULL, .end = 0x103ffffffffULL }, + { .nid = 1, .start = 0x10400000000ULL, .end = 0x203ffffffffULL }, + }, + .ram = { + { .start = 0x00000000000ULL, .end = 0x0000009ffffULL }, + { .start = 0x00000100000ULL, .end = 0x000165bffffULL }, + { .start = 0x00016600000ULL, .end = 0x0001aa1dfffULL }, + { .start = 0x0001aa1f000ULL, .end = 0x0001aa53fffULL }, + { .start = 0x0001aab8000ULL, .end = 0x0001aac6fffULL }, + { .start = 0x0001aacc000ULL, .end = 0x0006f3fefffULL }, + { .start = 0x00075dff000ULL, .end = 0x00075dfffffULL }, + { .start = 0x00076000000ULL, .end = 0x000a7ffffffULL }, + { .start = 0x00100010000ULL, .end = 0x0fc43ffffffULL }, + { .start = 0x0fc45000000ULL, .end = 0x0fc47ffffffULL }, + { .start = 0x0fc49000000ULL, .end = 0x0fc4bffffffULL }, + { .start = 0x0fc4d000000ULL, .end = 0x0fc4d3bffffULL }, + { .start = 0x0fc4f000000ULL, .end = 0x0fc4f0fffffULL }, + { .start = 0x10000000000ULL, .end = 0x203fd7fffffULL }, + }, + }, + /* + * Reduction of the issue above: introduce an unaligned middle region + * with regards to the hash shift. + */ + { + .affinity = { + { .nid = 0, .start = 0x00000ULL, .end = 0x00fffULL }, + /* + * The offset of the region below is not aligned with the hash + * shift: the shift calculation only takes into account the + * start of node address. + */ + { .nid = 0, .start = 0x01000ULL, .end = 0x04fffULL }, + { .nid = 1, .start = 0x14000ULL, .end = 0x14fffULL }, + }, + .ram = { + { .start = 0x00000ULL, .end = 0x04fffULL }, + { .start = 0x14000ULL, .end = 0x14fffULL }, + }, + }, }; int ret_code = EXIT_SUCCESS; diff --git a/xen/common/numa.c b/xen/common/numa.c index 8544a15982..92f8f1cedc 100644 --- a/xen/common/numa.c +++ b/xen/common/numa.c @@ -405,6 +405,12 @@ static int __init populate_memnodemap(const struct node *nodes, if ( (epdx >> shift) >= memnodemapsize ) return 0; + /* + * Round down start address: if start is not aligned to the memnodemap + * chunk size the tail remainder might not be added. Overlaps created + * by rounding will fall into the same NUMA region. + */ + spdx = ROUNDDOWN(spdx, 1UL << shift); do { if ( memnodemap[spdx >> shift] != NUMA_NO_NODE && (!nodeids || memnodemap[spdx >> shift] != nodeids[i]) )