objpool.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/objpool.h>
  3. #include <linux/slab.h>
  4. #include <linux/vmalloc.h>
  5. #include <linux/atomic.h>
  6. #include <linux/irqflags.h>
  7. #include <linux/cpumask.h>
  8. #include <linux/log2.h>
  9. /*
  10. * objpool: ring-array based lockless MPMC/FIFO queues
  11. *
  12. * Copyright: wuqiang.matt@bytedance.com,mhiramat@kernel.org
  13. */
  14. /* initialize percpu objpool_slot */
  15. static int
  16. objpool_init_percpu_slot(struct objpool_head *pool,
  17. struct objpool_slot *slot,
  18. int nodes, void *context,
  19. objpool_init_obj_cb objinit)
  20. {
  21. void *obj = (void *)&slot->entries[pool->capacity];
  22. int i;
  23. /* initialize elements of percpu objpool_slot */
  24. slot->mask = pool->capacity - 1;
  25. for (i = 0; i < nodes; i++) {
  26. if (objinit) {
  27. int rc = objinit(obj, context);
  28. if (rc)
  29. return rc;
  30. }
  31. slot->entries[slot->tail & slot->mask] = obj;
  32. obj = obj + pool->obj_size;
  33. slot->tail++;
  34. slot->last = slot->tail;
  35. pool->nr_objs++;
  36. }
  37. return 0;
  38. }
  39. /* allocate and initialize percpu slots */
  40. static int
  41. objpool_init_percpu_slots(struct objpool_head *pool, int nr_objs,
  42. void *context, objpool_init_obj_cb objinit)
  43. {
  44. int i, cpu_count = 0;
  45. for (i = 0; i < nr_cpu_ids; i++) {
  46. struct objpool_slot *slot;
  47. int nodes, size, rc;
  48. /* skip the cpu node which could never be present */
  49. if (!cpu_possible(i))
  50. continue;
  51. /* compute how many objects to be allocated with this slot */
  52. nodes = nr_objs / pool->nr_possible_cpus;
  53. if (cpu_count < (nr_objs % pool->nr_possible_cpus))
  54. nodes++;
  55. cpu_count++;
  56. size = struct_size(slot, entries, pool->capacity) +
  57. pool->obj_size * nodes;
  58. /*
  59. * here we allocate percpu-slot & objs together in a single
  60. * allocation to make it more compact, taking advantage of
  61. * warm caches and TLB hits. in default vmalloc is used to
  62. * reduce the pressure of kernel slab system. as we know,
  63. * mimimal size of vmalloc is one page since vmalloc would
  64. * always align the requested size to page size.
  65. * but if vmalloc fails or it is not available (e.g. GFP_ATOMIC)
  66. * allocate percpu slot with kmalloc.
  67. */
  68. slot = NULL;
  69. if ((pool->gfp & (GFP_ATOMIC | GFP_KERNEL)) != GFP_ATOMIC)
  70. slot = __vmalloc_node(size, sizeof(void *), pool->gfp,
  71. cpu_to_node(i), __builtin_return_address(0));
  72. if (!slot) {
  73. slot = kmalloc_node(size, pool->gfp, cpu_to_node(i));
  74. if (!slot)
  75. return -ENOMEM;
  76. }
  77. memset(slot, 0, size);
  78. pool->cpu_slots[i] = slot;
  79. /* initialize the objpool_slot of cpu node i */
  80. rc = objpool_init_percpu_slot(pool, slot, nodes, context, objinit);
  81. if (rc)
  82. return rc;
  83. }
  84. return 0;
  85. }
  86. /* cleanup all percpu slots of the object pool */
  87. static void objpool_fini_percpu_slots(struct objpool_head *pool)
  88. {
  89. int i;
  90. if (!pool->cpu_slots)
  91. return;
  92. for (i = 0; i < nr_cpu_ids; i++)
  93. kvfree(pool->cpu_slots[i]);
  94. kfree(pool->cpu_slots);
  95. }
  96. /* initialize object pool and pre-allocate objects */
  97. int objpool_init(struct objpool_head *pool, int nr_objs, int object_size,
  98. gfp_t gfp, void *context, objpool_init_obj_cb objinit,
  99. objpool_fini_cb release)
  100. {
  101. int rc, capacity, slot_size;
  102. /* check input parameters */
  103. if (nr_objs <= 0 || nr_objs > OBJPOOL_NR_OBJECT_MAX ||
  104. object_size <= 0 || object_size > OBJPOOL_OBJECT_SIZE_MAX)
  105. return -EINVAL;
  106. /* align up to unsigned long size */
  107. object_size = ALIGN(object_size, sizeof(long));
  108. /* calculate capacity of percpu objpool_slot */
  109. capacity = roundup_pow_of_two(nr_objs);
  110. if (!capacity)
  111. return -EINVAL;
  112. /* initialize objpool pool */
  113. memset(pool, 0, sizeof(struct objpool_head));
  114. pool->nr_possible_cpus = num_possible_cpus();
  115. pool->obj_size = object_size;
  116. pool->capacity = capacity;
  117. pool->gfp = gfp & ~__GFP_ZERO;
  118. pool->context = context;
  119. pool->release = release;
  120. slot_size = nr_cpu_ids * sizeof(struct objpool_slot *);
  121. pool->cpu_slots = kzalloc(slot_size, pool->gfp);
  122. if (!pool->cpu_slots)
  123. return -ENOMEM;
  124. /* initialize per-cpu slots */
  125. rc = objpool_init_percpu_slots(pool, nr_objs, context, objinit);
  126. if (rc)
  127. objpool_fini_percpu_slots(pool);
  128. else
  129. refcount_set(&pool->ref, pool->nr_objs + 1);
  130. return rc;
  131. }
  132. EXPORT_SYMBOL_GPL(objpool_init);
  133. /* release whole objpool forcely */
  134. void objpool_free(struct objpool_head *pool)
  135. {
  136. if (!pool->cpu_slots)
  137. return;
  138. /* release percpu slots */
  139. objpool_fini_percpu_slots(pool);
  140. /* call user's cleanup callback if provided */
  141. if (pool->release)
  142. pool->release(pool, pool->context);
  143. }
  144. EXPORT_SYMBOL_GPL(objpool_free);
  145. /* drop the allocated object, rather reclaim it to objpool */
  146. int objpool_drop(void *obj, struct objpool_head *pool)
  147. {
  148. if (!obj || !pool)
  149. return -EINVAL;
  150. if (refcount_dec_and_test(&pool->ref)) {
  151. objpool_free(pool);
  152. return 0;
  153. }
  154. return -EAGAIN;
  155. }
  156. EXPORT_SYMBOL_GPL(objpool_drop);
  157. /* drop unused objects and defref objpool for releasing */
  158. void objpool_fini(struct objpool_head *pool)
  159. {
  160. int count = 1; /* extra ref for objpool itself */
  161. /* drop all remained objects from objpool */
  162. while (objpool_pop(pool))
  163. count++;
  164. if (refcount_sub_and_test(count, &pool->ref))
  165. objpool_free(pool);
  166. }
  167. EXPORT_SYMBOL_GPL(objpool_fini);