
 Version 2: including fixes suggested by working on the man page; particularly
  changing references to "task" to "thread".

 The 5 system calls that libnuma provides are defined in the versions.ldscript:
  version 1:
    set_mempolicy
    get_mempolicy
    mbind
  version 2:
    set_mempolicy
    get_mempolicy
    mbind
    move_pages
    migrate_pages

Diffed against numactl-1.0.2

Signed-off-by: Cliff Wickman <cpw@sgi.com>


 Makefile               |    2 
 libnuma.c              |  942 ++++++++++++++++++++++++++++++++++++++++---------
 memhog.c               |   12 
 migratepages.c         |   12 
 migspeed.c             |   16 
 numa.h                 |   78 ++--
 numactl.c              |   58 ++-
 numademo.c             |    6 
 numaint.h              |   18 
 shm.c                  |   16 
 stream_main.c          |    8 
 syscall.c              |   33 +
 test/distance.c        |    2 
 test/mbind_mig_pages.c |    8 
 test/migrate_pages.c   |    8 
 test/nodemap.c         |    6 
 test/prefered.c        |   12 
 test/tbitmap.c         |   10 
 util.c                 |  194 ----------
 versions.ldscript      |  143 +++++++
 20 files changed, 1124 insertions(+), 460 deletions(-)

