diff --git a/providers/mlx5/bitmap.h b/providers/mlx5/bitmap.h
index 034fb98..b2c8a36 100644
--- a/providers/mlx5/bitmap.h
+++ b/providers/mlx5/bitmap.h
@@ -54,8 +54,6 @@
 #define MLX5_SHMAT_FLAGS 0
 #endif
 
-#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
-
 #ifndef HPAGE_SIZE
 #define HPAGE_SIZE		(2UL * 1024 * 1024)
 #endif
diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt
index d8a66be..58c77d5 100644
--- a/util/CMakeLists.txt
+++ b/util/CMakeLists.txt
@@ -1,4 +1,5 @@
 publish_internal_headers(util
+  bitmap.h
   cl_qmap.h
   compiler.h
   interval_set.h
@@ -9,6 +10,7 @@ publish_internal_headers(util
   )
 
 set(C_FILES
+  bitmap.c
   cl_map.c
   interval_set.c
   node_name_map.c
diff --git a/util/bitmap.c b/util/bitmap.c
new file mode 100644
index 0000000..e5ed30e
--- /dev/null
+++ b/util/bitmap.c
@@ -0,0 +1,180 @@
+/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file */
+
+#include "bitmap.h"
+
+#define BMP_WORD_INDEX(n) (BITS_TO_LONGS((n) + 1) - 1)
+#define BMP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
+#define BMP_LAST_WORD_MASK(end) (~BMP_FIRST_WORD_MASK(end))
+
+static unsigned long __word_ffs(const unsigned long *word)
+{
+	unsigned long i;
+
+	for (i = 0; i < BITS_PER_LONG; i++) {
+		if (bitmap_test_bit(word, i))
+			return i;
+	}
+
+	return i;
+}
+
+static unsigned long word_ffs(const unsigned long *word,
+			      unsigned long bmp_index, unsigned long end)
+{
+	unsigned long set_bit;
+
+	set_bit = __word_ffs(word);
+	set_bit += bmp_index * BITS_PER_LONG;
+	if (set_bit >= end)
+		return end;
+
+	return set_bit;
+}
+
+/*
+ * Finds the first set bit in the bitmap starting from
+ * 'start' bit until ('end'-1) bit.
+ *
+ * Returns the set bit index if found, otherwise returns 'end'.
+ */
+unsigned long bitmap_find_first_bit(const unsigned long *bmp,
+				    unsigned long start, unsigned long end)
+{
+	unsigned long mask;
+	unsigned long first_word;
+	unsigned long curr_idx = BMP_WORD_INDEX(start);
+	unsigned long end_idx = BMP_WORD_INDEX(end);
+
+	assert(start <= end);
+
+	mask = BMP_FIRST_WORD_MASK(start);
+
+	first_word = bmp[curr_idx] & mask;
+	if (first_word)
+		return word_ffs(&first_word, curr_idx, end);
+
+	for (curr_idx++; curr_idx <= end_idx; curr_idx++) {
+		if (!bmp[curr_idx])
+			continue;
+
+		return word_ffs(&bmp[curr_idx], curr_idx, end);
+	}
+
+	return end;
+}
+
+/*
+ * Zeroes bitmap bits in the following range: [start,end-1]
+ */
+void bitmap_zero_region(unsigned long *bmp, unsigned long start,
+			unsigned long end)
+{
+	unsigned long start_mask;
+	unsigned long last_mask;
+	unsigned long curr_idx = BMP_WORD_INDEX(start);
+	unsigned long end_idx = BMP_WORD_INDEX(end);
+
+	assert(start <= end);
+
+	start_mask = BMP_FIRST_WORD_MASK(start);
+	last_mask = BMP_LAST_WORD_MASK(end);
+
+	if (curr_idx == end_idx) {
+		bmp[curr_idx] &= ~(start_mask & last_mask);
+		return;
+	}
+
+	bmp[curr_idx] &= ~start_mask;
+
+	for (curr_idx++; curr_idx < end_idx; curr_idx++)
+		bmp[curr_idx] = 0;
+
+	bmp[curr_idx] &= ~last_mask;
+}
+
+/*
+ * Sets bitmap bits in the following range: [start,end-1]
+ */
+void bitmap_fill_region(unsigned long *bmp, unsigned long start,
+			unsigned long end)
+{
+	unsigned long start_mask;
+	unsigned long last_mask;
+	unsigned long curr_idx = BMP_WORD_INDEX(start);
+	unsigned long end_idx = BMP_WORD_INDEX(end);
+
+	assert(start <= end);
+
+	start_mask = BMP_FIRST_WORD_MASK(start);
+	last_mask = BMP_LAST_WORD_MASK(end);
+
+	if (curr_idx == end_idx) {
+		bmp[curr_idx] |= (start_mask & last_mask);
+		return;
+	}
+
+	bmp[curr_idx] |= start_mask;
+
+	for (curr_idx++; curr_idx < end_idx; curr_idx++)
+		bmp[curr_idx] = ULONG_MAX;
+
+	bmp[curr_idx] |= last_mask;
+}
+
+/*
+ * Checks whether the contiguous region of region_size bits starting from
+ * start is free.
+ *
+ * Returns true if the said region is free, otherwise returns false.
+ */
+static bool bitmap_is_free_region(unsigned long *bmp, unsigned long start,
+				  unsigned long region_size)
+{
+	unsigned long curr_idx;
+	unsigned long last_idx;
+	unsigned long last_mask;
+	unsigned long start_mask;
+
+	curr_idx = BMP_WORD_INDEX(start);
+	start_mask = BMP_FIRST_WORD_MASK(start);
+	last_idx = BMP_WORD_INDEX(start + region_size);
+	last_mask = BMP_LAST_WORD_MASK(start + region_size);
+
+	if (curr_idx == last_idx)
+		return !(bmp[curr_idx] & start_mask & last_mask);
+
+	if (bmp[curr_idx] & start_mask)
+		return false;
+
+	for (curr_idx++; curr_idx < last_idx; curr_idx++) {
+		if (bmp[curr_idx])
+			return false;
+	}
+
+	return !(bmp[curr_idx] & last_mask);
+}
+
+/*
+ * Finds a contiguous region with the size of region_size
+ * in the bitmap that is not set.
+ *
+ * Returns first index of such region if found,
+ * otherwise returns nbits.
+ */
+unsigned long bitmap_find_free_region(unsigned long *bmp,
+				      unsigned long nbits,
+				      unsigned long region_size)
+{
+	unsigned long start;
+
+	for (start = 0; start + region_size <= nbits; start++) {
+		if (bitmap_test_bit(bmp, start))
+			continue;
+
+		if (bitmap_is_free_region(bmp, start, region_size))
+			return start;
+	}
+
+	return nbits;
+}
+
diff --git a/util/bitmap.h b/util/bitmap.h
new file mode 100644
index 0000000..c48706a
--- /dev/null
+++ b/util/bitmap.h
@@ -0,0 +1,120 @@
+/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file */
+
+#ifndef UTIL_BITMAP_H
+#define UTIL_BITMAP_H
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+
+#define BMP_DECLARE(name, nbits) \
+	unsigned long (name)[BITS_TO_LONGS((nbits))]
+
+unsigned long bitmap_find_first_bit(const unsigned long *bmp,
+				    unsigned long start, unsigned long end);
+
+void bitmap_zero_region(unsigned long *bmp, unsigned long start,
+			unsigned long end);
+
+void bitmap_fill_region(unsigned long *bmp, unsigned long start,
+			unsigned long end);
+
+unsigned long bitmap_find_free_region(unsigned long *bmp,
+				      unsigned long nbits,
+				      unsigned long region_size);
+
+static inline void bitmap_fill(unsigned long *bmp, unsigned long nbits)
+{
+	unsigned long size = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+
+	memset(bmp, 0xff, size);
+}
+
+static inline void bitmap_zero(unsigned long *bmp, unsigned long nbits)
+{
+	unsigned long size = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+
+	memset(bmp, 0, size);
+}
+
+static inline bool bitmap_empty(const unsigned long *bmp, unsigned long nbits)
+{
+	unsigned long i;
+	unsigned long mask = ULONG_MAX;
+
+	assert(nbits);
+
+	for (i = 0; i < BITS_TO_LONGS(nbits) - 1; i++) {
+		if (bmp[i] != 0)
+			return false;
+	}
+
+	if (nbits % BITS_PER_LONG)
+		mask = (1UL << (nbits % BITS_PER_LONG)) - 1;
+
+	return (bmp[i] & mask) ? false : true;
+}
+
+static inline bool bitmap_full(const unsigned long *bmp, unsigned long nbits)
+{
+	unsigned long i;
+	unsigned long mask = ULONG_MAX;
+
+	assert(nbits);
+
+	for (i = 0; i < BITS_TO_LONGS(nbits) - 1; i++) {
+		if (bmp[i] != -1UL)
+			return false;
+	}
+
+	if (nbits % BITS_PER_LONG)
+		mask = (1UL << (nbits % BITS_PER_LONG)) - 1;
+
+	return ((bmp[i] & mask) ^ (mask)) ? false : true;
+}
+
+static inline void bitmap_set_bit(unsigned long *bmp, unsigned long idx)
+{
+	bmp[(idx / BITS_PER_LONG)] |= (1UL << (idx % BITS_PER_LONG));
+}
+
+static inline void bitmap_clear_bit(unsigned long *bmp, unsigned long idx)
+{
+	bmp[(idx / BITS_PER_LONG)] &= ~(1UL << (idx % BITS_PER_LONG));
+}
+
+static inline bool bitmap_test_bit(const unsigned long *bmp, unsigned long idx)
+{
+	return !!(bmp[(idx / BITS_PER_LONG)] &
+		 (1UL << (idx % BITS_PER_LONG)));
+}
+
+static inline unsigned long *bitmap_alloc0(unsigned long size)
+{
+	unsigned long *bmp;
+
+	bmp = calloc(BITS_TO_LONGS(size), sizeof(long));
+	if (!bmp)
+		return NULL;
+
+	return bmp;
+}
+
+static inline unsigned long *bitmap_alloc1(unsigned long size)
+{
+	unsigned long *bmp;
+
+	bmp = bitmap_alloc0(size);
+	if (!bmp)
+		return NULL;
+
+	bitmap_fill(bmp, size);
+
+	return bmp;
+}
+
+#endif
diff --git a/util/util.h b/util/util.h
index f721b83..af03c42 100644
--- a/util/util.h
+++ b/util/util.h
@@ -28,6 +28,7 @@ static inline bool __good_snprintf(size_t len, int rc)
 
 #define BITS_PER_LONG	   (8 * sizeof(long))
 #define BITS_PER_LONG_LONG (8 * sizeof(long long))
+#define BITS_TO_LONGS(nr)  (((nr) + BITS_PER_LONG - 1) / BITS_PER_LONG)
 
 #define GENMASK(h, l) \
 	(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
