mempool: Use masks to get pool range from pointer and stride for percpu offset
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 8 Mar 2024 20:34:01 +0000 (15:34 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 8 Mar 2024 20:34:01 +0000 (15:34 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I45bb460be66bc4843ead316d7b870958cd1217c2

include/rseq/mempool.h
src/rseq-mempool.c
tests/mempool_test.c

index 3be30926c62282420adbd89154747462c1319c6f..7e20f50eb15255cd7d5ac38807ebc58f40543d24 100644 (file)
@@ -143,6 +143,10 @@ void __rseq_percpu *rseq_percpu_zmalloc(struct rseq_percpu_pool *pool);
  * - rseq_percpu_pool_set_malloc(),
  * - rseq_percpu_pool_set_zmalloc().
  *
+ * The @stride argument to __rseq_percpu_free() is a configurable
+ * stride, which must match the stride received by pool creation.
+ * rseq_percpu_free() uses the default RSEQ_PERCPU_STRIDE stride.
+ *
  * This API is MT-safe.
  */
 void __rseq_percpu_free(void __rseq_percpu *ptr, size_t percpu_stride);
@@ -150,30 +154,31 @@ void __rseq_percpu_free(void __rseq_percpu *ptr, size_t percpu_stride);
 #define rseq_percpu_free(ptr)  __rseq_percpu_free(ptr, RSEQ_PERCPU_STRIDE)
 
 /*
- * rseq_percpu_ptr: Decode a per-cpu pointer.
+ * rseq_percpu_ptr: Offset a per-cpu pointer for a given CPU.
  *
- * Decode a per-cpu pointer @ptr to get the associated pointer for the
- * given @cpu. The @ptr argument is a __rseq_percpu encoded pointer
- * returned by either:
+ * Offset a per-cpu pointer @ptr to get the associated pointer for the
+ * given @cpu. The @ptr argument is a __rseq_percpu pointer returned by
+ * either:
  *
  * - rseq_percpu_malloc(),
  * - rseq_percpu_zmalloc(),
  * - rseq_percpu_pool_set_malloc(),
  * - rseq_percpu_pool_set_zmalloc().
  *
- * The __rseq_percpu pointer can be decoded with rseq_percpu_ptr() even
- * after it has been freed, as long as its associated pool has not been
- * destroyed. However, memory pointed to by the decoded pointer should
- * not be accessed after the __rseq_percpu pointer has been freed.
+ * The macros rseq_percpu_ptr() and __rseq_percpu_ptr() preserve the
+ * type of the @ptr parameter for the returned pointer, but removes the
+ * __rseq_percpu annotation.
  *
- * The macro rseq_percpu_ptr() preserves the type of the @ptr parameter
- * for the returned pointer, but removes the __rseq_percpu annotation.
+ * The macro __rseq_percpu_ptr() takes a configurable @stride argument,
+ * whereas rseq_percpu_ptr() uses the RSEQ_PERCPU_STRIDE default stride.
+ * This must match the stride used for pool creation.
  *
  * This API is MT-safe.
  */
-void *__rseq_percpu_ptr(void __rseq_percpu *ptr, int cpu, size_t percpu_stride);
-#define rseq_percpu_ptr(ptr, cpu)      \
-       ((__typeof__(*(ptr)) *) __rseq_percpu_ptr(ptr, cpu, RSEQ_PERCPU_STRIDE))
+#define __rseq_percpu_ptr(ptr, cpu, stride) \
+       ((__typeof__(*(ptr)) *) ((uintptr_t) (ptr) + ((unsigned int) (cpu) * (uintptr_t) (stride))))
+
+#define rseq_percpu_ptr(ptr, cpu) __rseq_percpu_ptr(ptr, cpu, RSEQ_PERCPU_STRIDE)
 
 /*
  * rseq_percpu_pool_set_create: Create a pool set.
index 0379ba4cb3f44e3dee41ce9cd6ebb247831ddfbc..23a26d2c686b3277d7e98fc40db2820b543f7793 100644 (file)
@@ -70,6 +70,8 @@
 
 #define MOVE_PAGES_BATCH_SIZE  4096
 
+#define RANGE_HEADER_OFFSET    sizeof(struct rseq_percpu_pool_range)
+
 struct free_list_node;
 
 struct free_list_node {
@@ -93,6 +95,7 @@ struct rseq_percpu_pool_range;
 struct rseq_percpu_pool_range {
        struct rseq_percpu_pool_range *next;
        struct rseq_percpu_pool *pool;  /* Backward ref. to container pool. */
+       void *header;
        void *base;
        size_t next_unused;
        /* Track alloc/free. */
@@ -147,17 +150,6 @@ void *__rseq_pool_percpu_ptr(struct rseq_percpu_pool *pool, int cpu,
        return pool->ranges->base + (stride * cpu) + item_offset;
 }
 
-void *__rseq_percpu_ptr(void __rseq_percpu *_ptr, int cpu, size_t stride)
-{
-       uintptr_t ptr = (uintptr_t) _ptr;
-       uintptr_t item_offset = ptr & MAX_POOL_LEN_MASK;
-       uintptr_t pool_index = ptr >> POOL_INDEX_SHIFT;
-       struct rseq_percpu_pool *pool = &rseq_percpu_pool[pool_index];
-
-       assert(cpu >= 0);
-       return __rseq_pool_percpu_ptr(pool, cpu, item_offset, stride);
-}
-
 static
 void rseq_percpu_zero_item(struct rseq_percpu_pool *pool, uintptr_t item_offset)
 {
@@ -386,7 +378,7 @@ int rseq_percpu_pool_range_destroy(struct rseq_percpu_pool *pool,
 {
        destroy_alloc_bitmap(pool, range);
        /* range is a header located one page before the aligned mapping. */
-       return pool->attr.munmap_func(pool->attr.mmap_priv, range,
+       return pool->attr.munmap_func(pool->attr.mmap_priv, range->header,
                        (pool->percpu_stride * pool->max_nr_cpus) + rseq_get_page_len());
 }
 
@@ -477,6 +469,7 @@ struct rseq_percpu_pool_range *rseq_percpu_pool_range_create(struct rseq_percpu_
 {
        struct rseq_percpu_pool_range *range;
        unsigned long page_size;
+       void *header;
        void *base;
 
        page_size = rseq_get_page_len();
@@ -484,11 +477,13 @@ struct rseq_percpu_pool_range *rseq_percpu_pool_range_create(struct rseq_percpu_
        base = aligned_mmap_anonymous(pool, page_size,
                        pool->percpu_stride * pool->max_nr_cpus,
                        pool->percpu_stride,
-                       (void **) &range, page_size);
+                       &header, page_size);
        if (!base)
                return NULL;
+       range = (struct rseq_percpu_pool_range *) (base - RANGE_HEADER_OFFSET);
        range->pool = pool;
        range->base = base;
+       range->header = header;
        if (pool->attr.robust_set) {
                if (create_alloc_bitmap(pool, range))
                        goto error_alloc;
@@ -656,7 +651,7 @@ void __rseq_percpu *__rseq_percpu_malloc(struct rseq_percpu_pool *pool, bool zer
                /* Remove node from free list (update head). */
                pool->free_list_head = node->next;
                item_offset = (uintptr_t) ((void *) node - pool->ranges->base);
-               addr = (void *) (((uintptr_t) pool->index << POOL_INDEX_SHIFT) | item_offset);
+               addr = (void __rseq_percpu *) (pool->ranges->base + item_offset);
                goto end;
        }
        if (pool->ranges->next_unused + pool->item_len > pool->percpu_stride) {
@@ -665,7 +660,7 @@ void __rseq_percpu *__rseq_percpu_malloc(struct rseq_percpu_pool *pool, bool zer
                goto end;
        }
        item_offset = pool->ranges->next_unused;
-       addr = (void *) (((uintptr_t) pool->index << POOL_INDEX_SHIFT) | item_offset);
+       addr = (void __rseq_percpu *) (pool->ranges->base + item_offset);
        pool->ranges->next_unused += pool->item_len;
 end:
        if (addr)
@@ -714,9 +709,10 @@ void clear_alloc_slot(struct rseq_percpu_pool *pool, size_t item_offset)
 void __rseq_percpu_free(void __rseq_percpu *_ptr, size_t percpu_stride)
 {
        uintptr_t ptr = (uintptr_t) _ptr;
-       uintptr_t item_offset = ptr & MAX_POOL_LEN_MASK;
-       uintptr_t pool_index = ptr >> POOL_INDEX_SHIFT;
-       struct rseq_percpu_pool *pool = &rseq_percpu_pool[pool_index];
+       void *range_base = (void *) (ptr & (~(percpu_stride - 1)));
+       struct rseq_percpu_pool_range *range = (struct rseq_percpu_pool_range *) (range_base - RANGE_HEADER_OFFSET);
+       struct rseq_percpu_pool *pool = range->pool;
+       uintptr_t item_offset = ptr & (percpu_stride - 1);
        struct free_list_node *head, *item;
 
        pthread_mutex_lock(&pool->lock);
@@ -724,7 +720,7 @@ void __rseq_percpu_free(void __rseq_percpu *_ptr, size_t percpu_stride)
        /* Add ptr to head of free list */
        head = pool->free_list_head;
        /* Free-list is in CPU 0 range. */
-       item = (struct free_list_node *)__rseq_pool_percpu_ptr(pool, 0, item_offset, percpu_stride);
+       item = (struct free_list_node *) ptr;
        item->next = head;
        pool->free_list_head = item;
        pthread_mutex_unlock(&pool->lock);
index 9bc819b7581e351d28193526ea5f736507aada25..6f8597a402f9a20ff9b89c053c6191d5a4a70626 100644 (file)
@@ -55,7 +55,7 @@ static void test_mempool_fill(size_t stride)
                if (!ptr)
                        break;
                /* Link items in cpu 0. */
-               cpuptr = (struct test_data *) __rseq_percpu_ptr(ptr, 0, stride);
+               cpuptr = __rseq_percpu_ptr(ptr, 0, stride);
                cpuptr->backref = ptr;
                /* Randomize items in list. */
                if (count & 1)
@@ -70,7 +70,7 @@ static void test_mempool_fill(size_t stride)
        list_for_each_entry(iter, &list, node) {
                ptr = iter->backref;
                for (i = 0; i < CPU_SETSIZE; i++) {
-                       struct test_data *cpuptr = (struct test_data *) __rseq_percpu_ptr(ptr, i, stride);
+                       struct test_data *cpuptr = __rseq_percpu_ptr(ptr, i, stride);
 
                        if (cpuptr->value != 0)
                                abort();
This page took 0.040074 seconds and 4 git commands to generate.