Index: numactl-1.0.2/syscall.c
===================================================================
--- numactl-1.0.2.orig/syscall.c
+++ numactl-1.0.2/syscall.c
@@ -143,8 +143,8 @@ long WEAK get_mempolicy(int *policy, con
 long WEAK mbind(void *start, unsigned long len, int mode, 
 	const unsigned long *nmask, unsigned long maxnode, unsigned flags)
 {
-	return syscall6(__NR_mbind, (long)start, len, mode, nmask, maxnode,
-							flags);
+	return syscall6(__NR_mbind, (long)start, len, mode, (long)nmask,
+				maxnode, flags);
 }
 
 long WEAK set_mempolicy(int mode, const unsigned long *nmask, 
@@ -168,22 +168,37 @@ long WEAK move_pages(int pid, unsigned l
 }
 
 /* SLES8 glibc doesn't define those */
+int numa_sched_setaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask)
+{
+	return syscall(__NR_sched_setaffinity,pid,len,mask);
+}
+__asm__(".symver numa_sched_setaffinity_v1,numa_sched_setaffinity@libnuma_1.1");
 
-int numa_sched_setaffinity(pid_t pid, struct bitmask *mask)
+int numa_sched_setaffinity_v2(pid_t pid, struct bitmask *mask)
 {
-	return syscall(__NR_sched_setaffinity, pid, bitmask_nbytes(mask),
+	return syscall(__NR_sched_setaffinity, pid, numa_bitmask_nbytes(mask),
 								mask->maskp);
 }
+__asm__(".symver numa_sched_setaffinity_v2,numa_sched_setaffinity@@libnuma_1.2");
+
+int numa_sched_getaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask)
+{
+	return syscall(__NR_sched_getaffinity,pid,len,mask);
+
+}
+__asm__(".symver numa_sched_getaffinity_v1,numa_sched_getaffinity@libnuma_1.1");
 
-int numa_sched_getaffinity(pid_t pid, struct bitmask *mask)
+int numa_sched_getaffinity_v2(pid_t pid, struct bitmask *mask)
 {
 	/* len is length in bytes */
-	return syscall(__NR_sched_getaffinity, pid, bitmask_nbytes(mask),
+	return syscall(__NR_sched_getaffinity, pid, numa_bitmask_nbytes(mask),
 								mask->maskp);
 	/* sched_getaffinity returns sizeof(cpumask_t) */
 
 }
+__asm__(".symver numa_sched_getaffinity_v2,numa_sched_getaffinity@@libnuma_1.2");
 
-make_internal_alias(numa_sched_getaffinity);
-make_internal_alias(numa_sched_setaffinity);
-make_internal_alias(get_mempolicy);
+make_internal_alias(numa_sched_getaffinity_v1);
+make_internal_alias(numa_sched_getaffinity_v2);
+make_internal_alias(numa_sched_setaffinity_v1);
+make_internal_alias(numa_sched_setaffinity_v2);
Index: numactl-1.0.2/libnuma.c
===================================================================
--- numactl-1.0.2.orig/libnuma.c
+++ numactl-1.0.2/libnuma.c
@@ -37,10 +37,21 @@
 
 #define WEAK __attribute__((weak))
 
-struct bitmask *numa_no_nodes = NULL;
-struct bitmask *numa_all_nodes = NULL;
-struct bitmask *numa_all_cpus = NULL;
-struct bitmask **node_cpu_mask;
+#define CPU_BUFFER_SIZE 4096     /* This limits you to 32768 CPUs */
+
+/* these are the old (version 1) masks */
+nodemask_t numa_no_nodes;
+nodemask_t numa_all_nodes;
+/* these are now the default bitmask (pointers to) (version 2) */
+struct bitmask *numa_no_nodes_ptr = NULL;
+struct bitmask *numa_all_nodes_ptr = NULL;
+struct bitmask *numa_all_cpus_ptr = NULL;
+/* I would prefer to use symbol versioning to create v1 and v2 versions
+   of numa_no_nodes and numa_all_nodes, but the loader does not correctly
+   handle versioning of BSS versus small data items */
+
+static unsigned long *node_cpu_mask_v1[NUMA_NUM_NODES];
+struct bitmask **node_cpu_mask_v2;
 
 #ifdef __thread
 #warning "not threadsafe"
@@ -57,11 +68,52 @@ static int nodemask_sz = 0;
 static int cpumask_sz = 0;
 
 int numa_exit_on_error = 0;
+struct bitmask *numa_allocate_nodemask(void);
+void set_sizes(void);
+void copy_nodemask_to_bitmask(nodemask_t *, struct bitmask *);
+void copy_bitmask_to_nodemask(struct bitmask *, nodemask_t *);
+
+static inline void
+nodemask_set_v1(nodemask_t *mask, int node)
+{
+	mask->n[node / (8*sizeof(unsigned long))] |=
+		(1UL<<(node%(8*sizeof(unsigned long))));
+}
+
+static inline int
+nodemask_isset_v1(const nodemask_t *mask, int node)
+{
+	if ((unsigned)node >= NUMA_NUM_NODES)
+		return 0;
+	if (mask->n[node / (8*sizeof(unsigned long))] &
+		(1UL<<(node%(8*sizeof(unsigned long)))))
+		return 1;
+	return 0;
+}
+
+/*
+ * There are two special functions, _init(void) and _fini(void), which
+ * are called automatically by the dynamic loader whenever a library is loaded.
+ *
+ * The v1 library depends upon nodemask_t's of all nodes and no nodes.
+ */
+void
+numa_init()
+{
+	int max,i;
+
+	set_sizes();
+	/* numa_all_nodes should represent existing nodes on this system */
+        max = numa_num_configured_nodes();
+        for (i = 0; i < max; i++)
+                nodemask_set_v1((nodemask_t *)&numa_all_nodes, i);
+	memset(&numa_no_nodes, 0, sizeof(numa_no_nodes));
+}
 
 /*
  * The following bitmask declarations, bitmask_*() routines, and associated
  * _setbit() and _getbit() routines are:
- * Copyright (c) 2004 Silicon Graphics, Inc. (SGI) All rights reserved.
+ * Copyright (c) 2004_2007 Silicon Graphics, Inc. (SGI) All rights reserved.
  * SGI publishes it under the terms of the GNU General Public License, v2,
  * as published by the Free Software Foundation.
  */
@@ -86,13 +138,13 @@ _setbit(struct bitmask *bmp, unsigned in
 }
 
 int
-bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
+numa_bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
 {
 	return _getbit(bmp, i);
 }
 
 struct bitmask *
-bitmask_setall(struct bitmask *bmp)
+numa_bitmask_setall(struct bitmask *bmp)
 {
 	unsigned int i;
 	for (i = 0; i < bmp->size; i++)
@@ -101,7 +153,7 @@ bitmask_setall(struct bitmask *bmp)
 }
 
 struct bitmask *
-bitmask_clearall(struct bitmask *bmp)
+numa_bitmask_clearall(struct bitmask *bmp)
 {
 	unsigned int i;
 	for (i = 0; i < bmp->size; i++)
@@ -110,28 +162,28 @@ bitmask_clearall(struct bitmask *bmp)
 }
 
 struct bitmask *
-bitmask_setbit(struct bitmask *bmp, unsigned int i)
+numa_bitmask_setbit(struct bitmask *bmp, unsigned int i)
 {
 	_setbit(bmp, i, 1);
 	return bmp;
 }
 
 struct bitmask *
-bitmask_clearbit(struct bitmask *bmp, unsigned int i)
+numa_bitmask_clearbit(struct bitmask *bmp, unsigned int i)
 {
 	_setbit(bmp, i, 0);
 	return bmp;
 }
 
 unsigned int
-bitmask_nbytes(struct bitmask *bmp)
+numa_bitmask_nbytes(struct bitmask *bmp)
 {
 	return longsperbits(bmp->size) * sizeof(unsigned long);
 }
 
 /* where n is the number of bits in the map */
 struct bitmask *
-bitmask_alloc(unsigned int n)
+numa_bitmask_alloc(unsigned int n)
 {
 	struct bitmask *bmp;
 
@@ -152,7 +204,7 @@ bitmask_alloc(unsigned int n)
 }
 
 void
-bitmask_free(struct bitmask *bmp)
+numa_bitmask_free(struct bitmask *bmp)
 {
 	if (bmp == 0)
 		return;
@@ -164,7 +216,7 @@ bitmask_free(struct bitmask *bmp)
 
 /* True if two bitmasks are equal */
 int
-bitmask_equal(const struct bitmask *bmp1, const struct bitmask *bmp2)
+numa_bitmask_equal(const struct bitmask *bmp1, const struct bitmask *bmp2)
 {
 	unsigned int i;
 	for (i = 0; i < bmp1->size || i < bmp2->size; i++)
@@ -174,14 +226,12 @@ bitmask_equal(const struct bitmask *bmp1
 }
 /* *****end of bitmask_  routines ************ */
 
-make_internal_alias(numa_exit_on_error);
-
 /* Next two can be overwritten by the application for different error handling */
 WEAK void numa_error(char *where) 
 { 
 	int olde = errno;
 	perror(where); 
-	if (numa_exit_on_error_int)
+	if (numa_exit_on_error)
 		exit(1); 
 	errno = olde;
 } 
@@ -198,7 +248,7 @@ WEAK void numa_warn(int num, char *fmt, 
 	warned |= (1<<num); 
 
 	va_start(ap,fmt);
-	fprintf(stderr, "libnuma: Warning: "); 
+	fprintf(stderr, "libnuma: Warning: ");
 	vfprintf(stderr, fmt, ap);
 	fputc('\n', stderr);
 	va_end(ap);
@@ -302,7 +352,8 @@ static const char *nodemask_prefix = "Me
  * ascii format that uses 9 characters for each 32 bits of mask.
  * (this could also be used to find the cpumask size)
  */
-static void set_nodemask_size()
+static void
+set_nodemask_size()
 {
 	FILE *fp = NULL;
 	char *buf = NULL;
@@ -389,12 +440,12 @@ read_mask(char *s, struct bitmask *bmp)
 
 /*
  * Read a processes constraints in terms of nodes and cpus from
- * /proc/pid/status.
+ * /proc/self/status.
  */
 void
-set_task_constraints(void)
+set_thread_constraints(void)
 {
-	int max_cpus = number_of_possible_cpus();
+	int max_cpus = numa_num_possible_cpus();
 	int buflen;
 	char *buffer;
 	FILE *f;
@@ -405,31 +456,31 @@ set_task_constraints(void)
 	buflen = max_cpus / 4 + max_cpus / BITS_PER_LONG + 40;
 	buffer = malloc(buflen);
 
-	numa_all_cpus = allocate_cpumask();
-	numa_all_nodes = allocate_nodemask();
+	numa_all_cpus_ptr = numa_allocate_cpumask();
+	numa_all_nodes_ptr = numa_allocate_nodemask();
+	numa_no_nodes_ptr = numa_allocate_nodemask();
 
-	sprintf(buffer,"/proc/%d/status", getpid());
-	f = fopen(buffer, "r");
+	f = fopen(mask_size_file, "r");
 	if (!f) {
-		numa_warn(W_cpumap, "Cannot parse /proc/%d/status", getpid());
+		numa_warn(W_cpumap, "Cannot parse %s", mask_size_file);
 		return;
 	}
 
 	while (fgets(buffer, buflen, f)) {
 
 		if (strncmp(buffer,"Cpus_allowed",12) == 0)
-			maxproccpu = read_mask(buffer + 14, numa_all_cpus);
+			maxproccpu = read_mask(buffer + 14, numa_all_cpus_ptr);
 
 		if (strncmp(buffer,"Mems_allowed",12) == 0) {
 			maxprocnode =
-				read_mask(buffer + 14, numa_all_nodes);
+				read_mask(buffer + 14, numa_all_nodes_ptr);
 		}
 	}
 	fclose(f);
 	free (buffer);
 
 	if (maxprocnode < 0) {
-		numa_warn(W_cpumap, "Cannot parse /proc/%d/status", getpid());
+		numa_warn(W_cpumap, "Cannot parse %s", mask_size_file);
 		return;
 	}
 	return;
@@ -448,18 +499,18 @@ set_numa_max_cpu(void)
 	struct bitmask *buffer;
 
 	do {
-		buffer = bitmask_alloc(len);
-		n = numa_sched_getaffinity_int(0, buffer);
+		buffer = numa_bitmask_alloc(len);
+		n = numa_sched_getaffinity_v2_int(0, buffer);
 		/* on success, returns size of kernel cpumask_t, in bytes */
 		if (n < 0 && errno == EINVAL) {
 			if (len >= 1024*1024)
 				break;
 			len *= 2;
-			bitmask_free(buffer);
+			numa_bitmask_free(buffer);
 			continue;
 		}
 	} while (n < 0);
-	bitmask_free(buffer);
+	numa_bitmask_free(buffer);
 	errno = olde;
 	cpumask_sz = n*8;
 }
@@ -477,8 +528,8 @@ set_configured_cpus()
 	dir = opendir(dirnamep);
 
 	if (dir == NULL) {
-		fprintf (stderr,
-			"cannot open directory %s\n", dirnamep);
+		/* fall back to using the online cpu count */
+		maxconfiguredcpu = sysconf(_SC_NPROCESSORS_CONF) - 1;
 		return;
 	}
 	while ((dirent = readdir(dir)) != 0) {
@@ -501,98 +552,118 @@ set_sizes()
 {
 	sizes_set++;
 	set_configured_nodes();	/* configured nodes listed in /sys */
-	set_nodemask_size();	/* size of nodemask_t */
-	set_numa_max_cpu();	/* size of cpumask_t */
+	set_nodemask_size();	/* size of kernel nodemask_t */
+	set_numa_max_cpu();	/* size of kernel cpumask_t */
 	set_configured_cpus();	/* cpus listed in /sys/devices/system/cpu */
-	set_task_constraints();	/* cpus and nodes for current task */
+	set_thread_constraints(); /* cpus and nodes for current thread */
 }
 
 int
-number_of_configured_nodes()
+numa_num_configured_nodes()
 {
-	if (!sizes_set)
-		set_sizes();
 	return maxconfigurednode+1;
 }
 
 int
-number_of_configured_cpus(void)
+numa_num_configured_cpus(void)
 {
 
-	if (!sizes_set)
-		set_sizes();
 	return maxconfiguredcpu+1;
 }
 
 int
-number_of_possible_nodes()
+numa_num_possible_nodes()
 {
-	if (!sizes_set)
-		set_sizes();
 	return nodemask_sz;
 }
 
 int
-number_of_possible_cpus()
+numa_num_possible_cpus()
 {
-	if (!sizes_set)
-		set_sizes();
 	return cpumask_sz;
 }
 
 int
-number_of_task_nodes()
+numa_num_thread_nodes()
 {
-	if (!sizes_set)
-		set_sizes();
 	return maxprocnode+1;
 }
 
 int
-number_of_task_cpus()
+numa_num_thread_cpus()
 {
-	if (!sizes_set)
-		set_sizes();
 	return maxproccpu+1;
 }
 
 /*
+ * Return the number of the highest node in this running system,
+ */
+int
+numa_max_node(void)
+{
+	return numa_num_configured_nodes()-1;
+}
+
+make_internal_alias(numa_max_node);
+
+/*
+ * Return the number of the highest possible node in a system,
+ * which for v1 is the size of a numa.h nodemask_t(in bits)-1.
+ * but for v2 is the size of a kernel nodemask_t(in bits)-1.
+ */
+int
+numa_max_possible_node_v1(void)
+{
+	return ((sizeof(nodemask_t)*8)-1);
+}
+__asm__(".symver numa_max_possible_node_v1,numa_max_possible_node@libnuma_1.1");
+
+int
+numa_max_possible_node_v2(void)
+{
+	return numa_num_possible_nodes()-1;
+}
+__asm__(".symver numa_max_possible_node_v2,numa_max_possible_node@@libnuma_1.2");
+
+make_internal_alias(numa_max_possible_node_v1);
+make_internal_alias(numa_max_possible_node_v2);
+
+/*
  * Allocate a bitmask for cpus, of a size large enough to
  * match the kernel's cpumask_t.
  */
 struct bitmask *
-allocate_cpumask()
+numa_allocate_cpumask()
 {
-	int ncpus = number_of_possible_cpus();
+	int ncpus = numa_num_possible_cpus();
 
-	return bitmask_alloc(ncpus);
+	return numa_bitmask_alloc(ncpus);
 }
 
 /*
- * Allocate a bitmask for nodes, of a size large enough to
- * match the kernel's nodemask_t.
+ * Allocate a bitmask the size of a libnuma nodemask_t
  */
-struct bitmask *
-allocate_nodemask()
+static struct bitmask *
+allocate_nodemask_v1()
 {
-	int nnodes = numa_max_node()+1;
+	int nnodes = numa_max_possible_node_v1_int()+1;
 
-	return bitmask_alloc(nnodes);
+	return numa_bitmask_alloc(nnodes);
 }
 
 /*
- * Return the number of the highest node in the system, in other words
- * the size of a kernel nodemask_t (in bits) - 1).
+ * Allocate a bitmask for nodes, of a size large enough to
+ * match the kernel's nodemask_t.
  */
-int
-numa_max_node(void)
+struct bitmask *
+numa_allocate_nodemask()
 {
-	if (!sizes_set)
-		set_sizes();
-	return nodemask_sz -1;
-}
+	struct bitmask *bmp;
+	int nnodes = numa_max_possible_node_v2_int() + 1;
 
-make_internal_alias(numa_max_node);
+	bmp = numa_bitmask_alloc(nnodes);
+	return bmp;
+}
 
 /* (cache the result?) */
 long long numa_node_size64(int node, long long *freep)
@@ -658,28 +729,53 @@ int numa_available(void)
 {
 	if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
 		return -1; 
-	numa_max_node_int();
 	return 0;
 } 
 
-void numa_interleave_memory(void *mem, size_t size, struct bitmask *bmp)
+void
+numa_interleave_memory_v1(void *mem, size_t size, const nodemask_t *mask)
+{
+	struct bitmask bitmask;
+
+	bitmask.size = sizeof(nodemask_t) * 8;
+	bitmask.maskp = (unsigned long *)mask;
+	dombind(mem, size, MPOL_INTERLEAVE, &bitmask);
+}
+__asm__(".symver numa_interleave_memory_v1,numa_interleave_memory@libnuma_1.1");
+
+void
+numa_interleave_memory_v2(void *mem, size_t size, struct bitmask *bmp)
 { 
 	dombind(mem, size, MPOL_INTERLEAVE, bmp);
 } 
+__asm__(".symver numa_interleave_memory_v2,numa_interleave_memory@@libnuma_1.2");
 
 void numa_tonode_memory(void *mem, size_t size, int node)
 {
 	struct bitmask *nodes;
 
-	nodes = allocate_nodemask();
-	bitmask_setbit(nodes, node);
+	nodes = numa_allocate_nodemask();
+	numa_bitmask_setbit(nodes, node);
 	dombind(mem, size, bind_policy, nodes);
 }
 
-void numa_tonodemask_memory(void *mem, size_t size, struct bitmask *bmp)
+void
+numa_tonodemask_memory_v1(void *mem, size_t size, const nodemask_t *mask)
+{
+	struct bitmask bitmask;
+
+	bitmask.maskp = (unsigned long *)mask;
+	bitmask.size  = sizeof(nodemask_t);
+	dombind(mem, size,  bind_policy, &bitmask);
+}
+__asm__(".symver numa_tonodemask_memory_v1,numa_tonodemask_memory@libnuma_1.1");
+
+void
+numa_tonodemask_memory_v2(void *mem, size_t size, struct bitmask *bmp)
 {
 	dombind(mem, size,  bind_policy, bmp);
 }
+__asm__(".symver numa_tonodemask_memory_v2,numa_tonodemask_memory@@libnuma_1.2");
 
 void numa_setlocal_memory(void *mem, size_t size)
 {
@@ -707,7 +803,23 @@ void *numa_alloc(size_t size)
 	return mem;
 } 
 
-void *numa_alloc_interleaved_subset(size_t size, struct bitmask *bmp)
+void *numa_alloc_interleaved_subset_v1(size_t size, const nodemask_t *mask)
+{
+	char *mem;
+	struct bitmask bitmask;
+
+	mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
+			0, 0);
+	if (mem == (char *)-1)
+		return NULL;
+	bitmask.maskp = (unsigned long *)mask;
+	bitmask.size  = sizeof(nodemask_t);
+	dombind(mem, size, MPOL_INTERLEAVE, &bitmask);
+	return mem;
+}
+__asm__(".symver numa_alloc_interleaved_subset_v1,numa_alloc_interleaved_subset@libnuma_1.1");
+
+void *numa_alloc_interleaved_subset_v2(size_t size, struct bitmask *bmp)
 { 
 	char *mem;	
 
@@ -718,37 +830,77 @@ void *numa_alloc_interleaved_subset(size
 	dombind(mem, size, MPOL_INTERLEAVE, bmp);
 	return mem;
 } 
+__asm__(".symver numa_alloc_interleaved_subset_v2,numa_alloc_interleaved_subset@@libnuma_1.2");
 
-make_internal_alias(numa_alloc_interleaved_subset);
+make_internal_alias(numa_alloc_interleaved_subset_v1);
+make_internal_alias(numa_alloc_interleaved_subset_v2);
 
-void *numa_alloc_interleaved(size_t size)
+void *
+numa_alloc_interleaved(size_t size)
 { 
-	return numa_alloc_interleaved_subset_int(size, numa_all_nodes);
+	return numa_alloc_interleaved_subset_v2_int(size, numa_all_nodes_ptr);
 } 
 
-void numa_set_interleave_mask(struct bitmask *bmp)
-{ 
-	if (!numa_no_nodes)
-		numa_no_nodes = allocate_nodemask();
+/*
+ * given a user node mask, set memory policy to use those nodes
+ */
+void
+numa_set_interleave_mask_v1(nodemask_t *mask)
+{
+	struct bitmask *bmp;
+	int nnodes = numa_max_possible_node_v1_int()+1;
+
+	bmp = numa_bitmask_alloc(nnodes);
+	copy_nodemask_to_bitmask(mask, bmp);
+	if (numa_bitmask_equal(bmp, numa_no_nodes_ptr))
+		setpol(MPOL_DEFAULT, bmp);
+	else
+		setpol(MPOL_INTERLEAVE, bmp);
+	numa_bitmask_free(bmp);
+}
 
-	if (bitmask_equal(bmp, numa_no_nodes))
+__asm__(".symver numa_set_interleave_mask_v1,numa_set_interleave_mask@libnuma_1.1");
+
+void
+numa_set_interleave_mask_v2(struct bitmask *bmp)
+{
+	if (numa_bitmask_equal(bmp, numa_no_nodes_ptr))
 		setpol(MPOL_DEFAULT, bmp);
 	else
 		setpol(MPOL_INTERLEAVE, bmp);
 } 
+__asm__(".symver numa_set_interleave_mask_v2,numa_set_interleave_mask@@libnuma_1.2");
+
+nodemask_t
+numa_get_interleave_mask_v1(void)
+{
+	int oldpolicy;
+	struct bitmask *bmp;
+	nodemask_t mask;
+
+	bmp = allocate_nodemask_v1();
+	getpol(&oldpolicy, bmp);
+	if (oldpolicy == MPOL_INTERLEAVE)
+		copy_bitmask_to_nodemask(bmp, &mask);
+	else
+	 	copy_bitmask_to_nodemask(numa_no_nodes_ptr, &mask);
+	return mask;
+}
+__asm__(".symver numa_get_interleave_mask_v1,numa_get_interleave_mask@libnuma_1.1");
 
 struct bitmask *
-numa_get_interleave_mask(void)
+numa_get_interleave_mask_v2(void)
 { 
 	int oldpolicy;
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
+	bmp = numa_allocate_nodemask();
 	getpol(&oldpolicy, bmp);
 	if (oldpolicy == MPOL_INTERLEAVE)
 		return bmp;
-	return numa_no_nodes; 
+	return numa_no_nodes_ptr;
 } 
+__asm__(".symver numa_get_interleave_mask_v2,numa_get_interleave_mask@@libnuma_1.2");
 
 /* (undocumented) */
 int numa_get_interleave_node(void)
@@ -764,8 +916,8 @@ void *numa_alloc_onnode(size_t size, int
 	char *mem; 
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
-	bitmask_setbit(bmp, node);
+	bmp = numa_allocate_nodemask();
+	numa_bitmask_setbit(bmp, node);
 	mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
 		   0, 0);  
 	if (mem == (char *)-1)
@@ -793,40 +945,137 @@ void numa_set_bind_policy(int strict) 
 		bind_policy = MPOL_PREFERRED;
 } 
 
-void numa_set_membind(struct bitmask *bmp)
+void
+numa_set_membind_v1(const nodemask_t *mask)
+{
+	struct bitmask bitmask;
+
+	bitmask.maskp = (unsigned long *)mask;
+	bitmask.size  = sizeof(nodemask_t);
+	setpol(MPOL_BIND, &bitmask);
+}
+__asm__(".symver numa_set_membind_v1,numa_set_membind@libnuma_1.1");
+
+void
+numa_set_membind_v2(struct bitmask *bmp)
 { 
 	setpol(MPOL_BIND, bmp);
 } 
+__asm__(".symver numa_set_membind_v2,numa_set_membind@@libnuma_1.2");
+
+make_internal_alias(numa_set_membind_v2);
+
+/*
+ * copy a bitmask map body to a numa.h nodemask_t structure
+ */
+void
+copy_bitmask_to_nodemask(struct bitmask *bmp, nodemask_t *nmp)
+{
+	int max, i;
 
-make_internal_alias(numa_set_membind);
+	memset(nmp, 0, sizeof(nodemask_t));
+        max = (sizeof(nodemask_t)*8);
+	for (i=0; i<bmp->size; i++) {
+		if (i >= max)
+			break;
+		if (numa_bitmask_isbitset(bmp, i))
+                	nodemask_set_v1((nodemask_t *)nmp, i);
+	}
+}
+
+/*
+ * copy a numa.h nodemask_t structure to a bitmask map body
+ */
+void
+copy_nodemask_to_bitmask(nodemask_t *nmp, struct bitmask *bmp)
+{
+	int max, i;
+
+	numa_bitmask_clearall(bmp);
+        max = (sizeof(nodemask_t)*8);
+	if (max > bmp->size)
+		max = bmp->size;
+	for (i=0; i<max; i++) {
+		if (nodemask_isset_v1(nmp, i))
+			numa_bitmask_setbit(bmp, i);
+	}
+}
+
+nodemask_t
+numa_get_membind_v1(void)
+{
+	int oldpolicy;
+	struct bitmask *bmp;
+	nodemask_t *nmp;
+
+	bmp = allocate_nodemask_v1();
+	getpol(&oldpolicy, bmp);
+	if (oldpolicy == MPOL_BIND) {
+		nmp = (nodemask_t *)bmp->maskp;
+		return *nmp;
+	}
+	/* copy the body of the map to numa_all_nodes */
+	copy_bitmask_to_nodemask(bmp, &numa_all_nodes);
+	return numa_all_nodes;
+}
+__asm__(".symver numa_get_membind_v1,numa_get_membind@libnuma_1.1");
 
 struct bitmask *
-numa_get_membind(void)
+numa_get_membind_v2(void)
 {
 	int oldpolicy;
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
+	bmp = numa_allocate_nodemask();
 	getpol(&oldpolicy, bmp);
 	if (oldpolicy == MPOL_BIND)
 		return bmp;
-	return numa_all_nodes;	
+	return numa_all_nodes_ptr;
 } 
+__asm__(".symver numa_get_membind_v2,numa_get_membind@@libnuma_1.2");
 
 void numa_free(void *mem, size_t size)
 { 
 	munmap(mem, size); 
 } 
 
-static void bad_cpumap(struct bitmask *mask)
+int
+numa_parse_bitmap_v1(char *line, unsigned long *mask, int ncpus)
 {
-	int n;
+	int i;
+	char *p = strchr(line, '\n');
+	if (!p)
+		return -1;
 
-	for (n = 0; n < mask->size; n++)
-		bitmask_setbit(mask, n);
+	for (i = 0; p > line;i++) {
+		char *oldp, *endp;
+		oldp = p;
+		if (*p == ',')
+			--p;
+		while (p > line && *p != ',')
+			--p;
+		/* Eat two 32bit fields at a time to get longs */
+		if (p > line && sizeof(unsigned long) == 8) {
+			oldp--;
+			memmove(p, p+1, oldp-p+1);
+			while (p > line && *p != ',')
+				--p;
+		}
+		if (*p == ',')
+			p++;
+		if (i >= CPU_LONGS(ncpus))
+			return -1;
+		mask[i] = strtoul(p, &endp, 16);
+		if (endp != oldp)
+			return -1;
+		p--;
+	}
+	return 0;
 }
+__asm__(".symver numa_parse_bitmap_v1,numa_parse_bitmap@libnuma_1.1");
 
-int numa_parse_bitmap(char *line, struct bitmask *mask)
+int
+numa_parse_bitmap_v2(char *line, struct bitmask *mask)
 {
 	int i, ncpus;
 	char *p = strchr(line, '\n'); 
@@ -859,13 +1108,83 @@ int numa_parse_bitmap(char *line, struct
 	}
 	return 0;
 }
+__asm__(".symver numa_parse_bitmap_v2,numa_parse_bitmap@@libnuma_1.2");
 
 void
-init_node_cpu_mask()
+init_node_cpu_mask_v2()
 {
-	int nnodes = numa_max_node()+1;
-	node_cpu_mask = calloc (nnodes, sizeof(struct bitmask *));
+	int nnodes = numa_max_possible_node_v2_int() + 1;
+	node_cpu_mask_v2 = calloc (nnodes, sizeof(struct bitmask *));
+}
+
+/* This would be better with some locking, but I don't want to make libnuma
+   dependent on pthreads right now. The races are relatively harmless. */
+int
+numa_node_to_cpus_v1(int node, unsigned long *buffer, int bufferlen)
+{
+	int err = 0;
+	char fn[64];
+	FILE *f;
+	char *line = NULL;
+	size_t len = 0;
+	struct bitmask bitmask;
+	int buflen_needed;
+	unsigned long *mask;
+	int ncpus = numa_num_possible_cpus();
+	int maxnode = numa_max_node_int();
+
+	buflen_needed = CPU_BYTES(ncpus);
+	if ((unsigned)node > maxnode || bufferlen < buflen_needed) {
+		errno = ERANGE;
+		return -1;
+	}
+	if (bufferlen > buflen_needed)
+		memset(buffer, 0, bufferlen);
+	if (node_cpu_mask_v1[node]) {
+		memcpy(buffer, node_cpu_mask_v1[node], buflen_needed);
+		return 0;
+	}
+
+	mask = malloc(buflen_needed);
+	if (!mask)
+		mask = (unsigned long *)buffer;
+	memset(mask, 0, buflen_needed);
+
+	sprintf(fn, "/sys/devices/system/node/node%d/cpumap", node);
+	f = fopen(fn, "r");
+	if (!f || getdelim(&line, &len, '\n', f) < 1) {
+		numa_warn(W_nosysfs2,
+		   "/sys not mounted or invalid. Assuming one node: %s",
+			  strerror(errno));
+		bitmask.maskp = (unsigned long *)mask;
+		bitmask.size  = buflen_needed * 8;
+		numa_bitmask_setall(&bitmask);
+		err = -1;
+	}
+	if (f)
+		fclose(f);
+
+	if (line && (numa_parse_bitmap_v1(line, mask, ncpus) < 0)) {
+		numa_warn(W_cpumap, "Cannot parse cpumap. Assuming one node");
+		bitmask.maskp = (unsigned long *)mask;
+		bitmask.size  = buflen_needed * 8;
+		numa_bitmask_setall(&bitmask);
+		err = -1;
+	}
+
+	free(line);
+	memcpy(buffer, mask, buflen_needed);
+
+	/* slightly racy, see above */
+	if (node_cpu_mask_v1[node]) {
+		if (mask != buffer)
+			free(mask);
+	} else {
+		node_cpu_mask_v1[node] = mask;
+	}
+	return err;
 }
+__asm__(".symver numa_node_to_cpus_v1,numa_node_to_cpus@libnuma_1.1");
 
 /*
  * test whether a node has cpus
@@ -875,37 +1194,38 @@ init_node_cpu_mask()
 /*
  * deliver a bitmask of cpus representing the cpus on a given node
  */
-int numa_node_to_cpus(int node, struct bitmask *buffer)
+int
+numa_node_to_cpus_v2(int node, struct bitmask *buffer)
 {
 	int err = 0, bufferlen;
-	int nnodes = number_of_configured_nodes();
+	int nnodes = numa_num_configured_nodes();
 	char fn[64], *line = NULL;
 	FILE *f; 
 	size_t len = 0; 
 	struct bitmask *mask;
 
-	if (!node_cpu_mask)
-		init_node_cpu_mask();
+	if (!node_cpu_mask_v2)
+		init_node_cpu_mask_v2();
 
-	bufferlen = bitmask_nbytes(buffer);
+	bufferlen = numa_bitmask_nbytes(buffer);
 	if (node > nnodes-1) {
 		errno = ERANGE;
 		return -1;
 	}
-	bitmask_clearall(buffer);
+	numa_bitmask_clearall(buffer);
 
-	if (node_cpu_mask[node]) { 
+	if (node_cpu_mask_v2[node]) {
 		/* have already constructed a mask for this node */
-		if (buffer->size != node_cpu_mask[node]->size) {
+		if (buffer->size != node_cpu_mask_v2[node]->size) {
 			printf ("map size mismatch; abort\n");
 			exit(1);
 		}
-		memcpy(buffer->maskp, node_cpu_mask[node]->maskp, bufferlen);
+		memcpy(buffer->maskp, node_cpu_mask_v2[node]->maskp, bufferlen);
 		return 0;
 	}
 
 	/* need a new mask for this node */
-	mask = allocate_cpumask();
+	mask = numa_allocate_cpumask();
 
 	/* this is a kernel cpumask_t (see node_read_cpumap()) */
 	sprintf(fn, "/sys/devices/system/node/node%d/cpumap", node); 
@@ -914,15 +1234,15 @@ int numa_node_to_cpus(int node, struct b
 		numa_warn(W_nosysfs2,
 		   "/sys not mounted or invalid. Assuming one node: %s",
 			  strerror(errno)); 
-		bad_cpumap(mask);
+		numa_bitmask_setall(mask);
 		err = -1;
 	} 
 	if (f)
 		fclose(f);
 
-	if (line && numa_parse_bitmap(line, mask) < 0) {
+	if (line && (numa_parse_bitmap_v2(line, mask) < 0)) {
 		numa_warn(W_cpumap, "Cannot parse cpumap. Assuming one node");
-		bad_cpumap(mask);
+		numa_bitmask_setall(mask);
 		err = -1;
 	}
 
@@ -931,37 +1251,95 @@ int numa_node_to_cpus(int node, struct b
 
 	/* slightly racy, see above */ 
 	/* save the mask we created */
-	if (node_cpu_mask[node]) {
+	if (node_cpu_mask_v2[node]) {
 		/* how could this be? */
 		if (mask != buffer)
-			bitmask_free(mask);
+			numa_bitmask_free(mask);
 	} else {
-		node_cpu_mask[node] = mask; 
+		node_cpu_mask_v2[node] = mask;
 	} 
 	return err; 
-} 
+}
+__asm__(".symver numa_node_to_cpus_v2,numa_node_to_cpus@@libnuma_1.2");
+
+make_internal_alias(numa_node_to_cpus_v1);
+make_internal_alias(numa_node_to_cpus_v2);
+
+
+int
+numa_run_on_node_mask_v1(const nodemask_t *mask)
+{
+	int ncpus = numa_num_possible_cpus();
+	int i, k, err;
+	unsigned long cpus[CPU_LONGS(ncpus)], nodecpus[CPU_LONGS(ncpus)];
+	memset(cpus, 0, CPU_BYTES(ncpus));
+	for (i = 0; i < NUMA_NUM_NODES; i++) {
+		if (mask->n[i / BITS_PER_LONG] == 0)
+			continue;
+		if (nodemask_isset_v1(mask, i)) {
+			if (numa_node_to_cpus_v1_int(i, nodecpus, CPU_BYTES(ncpus)) < 0) {
+				numa_warn(W_noderunmask,
+					  "Cannot read node cpumask from sysfs");
+				continue;
+			}
+			for (k = 0; k < CPU_LONGS(ncpus); k++)
+				cpus[k] |= nodecpus[k];
+		}
+	}
+	err = numa_sched_setaffinity_v1(0, CPU_BYTES(ncpus), cpus);
 
-make_internal_alias(numa_node_to_cpus);
+	/* The sched_setaffinity API is broken because it expects
+	   the user to guess the kernel cpuset size. Do this in a
+	   brute force way. */
+	if (err < 0 && errno == EINVAL) {
+		int savederrno = errno;
+		char *bigbuf;
+		static int size = -1;
+		if (size == -1)
+			size = CPU_BYTES(ncpus) * 2;
+		bigbuf = malloc(CPU_BUFFER_SIZE);
+		if (!bigbuf) {
+			errno = ENOMEM;
+			return -1;
+		}
+		errno = savederrno;
+		while (size <= CPU_BUFFER_SIZE) {
+			memcpy(bigbuf, cpus, CPU_BYTES(ncpus));
+			memset(bigbuf + CPU_BYTES(ncpus), 0,
+			       CPU_BUFFER_SIZE - CPU_BYTES(ncpus));
+			err = numa_sched_setaffinity_v1_int(0, size, (unsigned long *)bigbuf);
+			if (err == 0 || errno != EINVAL)
+				break;
+			size *= 2;
+		}
+		savederrno = errno;
+		free(bigbuf);
+		errno = savederrno;
+	}
+	return err;
+}
+__asm__(".symver numa_run_on_node_mask_v1,numa_run_on_node_mask@libnuma_1.1");
 
 /*
  * Given a node mask (size of a kernel nodemask_t) (probably populated by
  * a user argument list) set up a map of cpus (map "cpus") on those nodes.
  * Then set affinity to those cpus.
  */
-int numa_run_on_node_mask(struct bitmask *bmp)
+int
+numa_run_on_node_mask_v2(struct bitmask *bmp)
 { 	
 	int ncpus, i, k, err;
 	struct bitmask *cpus, *nodecpus;
 
-	cpus = allocate_cpumask();
+	cpus = numa_allocate_cpumask();
 	ncpus = cpus->size;
-	nodecpus = allocate_cpumask();
+	nodecpus = numa_allocate_cpumask();
 
 	for (i = 0; i < bmp->size; i++) {
 		if (bmp->maskp[i / BITS_PER_LONG] == 0)
 			continue;
-		if (bitmask_isbitset(bmp, i)) {
-			if (numa_node_to_cpus_int(i, nodecpus) < 0) {
+		if (numa_bitmask_isbitset(bmp, i)) {
+			if (numa_node_to_cpus_v2_int(i, nodecpus) < 0) {
 				numa_warn(W_noderunmask, 
 					"Cannot read node cpumask from sysfs");
 				continue;
@@ -970,53 +1348,85 @@ int numa_run_on_node_mask(struct bitmask
 				cpus->maskp[k] |= nodecpus->maskp[k];
 		}	
 	}
-	err = numa_sched_setaffinity_int(0, cpus);
+	err = numa_sched_setaffinity_v2_int(0, cpus);
 
 	/* used to have to consider that this could fail - it shouldn't now */
 	if (err < 0) {
-		printf ("numa_sched_setaffinity_int() failed; abort\n");
+		printf ("numa_sched_setaffinity_v2_int() failed; abort\n");
 		exit(1);
 	}
-	bitmask_free(cpus);
-	bitmask_free(nodecpus);
+	numa_bitmask_free(cpus);
+	numa_bitmask_free(nodecpus);
 
 	return err;
 } 
+__asm__(".symver numa_run_on_node_mask_v2,numa_run_on_node_mask@@libnuma_1.2");
+
+make_internal_alias(numa_run_on_node_mask_v2);
+
+nodemask_t
+numa_get_run_node_mask_v1(void)
+{
+	int ncpus = numa_num_configured_cpus();
+	int i, k;
+	int max = numa_max_node_int();
+	struct bitmask *bmp, *cpus, *nodecpus;
+	nodemask_t *nmp;
+
+	bmp = allocate_nodemask_v1(); /* the size of a nodemask_t */
+	cpus = numa_allocate_cpumask();
+	nodecpus = numa_allocate_cpumask();
+	if (numa_sched_getaffinity_v2_int(0, cpus) < 0)
+		return numa_no_nodes;
 
-make_internal_alias(numa_run_on_node_mask);
+	for (i = 0; i <= max; i++) {
+		if (numa_node_to_cpus_v2_int(i, nodecpus) < 0) {
+			/* It's possible for the node to not exist */
+			continue;
+		}
+		for (k = 0; k < CPU_LONGS(ncpus); k++) {
+			if (nodecpus->maskp[k] & cpus->maskp[k])
+				numa_bitmask_setbit(bmp, i);
+		}
+	}
+	nmp = (nodemask_t *)bmp->maskp;
+	return *nmp;
+}
+__asm__(".symver numa_get_run_node_mask_v1,numa_get_run_node_mask@libnuma_1.1");
 
 struct bitmask *
-numa_get_run_node_mask(void)
+numa_get_run_node_mask_v2(void)
 { 
-	int ncpus = number_of_configured_cpus();
 	int i, k;
+	int ncpus = numa_num_configured_cpus();
 	int max = numa_max_node_int();
 	struct bitmask *bmp, *cpus, *nodecpus;
 
-	bmp = allocate_cpumask();
-	cpus = allocate_cpumask();
-	nodecpus = allocate_cpumask();
+	bmp = numa_allocate_cpumask();
+	cpus = numa_allocate_cpumask();
+	nodecpus = numa_allocate_cpumask();
 
-	if (numa_sched_getaffinity_int(0, cpus) < 0)
-		return numa_no_nodes; 
+	if (numa_sched_getaffinity_v2_int(0, cpus) < 0)
+		return numa_no_nodes_ptr;
 
 	for (i = 0; i <= max; i++) {
-		if (numa_node_to_cpus_int(i, nodecpus) < 0) {
+		if (numa_node_to_cpus_v2_int(i, nodecpus) < 0) {
 			/* It's possible for the node to not exist */
 			continue;
 		}
 		for (k = 0; k < CPU_LONGS(ncpus); k++) {
 			if (nodecpus->maskp[k] & cpus->maskp[k])
-				bitmask_setbit(bmp, i);
+				numa_bitmask_setbit(bmp, i);
 		}
 	}		
 	return bmp;
 } 
+__asm__(".symver numa_get_run_node_mask_v2,numa_get_run_node_mask@@libnuma_1.2");
 
 int
 numa_migrate_pages(int pid, struct bitmask *fromnodes, struct bitmask *tonodes)
 {
-	int numa_num_nodes = number_of_possible_nodes();
+	int numa_num_nodes = numa_num_possible_nodes();
 
 	return migrate_pages(pid, numa_num_nodes + 1, fromnodes->maskp,
 							tonodes->maskp);
@@ -1030,14 +1440,14 @@ int numa_move_pages(int pid, unsigned lo
 
 int numa_run_on_node(int node)
 { 
-	int numa_num_nodes = number_of_possible_nodes();
+	int numa_num_nodes = numa_num_possible_nodes();
 	struct bitmask *cpus;
 
+	cpus = numa_allocate_cpumask();
 	if (node == -1) {
-		cpus = allocate_cpumask();
-		bitmask_setall(cpus);
+		numa_bitmask_setall(cpus);
 	} else if (node < numa_num_nodes) {
-		if (numa_node_to_cpus_int(node, cpus) < 0) {
+		if (numa_node_to_cpus_v2_int(node, cpus) < 0) {
 			numa_warn(W_noderunmask,
 				"Cannot read node cpumask from sysfs");
 			return -1; 
@@ -1046,7 +1456,7 @@ int numa_run_on_node(int node)
 		errno = EINVAL;
 		return -1; 
 	}
-	return numa_sched_setaffinity_int(0, cpus);
+	return numa_sched_setaffinity_v2_int(0, cpus);
 } 
 
 int numa_preferred(void)
@@ -1054,13 +1464,13 @@ int numa_preferred(void)
 	int policy;
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
+	bmp = numa_allocate_nodemask();
 	getpol(&policy, bmp);
 	if (policy == MPOL_PREFERRED || policy == MPOL_BIND) { 
 		int i;
-		int max = number_of_possible_nodes();
+		int max = numa_num_possible_nodes();
 		for (i = 0; i < max ; i++) 
-			if (bitmask_isbitset(bmp, i))
+			if (numa_bitmask_isbitset(bmp, i))
 				return i; 
 	}
 	/* could read the current CPU from /proc/self/status. Probably 
@@ -1072,11 +1482,11 @@ void numa_set_preferred(int node)
 { 
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
+	bmp = numa_allocate_nodemask();
 	if (node >= 0)
-		bitmask_setbit(bmp, node);
+		numa_bitmask_setbit(bmp, node);
 	setpol(MPOL_PREFERRED, bmp);
-	bitmask_free(bmp);
+	numa_bitmask_free(bmp);
 	return;
 } 
 
@@ -1084,17 +1494,29 @@ void numa_set_localalloc(void) 
 {	
 	struct bitmask *bmp;
 
-	bmp = allocate_nodemask();
+	bmp = numa_allocate_nodemask();
 	setpol(MPOL_PREFERRED, bmp);
-	bitmask_free(bmp);
+	numa_bitmask_free(bmp);
 	return;
 } 
 
-void numa_bind(struct bitmask *bmp)
+void numa_bind_v1(const nodemask_t *nodemask)
 {
-	numa_run_on_node_mask_int(bmp);
-	numa_set_membind_int(bmp);
+	struct bitmask bitmask;
+
+	bitmask.maskp = (unsigned long *)nodemask;
+	bitmask.size  = sizeof(nodemask_t);
+	numa_run_on_node_mask_v2_int(&bitmask);
+	numa_set_membind_v2_int(&bitmask);
 }
+__asm__(".symver numa_bind_v1,numa_bind@libnuma_1.1");
+
+void numa_bind_v2(struct bitmask *bmp)
+{
+	numa_run_on_node_mask_v2_int(bmp);
+	numa_set_membind_v2_int(bmp);
+}
+__asm__(".symver numa_bind_v2,numa_bind@@libnuma_1.2");
 
 void numa_set_strict(int flag)
 {
@@ -1103,3 +1525,201 @@ void numa_set_strict(int flag)
 	else
 		mbind_flags &= ~MPOL_MF_STRICT;
 }
+
+static void grumble(char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "numactl: ");
+	vfprintf(stderr,fmt,ap);
+	putchar('\n');
+	va_end(ap);
+	exit(1);
+}
+/*
+ * Extract a node or processor number from the given string.
+ * Allow a relative node / processor specification within the allowed
+ * set if "relative" is nonzero
+ */
+static unsigned long get_nr(char *s, char **end, struct bitmask *bmp, int relative)
+{
+	long i, nr;
+
+	if (!relative)
+		return strtoul(s, end, 0);
+
+	nr = strtoul(s, end, 0);
+	if (s == *end)
+		return nr;
+	/* Find the nth set bit */
+	for (i = 0; nr >= 0 && i <= bmp->size; i++)
+		if (numa_bitmask_isbitset(bmp, i))
+			nr--;
+	return i-1;
+}
+
+/*
+ * numa_parse_nodestring() is called to create a node mask, given
+ * an ascii string such as 25 or 12-15 or 1,3,5-7 or +6-10.
+ * (the + indicates that the numbers are cpuset-relative)
+ *
+ * The nodes may be specified as absolute, or relative to the current cpuset.
+ * The list of available nodes is in a map pointed to by "numa_all_nodes_ptr",
+ * which may represent all nodes or the nodes in the current cpuset.
+ *
+ * The caller must free the returned bitmask.
+ */
+struct bitmask *
+numa_parse_nodestring(char *s)
+{
+	int maxnode = numa_max_node();
+	int invert = 0, relative = 0;
+	int conf_nodes = numa_num_configured_nodes();
+	int thread_nodes = numa_num_thread_nodes();
+	char *end;
+	struct bitmask *mask;
+
+	mask = numa_allocate_nodemask();
+
+	if (s[0] == 0)
+		return numa_no_nodes_ptr;
+	if (*s == '!') {
+		invert = 1;
+		s++;
+	}
+	if (*s == '+') {
+		relative++;
+		s++;
+	}
+	do {
+		unsigned long arg;
+		int i;
+		if (!strcmp(s,"all")) {
+			int i;
+			for (i = 0; i < thread_nodes; i++)
+				numa_bitmask_setbit(mask, i);
+			s+=4;
+			break;
+		}
+		arg = get_nr(s, &end, numa_all_nodes_ptr, relative);
+		if (end == s)
+			grumble("unparseable node description `%s'\n", s);
+		if (arg > maxnode)
+			grumble("node argument %d is out of range\n", arg);
+		i = arg;
+		numa_bitmask_setbit(mask, i);
+		s = end;
+		if (*s == '-') {
+			char *end2;
+			unsigned long arg2;
+			arg2 = get_nr(++s, &end2, numa_all_nodes_ptr, relative);
+			if (end2 == s)
+				grumble("missing node argument %s\n", s);
+			if (arg2 >= thread_nodes)
+				grumble("node argument %d out of range\n", arg2);
+			while (arg <= arg2) {
+				i = arg;
+				if (numa_bitmask_isbitset(numa_all_nodes_ptr,i))
+					numa_bitmask_setbit(mask, i);
+				arg++;
+			}
+			s = end2;
+		}
+	} while (*s++ == ',');
+	if (s[-1] != '\0')
+		return 0;
+	if (invert) {
+		int i;
+		for (i = 0; i < conf_nodes; i++) {
+			if (numa_bitmask_isbitset(mask, i))
+				numa_bitmask_clearbit(mask, i);
+			else
+				numa_bitmask_setbit(mask, i);
+		}
+	}
+	return mask;
+}
+
+/*
+ * numa_parse_cpustring() is called to create a bitmask, given
+ * an ascii string such as 25 or 12-15 or 1,3,5-7 or +6-10.
+ * (the + indicates that the numbers are cpuset-relative)
+ *
+ * The cpus may be specified as absolute, or relative to the current cpuset.
+ * The list of available cpus for this task is in the map pointed to by
+ * "numa_all_cpus_ptr", which may represent all cpus or the cpus in the
+ * current cpuset.
+ *
+ * The caller must free the returned bitmask.
+ */
+struct bitmask *
+numa_parse_cpustring(char *s)
+{
+	int invert = 0, relative=0;
+	int conf_cpus = numa_num_configured_cpus();
+	int thread_cpus = numa_num_thread_cpus();
+	char *end;
+	struct bitmask *mask;
+
+	mask = numa_allocate_cpumask();
+
+	if (s[0] == 0)
+		return mask;
+	if (*s == '!') {
+		invert = 1;
+		s++;
+	}
+	if (*s == '+') {
+		relative++;
+		s++;
+	}
+	do {
+		unsigned long arg;
+		int i;
+
+		if (!strcmp(s,"all")) {
+			int i;
+			for (i = 0; i < thread_cpus; i++)
+				numa_bitmask_setbit(mask, i);
+			s+=4;
+			break;
+		}
+		arg = get_nr(s, &end, numa_all_cpus_ptr, relative);
+		if (end == s)
+			grumble("unparseable cpu description `%s'\n", s);
+		if (arg >= thread_cpus)
+			grumble("cpu argument %s is out of range\n", s);
+		i = arg;
+		numa_bitmask_setbit(mask, i);
+		s = end;
+		if (*s == '-') {
+			char *end2;
+			unsigned long arg2;
+			int i;
+			arg2 = get_nr(++s, &end2, numa_all_cpus_ptr, relative);
+			if (end2 == s)
+				grumble("missing cpu argument %s\n", s);
+			if (arg2 >= thread_cpus)
+				grumble("cpu argument %s out of range\n", s);
+			while (arg <= arg2) {
+				i = arg;
+				if (numa_bitmask_isbitset(numa_all_cpus_ptr, i))
+					numa_bitmask_setbit(mask, i);
+				arg++;
+			}
+			s = end2;
+		}
+	} while (*s++ == ',');
+	if (s[-1] != '\0')
+		return 0;
+	if (invert) {
+		int i;
+		for (i = 0; i < conf_cpus; i++) {
+			if (numa_bitmask_isbitset(mask, i))
+				numa_bitmask_clearbit(mask, i);
+			else
+				numa_bitmask_setbit(mask, i);
+		}
+	}
+	return mask;
+}
Index: numactl-1.0.2/numa.h
===================================================================
--- numactl-1.0.2.orig/numa.h
+++ numactl-1.0.2/numa.h
@@ -21,11 +21,22 @@
 
 #include <stddef.h>
 #include <string.h>
+#include <sys/types.h>
+
+#if defined(__x86_64__) || defined(__i386__)
+#define NUMA_NUM_NODES  128
+#else
+#define NUMA_NUM_NODES  2048
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct {
+        unsigned long n[NUMA_NUM_NODES/(sizeof(unsigned long)*8)];
+} nodemask_t;
+
 struct bitmask {
 	unsigned long size; /* number of bits in the map */
 	unsigned long *maskp;
@@ -36,37 +47,40 @@ struct bitmask {
 #define longsperbits(n) howmany(n, bitsperlong)
 #define bytesperbits(x) ((x+7)/8)
 
-int bitmask_isbitset(const struct bitmask *, unsigned int);
-struct bitmask *bitmask_clearall(struct bitmask *);
-struct bitmask *bitmask_setbit(struct bitmask *, unsigned int);
-struct bitmask *bitmask_clearbit(struct bitmask *, unsigned int);
-unsigned int bitmask_nbytes(struct bitmask *);
-struct bitmask *bitmask_alloc(unsigned int);
-void bitmask_free(struct bitmask *);
-int bitmask_equal(const struct bitmask *, const struct bitmask *);
+/* operations on struct bitmask */
+int numa_bitmask_isbitset(const struct bitmask *, unsigned int);
+struct bitmask *numa_bitmask_setall(struct bitmask *);
+struct bitmask *numa_bitmask_clearall(struct bitmask *);
+struct bitmask *numa_bitmask_setbit(struct bitmask *, unsigned int);
+struct bitmask *numa_bitmask_clearbit(struct bitmask *, unsigned int);
+unsigned int numa_bitmask_nbytes(struct bitmask *);
+struct bitmask *numa_bitmask_alloc(unsigned int);
+void numa_bitmask_free(struct bitmask *);
+int numa_bitmask_equal(const struct bitmask *, const struct bitmask *);
 
+/* compatibility for codes that used them: */
 static inline void nodemask_zero(struct bitmask *mask)
 { 
-	bitmask_clearall(mask);
+	numa_bitmask_clearall(mask);
 } 
 
 static inline void nodemask_set(struct bitmask *mask, int node)
 {
-	bitmask_setbit(mask, node);
+	numa_bitmask_setbit(mask, node);
 } 
 
 static inline void nodemask_clr(struct bitmask *mask, int node)
 {
-	bitmask_clearbit(mask, node);
+	numa_bitmask_clearbit(mask, node);
 }
 
 static inline int nodemask_isset(struct bitmask *mask, int node)
 {
-	return bitmask_isbitset(mask, node);
+	return numa_bitmask_isbitset(mask, node);
 }
 static inline int nodemask_equal(struct bitmask *a, struct bitmask *b)
 { 
-	return bitmask_equal(a, b);
+	return numa_bitmask_equal(a, b);
 } 
 
 /* NUMA support available. If this returns a negative value all other function
@@ -77,6 +91,7 @@ int numa_available(void);
 
 /* Get max available node */
 int numa_max_node(void);
+int numa_max_possible_node(void);
 /* Return preferred node */
 int numa_preferred(void);
 
@@ -87,10 +102,13 @@ long numa_node_size(int node, long *free
 int numa_pagesize(void); 
 
 /* Set with all nodes. Only valid after numa_available. */
-extern struct bitmask *numa_all_nodes;
+extern struct bitmask *numa_all_nodes_ptr;
+
+/* Set with all cpus. */
+extern struct bitmask *numa_all_cpus_ptr;
 
 /* Set with no nodes */
-extern struct bitmask *numa_no_nodes;
+extern struct bitmask *numa_no_nodes_ptr;
 
 /* Only run and allocate memory from a specific set of nodes. */
 void numa_bind(struct bitmask *nodes);
@@ -102,7 +120,7 @@ void numa_set_interleave_mask(struct bit
 struct bitmask *numa_get_interleave_mask(void);
 
 /* allocate a bitmask big enough for all nodes */
-struct bitmask *allocate_nodemask(void);
+struct bitmask *numa_allocate_nodemask(void);
 
 /* Some node to preferably allocate memory from for thread. */
 void numa_set_preferred(int node);
@@ -166,34 +184,31 @@ void numa_set_bind_policy(int strict);  
 void numa_set_strict(int flag);
 
 /* maximum nodes (size of kernel nodemask_t) */
-int number_of_possible_nodes();
+int numa_num_possible_nodes();
 
 /* maximum cpus (size of kernel cpumask_t) */
-int number_of_possible_cpus();
+int numa_num_possible_cpus();
 
 /* nodes in the system */
-int number_of_configured_nodes();
+int numa_num_configured_nodes();
 
 /* maximum cpus */
-int number_of_configured_cpus();
+int numa_num_configured_cpus();
 
 /* maximum cpus allowed to current task */
-int number_of_task_cpus();
+int numa_num_task_cpus();
 
 /* maximum nodes allowed to current task */
-int number_of_task_nodes();
+int numa_num_task_nodes();
 
 /* allocate a bitmask the size of the kernel cpumask_t */
-struct bitmask *allocate_cpumask();
-
-/* allocate a bitmask the size of the kernel nodemask_t */
-struct bitmask *allocate_nodemask();
+struct bitmask *numa_allocate_cpumask();
 
 /* set up to represent the cpus available to the current task */
 struct bitmask *numa_all_cpus;
 
 /* Convert node to CPU mask. -1/errno on failure, otherwise 0. */
-int numa_node_to_cpus(int node, struct bitmask *buffer);
+int numa_node_to_cpus(int, struct bitmask *);
 
 /* Report distance of node1 from node2. 0 on error.*/
 int numa_distance(int node1, int node2);
@@ -216,9 +231,18 @@ int numa_migrate_pages(int pid, struct b
 int numa_move_pages(int pid, unsigned long count, void **pages,
 		const int *nodes, int *status, int flags);
 
+int numa_sched_getaffinity(pid_t, struct bitmask *);
+int numa_sched_setaffinity(pid_t, struct bitmask *);
+
+/* Convert an ascii list of nodes to a bitmask */
+struct bitmask *numa_parse_nodestring(char *);
+
+/* Convert an ascii list of cpu to a bitmask */
+struct bitmask *numa_parse_cpustring(char *);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif
+
Index: numactl-1.0.2/shm.c
===================================================================
--- numactl-1.0.2.orig/shm.c
+++ numactl-1.0.2/shm.c
@@ -184,8 +184,8 @@ void dump_shm(void) 
 		return;
 	}
 
-	nodes = allocate_nodemask();
-	prevnodes = allocate_nodemask();
+	nodes = numa_allocate_nodemask();
+	prevnodes = numa_allocate_nodemask();
 
 	for (c = 0; c < shmlen; c += shm_pagesize) { 
 		if (get_mempolicy(&pol, nodes->maskp, nodes->size, c+shmptr,
@@ -215,10 +215,10 @@ static void vwarn(char *ptr, char *fmt, 
 
 static unsigned interleave_next(unsigned cur, struct bitmask *mask)
 {
-	int numa_num_nodes = number_of_possible_nodes();
+	int numa_num_nodes = numa_num_possible_nodes();
 
 	++cur;
-	while (!nodemask_isset(mask, cur)) { 		
+	while (!numa_bitmask_isbitset(mask, cur)) {
 		cur = (cur+1) % numa_num_nodes;
 	} 
 	return cur;
@@ -232,7 +232,7 @@ void verify_shm(int policy, struct bitma
 	int pol2;
 	struct bitmask *nodes2;
 
-	nodes2 = allocate_nodemask();
+	nodes2 = numa_allocate_nodemask();
 	
 	if (policy == MPOL_INTERLEAVE) {
 		if (get_mempolicy(&ilnode, NULL, 0, shmptr,
@@ -250,7 +250,7 @@ void verify_shm(int policy, struct bitma
 			      policy_name(pol2), policy_name(policy));
 			return;
 		}
-		if (memcmp(nodes2, nodes, bitmask_nbytes(nodes))) {
+		if (memcmp(nodes2, nodes, numa_bitmask_nbytes(nodes))) {
 			vwarn(p, "mismatched node mask\n"); 
 			printmask("expected", nodes);
 			printmask("real", nodes2);
@@ -261,7 +261,7 @@ void verify_shm(int policy, struct bitma
 
 		switch (policy) { 
 		case MPOL_INTERLEAVE: 
-			if (node < 0 || !nodemask_isset(nodes2, node))
+			if (node < 0 || !numa_bitmask_isbitset(nodes2, node))
 				vwarn(p, "interleave node out of range %d\n", node);
 			if (node != ilnode) { 
 				vwarn(p, "expected interleave node %d, got %d\n",
@@ -272,7 +272,7 @@ void verify_shm(int policy, struct bitma
 			break;
 		case MPOL_PREFERRED:
 		case MPOL_BIND:
-			if (!nodemask_isset(nodes2, node)) {
+			if (!numa_bitmask_isbitset(nodes2, node)) {
 				vwarn(p, "unexpected node %d\n", node);
 				printmask("expected", nodes2);
 			}	
Index: numactl-1.0.2/numaint.h
===================================================================
--- numactl-1.0.2.orig/numaint.h
+++ numactl-1.0.2/numaint.h
@@ -1,15 +1,19 @@
 /* Internal interfaces of libnuma */
 #include "bitops.h"
 
-extern int numa_sched_setaffinity(pid_t pid, struct bitmask *mask);
-extern int numa_sched_getaffinity(pid_t pid, struct bitmask *mask);
-extern int numa_sched_setaffinity_int(pid_t pid, struct bitmask *mask);
-extern int numa_sched_getaffinity_int(pid_t pid, struct bitmask *mask);
-extern long get_mempolicy_int(int *policy, const unsigned long *nmask,
+extern int numa_sched_setaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask);
+extern int numa_sched_getaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask);
+extern int numa_sched_setaffinity_v1_int(pid_t pid, unsigned len,const unsigned long *mask);
+extern int numa_sched_getaffinity_v1_int(pid_t pid, unsigned len,const unsigned long *mask);
+extern int numa_sched_setaffinity_v2(pid_t pid, struct bitmask *mask);
+extern int numa_sched_getaffinity_v2(pid_t pid, struct bitmask *mask);
+extern int numa_sched_setaffinity_v2_int(pid_t pid, struct bitmask *mask);
+extern int numa_sched_getaffinity_v2_int(pid_t pid, struct bitmask *mask);
+extern long get_mempolicy(int *policy, const unsigned long *nmask,
                               unsigned long maxnode, void *addr, int flags);
-extern long mbind_int(void *start, unsigned long len, int mode, 
+extern long mbind(void *start, unsigned long len, int mode,
 	  const unsigned long *nmask, unsigned long maxnode, unsigned flags);
-extern long set_mempolicy_int(int mode, const unsigned long *nmask, 
+extern long set_mempolicy(int mode, const unsigned long *nmask,
 			  unsigned long maxnode);
 extern long migrate_pages(int pid, unsigned long maxnode, const unsigned long *frommask,
 	const unsigned long *tomask);
Index: numactl-1.0.2/Makefile
===================================================================
--- numactl-1.0.2.orig/Makefile
+++ numactl-1.0.2/Makefile
@@ -69,7 +69,7 @@ stream: stream_lib.o stream_main.o  libn
 stream_main.o: stream_main.c
 
 libnuma.so.1: libnuma.o syscall.o distance.o
-	${CC} -shared -Wl,-soname=libnuma.so.1 -o libnuma.so.1 $^
+	${CC} -shared -Wl,-soname=libnuma.so.1 -Wl,--version-script,versions.ldscript -Wl,-init,numa_init -o libnuma.so.1 $^
 
 libnuma.so: libnuma.so.1
 	ln -sf libnuma.so.1 libnuma.so
Index: numactl-1.0.2/versions.ldscript
===================================================================
--- /dev/null
+++ numactl-1.0.2/versions.ldscript
@@ -0,0 +1,143 @@
+# Symbols defined in the library which aren't specifically bound to a
+# version node are effectively bound to an unspecified base version of
+# the library. It is possible to bind all otherwise unspecified symbols
+# to a given version node using `global: *' somewhere in the version script.
+#
+# The interfaces at the "v1" level.
+# At this level we present these functions to the linker (and thus to an
+# application).
+# Any functions not defined in the global list (i.e. "local") will be internal
+# to the library (i.e. not exported but used within the library).
+# Thus the real function names, "numa_bind_v1" etc, are local and won't
+# be known to the linker.
+
+# the first 16 have v1 aliases
+# 3 of the 5 system calls that libnuma provides are common to all versions:
+libnuma_1.1 {
+  global:
+    set_mempolicy;
+    get_mempolicy;
+    mbind;
+    numa_all_nodes;
+    numa_alloc;
+    numa_alloc_interleaved;
+    numa_alloc_interleaved_subset;
+    numa_alloc_local;
+    numa_alloc_onnode;
+    numa_available;
+    numa_bind;
+    numa_distance;
+    numa_error;
+    numa_exit_on_error;
+    numa_free;
+    numa_get_interleave_mask;
+    numa_get_interleave_node;
+    numa_get_membind;
+    numa_get_run_node_mask;
+    numa_interleave_memory;
+    numa_max_node;
+    numa_migrate_pages;
+    numa_no_nodes;
+    numa_node_size64;
+    numa_node_size;
+    numa_node_to_cpus;
+    numa_pagesize;
+    numa_parse_bitmap;
+    numa_police_memory;
+    numa_preferred;
+    numa_run_on_node;
+    numa_run_on_node_mask;
+    numa_sched_getaffinity;
+    numa_sched_setaffinity;
+    numa_set_bind_policy;
+    numa_set_interleave_mask;
+    numa_set_localalloc;
+    numa_set_membind;
+    numa_set_preferred;
+    numa_set_strict;
+    numa_setlocal_memory;
+    numa_tonode_memory;
+    numa_tonodemask_memory;
+    numa_warn;
+  local:
+    *;
+};
+
+# The interfaces at the "v2" level.
+# The first 17 have v2 aliases
+# We add the bitmask_ functions
+# and the move_pages and migrate_pages system calls
+# 1.2 depends on 1.1
+
+libnuma_1.2 {
+  global:
+    set_mempolicy;
+    get_mempolicy;
+    mbind;
+    move_pages;
+    migrate_pages;
+    numa_all_cpus_ptr;
+    numa_all_nodes_ptr;
+    numa_alloc;
+    numa_alloc_interleaved;
+    numa_alloc_interleaved_subset;
+    numa_alloc_local;
+    numa_alloc_onnode;
+    numa_allocate_cpumask;
+    numa_allocate_nodemask;
+    numa_available;
+    numa_bind;
+    numa_bitmask_alloc;
+    numa_bitmask_clearall;
+    numa_bitmask_clearbit;
+    numa_bitmask_equal;
+    numa_bitmask_free;
+    numa_bitmask_isbitset;
+    numa_bitmask_nbytes;
+    numa_bitmask_setall;
+    numa_bitmask_setbit;
+    numa_distance;
+    numa_error;
+    numa_exit_on_error;
+    numa_free;
+    numa_get_interleave_mask;
+    numa_get_interleave_node;
+    numa_get_membind;
+    numa_get_run_node_mask;
+    numa_interleave_memory;
+    numa_max_node;
+    numa_max_possible_node;
+    numa_migrate_pages;
+    numa_move_pages;
+    numa_no_nodes_ptr;
+    numa_node_size64;
+    numa_node_size;
+    numa_node_to_cpus;
+    numa_num_configured_cpus;
+    numa_num_configured_nodes;
+    numa_num_possible_nodes;
+    numa_num_task_cpus;
+    numa_num_task_nodes;
+    numa_pagesize;
+    numa_parse_bitmap;
+    numa_parse_cpustring;
+    numa_parse_nodestring;
+    numa_police_memory;
+    numa_preferred;
+    numa_run_on_node;
+    numa_run_on_node_mask;
+    numa_sched_getaffinity;
+    numa_sched_setaffinity;
+    numa_set_bind_policy;
+    numa_set_interleave_mask;
+    numa_set_localalloc;
+    numa_set_membind;
+    numa_set_preferred;
+    numa_set_strict;
+    numa_setlocal_memory;
+    numa_tonode_memory;
+    numa_tonodemask_memory;
+    numa_warn;
+  local:
+    *;
+} libnuma_1.1;
Index: numactl-1.0.2/numactl.c
===================================================================
--- numactl-1.0.2.orig/numactl.c
+++ numactl-1.0.2/numactl.c
@@ -93,12 +93,12 @@ void usage_msg(char *msg, ...) 
 
 void show_physcpubind(void)
 {
-	int ncpus = number_of_configured_cpus();
+	int ncpus = numa_num_configured_cpus();
 	
 	for (;;) { 
 		struct bitmask *cpubuf;
 
-		cpubuf = bitmask_alloc(ncpus);
+		cpubuf = numa_bitmask_alloc(ncpus);
 
 		if (numa_sched_getaffinity(0, cpubuf) < 0) {
 			if (errno == EINVAL && ncpus < 1024*1024) {
@@ -118,7 +118,7 @@ void show(void)
 	struct bitmask *membind, *interleave, *cpubind;
 	unsigned long cur;
 	int policy;
-	int numa_num_nodes = number_of_possible_nodes();
+	int numa_num_nodes = numa_num_possible_nodes();
 	
 	if (numa_available() < 0) { 
 		show_physcpubind();
@@ -200,13 +200,13 @@ static void print_distances(int maxnode)
 void print_node_cpus(int node)
 {
 	int len = 1;
-	int conf_cpus = number_of_configured_cpus();
+	int conf_cpus = numa_num_configured_cpus();
 
 	for (;;) { 
 		int i, err;
 		struct bitmask *cpus;
 
-		cpus = bitmask_alloc(conf_cpus);
+		cpus = numa_bitmask_alloc(conf_cpus);
 		errno = 0;
 		err = numa_node_to_cpus(node, cpus);
 		if (err < 0) {
@@ -217,7 +217,7 @@ void print_node_cpus(int node)
 			break; 
 		}
 		for (i = 0; i < len*BITS_PER_LONG; i++) 
-			if (bitmask_isbitset(cpus, i))
+			if (numa_bitmask_isbitset(cpus, i))
 				printf(" %d", i);
 		break;
 	}
@@ -227,7 +227,7 @@ void print_node_cpus(int node)
 void hardware(void)
 { 
 	int i;
-	int maxnode = number_of_configured_nodes()-1;
+	int maxnode = numa_num_configured_nodes()-1;
 	printf("available: %d nodes (0-%d)\n", 1+maxnode, maxnode); 	
 	for (i = 0; i <= maxnode; i++) { 
 		char buf[64];
@@ -322,11 +322,11 @@ void get_short_opts(struct option *o, ch
 
 int main(int ac, char **av)
 {
-	int c, ncpus, i, nnodes=0;
+	int c, i, nnodes=0;
 	long node=-1;
 	char *end;
 	char shortopts[array_len(opts)*2 + 1];
-	struct bitmask *mask;
+	struct bitmask *mask = NULL;
 
 	get_short_opts(opts,shortopts);
 	while ((c = getopt_long(ac, av, shortopts, opts, NULL)) != -1) {
@@ -340,7 +340,12 @@ int main(int ac, char **av)
 			exit(0);
 		case 'i': /* --interleave */
 			checknuma();
-			mask = nodemask(optarg);
+			mask = numa_parse_nodestring(optarg);
+			if (!mask) {
+				printf ("<%s> is invalid\n", optarg);
+				usage();
+			}
+
 			errno = 0;
 			setpolicy(MPOL_INTERLEAVE);
 			if (shmfd >= 0)
@@ -353,7 +358,11 @@ int main(int ac, char **av)
 		case 'c': /* --cpubind */
 			dontshm("-c/--cpubind/--cpunodebind");
 			checknuma();
-			mask = nodemask(optarg);
+			mask = numa_parse_nodestring(optarg);
+			if (!mask) {
+				printf ("<%s> is invalid\n", optarg);
+				usage();
+			}
 			errno = 0;
 			check_cpubind(do_shm);
 			did_cpubind = 1;
@@ -364,7 +373,11 @@ int main(int ac, char **av)
 		{
 			struct bitmask *cpubuf;
 			dontshm("-C/--physcpubind");
-			cpubuf = cpumask(optarg, &ncpus);
+			cpubuf = numa_parse_cpustring(optarg);
+			if (!cpubuf) {
+				printf ("<%s> is invalid\n", optarg);
+				usage();
+			}
 			errno = 0;
 			check_cpubind(do_shm);
 			did_cpubind = 1;
@@ -376,7 +389,11 @@ int main(int ac, char **av)
 		case 'm': /* --membind */
 			checknuma();
 			setpolicy(MPOL_BIND);
-			mask = nodemask(optarg); 
+			mask = numa_parse_nodestring(optarg);
+			if (!mask) {
+				printf ("<%s> is invalid\n", optarg);
+				usage();
+			}
 			errno = 0;
 			numa_set_bind_policy(1);
 			if (shmfd >= 0) { 
@@ -390,16 +407,20 @@ int main(int ac, char **av)
 		case 'p': /* --preferred */
 			checknuma();
 			setpolicy(MPOL_PREFERRED);
-			mask = nodemask(optarg);
+			mask = numa_parse_nodestring(optarg);
+			if (!mask) {
+				printf ("<%s> is invalid\n", optarg);
+				usage();
+			}
 			for (i=0; i<mask->size; i++) {
-				if (bitmask_isbitset(mask, i)) {
+				if (numa_bitmask_isbitset(mask, i)) {
 					node = i;
 					nnodes++;
 				}
 			}
 			if (nnodes != 1)
 				usage();
-			bitmask_free(mask);
+			numa_bitmask_free(mask);
 			errno = 0;
 			numa_set_bind_policy(0);
 			if (shmfd >= 0) 
@@ -476,7 +497,10 @@ int main(int ac, char **av)
 			if (set_policy < 0) 
 				complain("Need a policy first to verify");
 			numa_police_memory(shmptr, shmlen); 
-			verify_shm(set_policy, mask);
+			if (!mask)
+				complain("Need a mask to verify");
+			else
+				verify_shm(set_policy, mask);
 			break;
 
 		default:
Index: numactl-1.0.2/util.c
===================================================================
--- numactl-1.0.2.orig/util.c
+++ numactl-1.0.2/util.c
@@ -31,212 +31,22 @@ void printmask(char *name, struct bitmas
 
 	printf("%s: ", name); 
 	for (i = 0; i <= mask->size; i++)
-		if (bitmask_isbitset(mask, i))
+		if (numa_bitmask_isbitset(mask, i))
 			printf("%d ", i); 
 	putchar('\n');
 } 
 
-/*
- * Extract a node or processor number from the given string.
- * Allow a relative node / processor specification within the allowed
- * set if "relative" is nonzero
- */
-unsigned long get_nr(char *s, char **end, struct bitmask *bmp, int relative)
-{
-	long i, nr;
-
-	if (!relative)
-		return strtoul(s, end, 0);
-
-	nr = strtoul(s, end, 0);
-	if (s == *end)
-		return nr;
-	/* Find the nth set bit */
-	for (i = 0; nr >= 0 && i <= bmp->size; i++)
-		if (bitmask_isbitset(bmp, i))
-			nr--;
-	return i-1;
-}
-
-/*
- * cpumask() is called to create a cpumask_t mask, given
- * an ascii string such as 25 or 12-15 or 1,3,5-7 or +6-10.
- * (the + indicates that the numbers are cpuset-relative)
- *
- * The cpus may be specified as absolute, or relative to the current cpuset.
- * The list of available cpus for this task is in map "numa_all_cpus",
- * which may represent all cpus or the cpus in the current cpuset.
- * (it is set up by read_constraints() from the current task's Cpus_allowed)
- *
- * The caller must free the returned cpubuf buffer.
- */
-struct bitmask *
-cpumask(char *s, int *ncpus)
-{
-	int invert = 0, relative=0;
-	int conf_cpus = number_of_configured_cpus();
-	int task_cpus = number_of_task_cpus();
-	char *end; 
-	struct bitmask *cpubuf;
-
-	cpubuf = allocate_cpumask();
-
-	if (s[0] == 0) 
-		return cpubuf;
-	if (*s == '!') { 
-		invert = 1;
-		s++;
-	}
-	if (*s == '+') {
-		relative++;
-		s++;
-	}
-	do {
-		unsigned long arg;
-		int i;
-
-		if (!strcmp(s,"all")) { 
-			int i;
-			for (i = 0; i < task_cpus; i++)
-				bitmask_setbit(cpubuf, i);
-			s+=4;
-			break;
-		}
-		arg = get_nr(s, &end, numa_all_cpus, relative);
-		if (end == s)
-			complain("unparseable cpu description `%s'\n", s);
-		if (arg >= task_cpus)
-			complain("cpu argument %s is out of range\n", s);
-		i = arg;
-		bitmask_setbit(cpubuf, i);
-		s = end; 
-		if (*s == '-') {
-			char *end2;
-			unsigned long arg2;
-			int i;
-			arg2 = get_nr(++s, &end2, numa_all_cpus, relative);
-			if (end2 == s)
-				complain("missing cpu argument %s\n", s);
-			if (arg2 >= task_cpus)
-				complain("cpu argument %s out of range\n", s);
-			while (arg <= arg2) {
-				i = arg;
-				if (bitmask_isbitset(numa_all_cpus, i))
-					bitmask_setbit(cpubuf, i);
-				arg++;
-			}
-			s = end2;
-		}
-	} while (*s++ == ','); 
-	if (s[-1] != '\0')
-		usage();
-	if (invert) { 
-		int i;
-		for (i = 0; i < conf_cpus; i++) {
-			if (bitmask_isbitset(cpubuf, i))
-				bitmask_clearbit(cpubuf, i);
-			else
-				bitmask_setbit(cpubuf, i);
-		}
-	} 
-	*ncpus = cpubuf->size;
-	return cpubuf;	
-}
-
 void printcpumask(char *name, struct bitmask *mask)
 { 
 	int i;
 	printf("%s: ", name);
 	for (i = 0; i < mask->size; i++) {
-		if (bitmask_isbitset(mask, i))
+		if (numa_bitmask_isbitset(mask, i))
 			printf("%d ", i);
 	}
 	putchar('\n');
 } 
 
-/*
- * nodemask() is called to create a node mask, given
- * an ascii string such as 25 or 12-15 or 1,3,5-7 or +6-10.
- * (the + indicates that the numbers are cpuset-relative)
- *
- * The nodes may be specified as absolute, or relative to the current cpuset.
- * The list of available nodes is in map "numa_all_nodes",
- * which may represent all nodes or the nodes in the current cpuset.
- * (it is set up by read_constraints() from the current task's Mems_allowed)
- *
- * The caller must free the returned nodebuf buffer.
- */
-struct bitmask *
-nodemask(char *s)
-{
-	int maxnode = numa_max_node();
-	int invert = 0, relative = 0;
-	int conf_nodes = number_of_configured_nodes();
-	int task_nodes = number_of_task_nodes();
-	char *end; 
-	struct bitmask *nodebuf;
-
-	nodebuf = allocate_nodemask();
-
-	if (s[0] == 0) 
-		return numa_no_nodes;
-	if (*s == '!') { 
-		invert = 1;
-		s++;
-	}
-	if (*s == '+') {
-		relative++;
-		s++;
-	}
-	do {
-		unsigned long arg;
-		int i;
-		if (!strcmp(s,"all")) { 
-			int i;
-			for (i = 0; i < task_nodes; i++)
-				bitmask_setbit(nodebuf, i);
-			s+=4;
-			break;
-		}
-		arg = get_nr(s, &end, numa_all_nodes, relative);
-		if (end == s)
-			complain("unparseable node description `%s'\n", s);
-		if (arg > maxnode)
-			complain("node argument %d is out of range\n", arg);
-		i = arg;
-		bitmask_setbit(nodebuf, i);
-		s = end; 
-		if (*s == '-') { 
-			char *end2;
-			unsigned long arg2;
-			arg2 = get_nr(++s, &end2, numa_all_nodes, relative);
-			if (end2 == s)
-				complain("missing node argument %s\n", s);
-			if (arg2 >= task_nodes)
-				complain("node argument %d out of range\n", arg2);
-			while (arg <= arg2) {
-				i = arg;
-				if (bitmask_isbitset(numa_all_nodes, i))
-					bitmask_setbit(nodebuf, i);
-				arg++;
-			}
-			s = end2;
-		}
-	} while (*s++ == ','); 
-	if (s[-1] != '\0')
-		usage();
-	if (invert) { 
-		int i;
-		for (i = 0; i < conf_nodes; i++) {
-			if (bitmask_isbitset(nodebuf, i))
-				bitmask_clearbit(nodebuf, i);
-			else
-				bitmask_setbit(nodebuf, i);
-		}
-	} 
-	return nodebuf;
-}
-
 void complain(char *fmt, ...)
 {
 	va_list ap;
Index: numactl-1.0.2/memhog.c
===================================================================
--- numactl-1.0.2.orig/memhog.c
+++ numactl-1.0.2/memhog.c
@@ -67,8 +67,8 @@ int main(int ac, char **av) 
 	int i;
 	int fd = -1; 
 
-	nodes = allocate_nodemask();
-	gnodes = allocate_nodemask();
+	nodes = numa_allocate_nodemask();
+	gnodes = numa_allocate_nodemask();
 
 	while (av[1] && av[1][0] == '-') { 
 		switch (av[1][1]) { 
@@ -96,7 +96,11 @@ int main(int ac, char **av) 
 		loose = 1;
 	policy = parse_policy(av[2], av[3]);
 	if (policy != MPOL_DEFAULT)
-		nodes = nodemask(av[3]);
+		nodes = numa_parse_nodestring(av[3]);
+        if (!nodes) {
+		printf ("<%s> is invalid\n", av[3]);
+		exit(1);
+	}
 	
 	if (fd >= 0)
 		map = mmap(NULL,length,PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
@@ -117,7 +121,7 @@ int main(int ac, char **av) 
 		ret = 1;
 		printf("policy %d gpolicy %d\n", policy, gpolicy); 
 	}
-	if (!loose && !bitmask_equal(gnodes, nodes)) {
+	if (!loose && !numa_bitmask_equal(gnodes, nodes)) {
 		printf("nodes differ %lx, %lx!\n",
 			gnodes->maskp[0], nodes->maskp[0]);
 		ret = 1;
Index: numactl-1.0.2/migspeed.c
===================================================================
--- numactl-1.0.2.orig/migspeed.c
+++ numactl-1.0.2/migspeed.c
@@ -38,8 +38,6 @@ void usage(void)
 	exit(1);
 }
 
-int numa_exit_on_error = 1;
-
 void displaymap(void)
 {
 	FILE *f = fopen("/proc/self/numa_maps","r");
@@ -102,7 +100,13 @@ int main(int argc, char *argv[])
 	if (verbose > 1)
 		printf("numa_max_node = %d\n", numa_max_node());
 
-	from = nodemask(argv[optind]);
+	numa_exit_on_error = 1;
+
+	from = numa_parse_nodestring(argv[optind]);
+	if (!from) {
+                printf ("<%s> is invalid\n", argv[optind]);
+		exit(1);
+	}
 	if (errno) {
 		perror("from mask");
 		exit(1);
@@ -114,7 +118,11 @@ int main(int argc, char *argv[])
 	if (!argv[optind+1])
 		usage();
 
-	to = nodemask(argv[optind+1]);
+	to = numa_parse_nodestring(argv[optind+1]);
+	if (!to) {
+                printf ("<%s> is invalid\n", argv[optind+1]);
+		exit(1);
+	}
 	if (errno) {
 		perror("to mask");
 		exit(1);
Index: numactl-1.0.2/stream_main.c
===================================================================
--- numactl-1.0.2.orig/stream_main.c
+++ numactl-1.0.2/stream_main.c
@@ -23,10 +23,14 @@ int main(int ac, char **av)
 
 	policy = parse_policy(av[1], av[2]); 
 
-        nodes = allocate_nodemask();
+        nodes = numa_allocate_nodemask();
 
 	if (av[1] && av[2])
-		nodes = nodemask(av[2]);
+		nodes = numa_parse_nodestring(av[2]);
+	if (!nodes) {
+		printf ("<%s> is invalid\n", av[2]);
+		exit(1);
+	}
 	size = stream_memsize();  
 	map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
 		   0, 0); 
Index: numactl-1.0.2/test/distance.c
===================================================================
--- numactl-1.0.2.orig/test/distance.c
+++ numactl-1.0.2/test/distance.c
@@ -11,7 +11,7 @@ int main(void)
 		exit(1);
 	}
 
-        numnodes = number_of_configured_nodes();
+        numnodes = numa_num_configured_nodes();
 	for (a = 0; a < numnodes; a++) { 
 		printf("%03d: ", a); 
 		if (numa_distance(a, a) != 10) { 
Index: numactl-1.0.2/test/mbind_mig_pages.c
===================================================================
--- numactl-1.0.2.orig/test/mbind_mig_pages.c
+++ numactl-1.0.2/test/mbind_mig_pages.c
@@ -34,10 +34,10 @@ int main(int argc, char **argv)
 
 	nr_nodes = numa_max_node()+1;
 
-	old_nodes = bitmask_alloc(nr_nodes);
-	new_nodes = bitmask_alloc(nr_nodes);
-	bitmask_setbit(old_nodes, 0);
-	bitmask_setbit(new_nodes, 1);
+	old_nodes = numa_bitmask_alloc(nr_nodes);
+	new_nodes = numa_bitmask_alloc(nr_nodes);
+	numa_bitmask_setbit(old_nodes, 0);
+	numa_bitmask_setbit(new_nodes, 1);
 
 	if (nr_nodes < 2) {
 		printf("A minimum of 2 nodes is required for this test.\n");
Index: numactl-1.0.2/test/migrate_pages.c
===================================================================
--- numactl-1.0.2.orig/test/migrate_pages.c
+++ numactl-1.0.2/test/migrate_pages.c
@@ -33,10 +33,10 @@ int main(int argc, char **argv)
 
 	nr_nodes = numa_max_node()+1;
 
-	old_nodes = bitmask_alloc(nr_nodes);
-        new_nodes = bitmask_alloc(nr_nodes);
-        bitmask_setbit(old_nodes, 1);
-        bitmask_setbit(new_nodes, 0);
+	old_nodes = numa_bitmask_alloc(nr_nodes);
+        new_nodes = numa_bitmask_alloc(nr_nodes);
+        numa_bitmask_setbit(old_nodes, 1);
+        numa_bitmask_setbit(new_nodes, 0);
 
 	if (nr_nodes < 2) {
 		printf("A minimum of 2 nodes is required for this test.\n");
Index: numactl-1.0.2/test/nodemap.c
===================================================================
--- numactl-1.0.2.orig/test/nodemap.c
+++ numactl-1.0.2/test/nodemap.c
@@ -8,13 +8,13 @@ int main(void)
 {
 	int i, k, w, ncpus;
 	struct bitmask *cpus;
-	int maxnode = number_of_configured_nodes()-1;
+	int maxnode = numa_num_configured_nodes()-1;
 
 	if (numa_available() < 0)  {
 		printf("no numa\n");
 		exit(1);
 	}
-	cpus = allocate_cpumask();
+	cpus = numa_allocate_cpumask();
 	ncpus = cpus->size;
 
 	for (i = 0; i <= maxnode ; i++) {
@@ -24,7 +24,7 @@ int main(void)
 		printf("%d: ", i); 
 		w = 0;
 		for (k = 0; k < ncpus; k++)
-			if (bitmask_isbitset(cpus, k))
+			if (numa_bitmask_isbitset(cpus, k))
 				printf(" %s%d", w>0?",":"", k);
 		putchar('\n');		
 	}
Index: numactl-1.0.2/test/prefered.c
===================================================================
--- numactl-1.0.2.orig/test/prefered.c
+++ numactl-1.0.2/test/prefered.c
@@ -18,8 +18,8 @@ int main(void)
 	int pol;
 	int node;
 	int err = 0;
-	nodes = bitmask_alloc(max+1);
-	mask = bitmask_alloc(max+1);
+	nodes = numa_bitmask_alloc(max+1);
+	mask = numa_bitmask_alloc(max+1);
 
 	for (i = max; i >= 0; --i) { 
 		char *mem = mmap(NULL, pagesize*(max+1), PROT_READ|PROT_WRITE, 
@@ -31,9 +31,9 @@ int main(void)
 
 		printf("%d offset %lx\n", i, (long)(adr - mem)); 
 
-		bitmask_clearall(nodes);
-		bitmask_clearall(mask);
-		bitmask_setbit(mask, i);
+		numa_bitmask_clearall(nodes);
+		numa_bitmask_clearall(mask);
+		numa_bitmask_setbit(mask, i);
 
 		if (mbind(adr,  pagesize, MPOL_PREFERRED, nodes->maskp,
 							nodes->size, 0) < 0)
@@ -45,7 +45,7 @@ int main(void)
 			err("get_mempolicy");
 	
 		assert(pol == MPOL_PREFERRED);
-		assert(bitmask_isbitset(mask, i));
+		assert(numa_bitmask_isbitset(mask, i));
 
 		node = 0x123;
 		
Index: numactl-1.0.2/test/tbitmap.c
===================================================================
--- numactl-1.0.2.orig/test/tbitmap.c
+++ numactl-1.0.2/test/tbitmap.c
@@ -73,14 +73,14 @@ int main(void)
 	struct bitmask *mask, *mask2;
 	int i;
 
-	mask  = bitmask_alloc(MASKSIZE);
-	mask2 = bitmask_alloc(MASKSIZE);
+	mask  = numa_bitmask_alloc(MASKSIZE);
+	mask2 = numa_bitmask_alloc(MASKSIZE);
 
 	printf("Testing bitmap functions\n");
 	for (i = 0; i < MASKSIZE; i++) {
-		bitmask_clearall(mask);
-		bitmask_clearall(mask2);
-		bitmask_setbit(mask, i);
+		numa_bitmask_clearall(mask);
+		numa_bitmask_clearall(mask2);
+		numa_bitmask_setbit(mask, i);
 		bitmap_scnprintf(buf, sizeof(buf), mask);
 		strcat(buf,"\n");
 		if (numa_parse_bitmap(buf, mask2) < 0)
Index: numactl-1.0.2/numademo.c
===================================================================
--- numactl-1.0.2.orig/numademo.c
+++ numactl-1.0.2/numademo.c
@@ -250,7 +250,7 @@ void test(enum test type)
 		memtest("memory without policy", numa_alloc(msize)); 
 	} 
 
-	numa_set_interleave_mask(numa_all_nodes);
+	numa_set_interleave_mask(numa_all_nodes_ptr);
 	memtest("manual interleaving to all nodes", numa_alloc(msize)); 
 
 	if (max_node > 0) { 
@@ -262,7 +262,7 @@ void test(enum test type)
 		printf("current interleave node %d\n", numa_get_interleave_node()); 
 	} 
 
-	numa_set_interleave_mask(numa_no_nodes);
+	numa_set_interleave_mask(numa_no_nodes_ptr);
 
 	nodes = numa_allocate_nodemask();
 
@@ -293,7 +293,7 @@ void test(enum test type)
 			numa_bitmask_setbit(nodes, k);
 			numa_set_membind(nodes);
 			memtest(buf, numa_alloc(msize)); 			
-			numa_set_membind(numa_all_nodes);
+			numa_set_membind(numa_all_nodes_ptr);
 		}
 		
 		numa_set_localalloc(); 
Index: numactl-1.0.2/migratepages.c
===================================================================
--- numactl-1.0.2.orig/migratepages.c
+++ numactl-1.0.2/migratepages.c
@@ -84,8 +84,16 @@ int main(int argc, char *argv[])
 	if (*end || end == argv[0])
 		usage();
 
-	fromnodes = nodemask(argv[1]);
-	tonodes = nodemask(argv[2]);
+	fromnodes = numa_parse_nodestring(argv[1]);
+	if (!fromnodes) {
+		printf ("<%s> is invalid\n", argv[1]);
+		exit(1);
+	}
+	tonodes = numa_parse_nodestring(argv[2]);
+	if (!tonodes) {
+		printf ("<%s> is invalid\n", argv[2]);
+		exit(1);
+	}
 
 	rc = numa_migrate_pages(pid, fromnodes, tonodes);
 
