mm/percpu.c: introduce pcpu_alloc_size()
authorHou Tao <houtao1@huawei.com>
Fri, 20 Oct 2023 13:31:57 +0000 (21:31 +0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 20 Oct 2023 21:15:06 +0000 (14:15 -0700)
Introduce pcpu_alloc_size() to get the size of the dynamic per-cpu
area. It will be used by bpf memory allocator in the following patches.
BPF memory allocator maintains per-cpu area caches for multiple area
sizes and its free API only has the to-be-freed per-cpu pointer, so it
needs the size of dynamic per-cpu area to select the corresponding cache
when bpf program frees the dynamic per-cpu pointer.

Acked-by: Dennis Zhou <dennis@kernel.org>
Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20231020133202.4043247-3-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/percpu.h
mm/percpu.c

index 68fac2e7cbe67053cafa2372661b2f0de3425d6f..8c677f185901bc75bfd1e8b7faeed2c63c47388f 100644 (file)
@@ -132,6 +132,7 @@ extern void __init setup_per_cpu_areas(void);
 extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) __alloc_size(1);
 extern void __percpu *__alloc_percpu(size_t size, size_t align) __alloc_size(1);
 extern void free_percpu(void __percpu *__pdata);
+extern size_t pcpu_alloc_size(void __percpu *__pdata);
 
 DEFINE_FREE(free_percpu, void __percpu *, free_percpu(_T))
 
index ea607078368df047411b79d95e8b63b80ceac23e..60ed078e4cd06ae59e90f4a29f04dc4008d51234 100644 (file)
@@ -2244,6 +2244,37 @@ static void pcpu_balance_workfn(struct work_struct *work)
        mutex_unlock(&pcpu_alloc_mutex);
 }
 
+/**
+ * pcpu_alloc_size - the size of the dynamic percpu area
+ * @ptr: pointer to the dynamic percpu area
+ *
+ * Returns the size of the @ptr allocation.  This is undefined for statically
+ * defined percpu variables as there is no corresponding chunk->bound_map.
+ *
+ * RETURNS:
+ * The size of the dynamic percpu area.
+ *
+ * CONTEXT:
+ * Can be called from atomic context.
+ */
+size_t pcpu_alloc_size(void __percpu *ptr)
+{
+       struct pcpu_chunk *chunk;
+       unsigned long bit_off, end;
+       void *addr;
+
+       if (!ptr)
+               return 0;
+
+       addr = __pcpu_ptr_to_addr(ptr);
+       /* No pcpu_lock here: ptr has not been freed, so chunk is still alive */
+       chunk = pcpu_chunk_addr_search(addr);
+       bit_off = (addr - chunk->base_addr) / PCPU_MIN_ALLOC_SIZE;
+       end = find_next_bit(chunk->bound_map, pcpu_chunk_map_bits(chunk),
+                           bit_off + 1);
+       return (end - bit_off) * PCPU_MIN_ALLOC_SIZE;
+}
+
 /**
  * free_percpu - free percpu area
  * @ptr: pointer to area to free