dbitmap.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright 2024 Google LLC
  4. *
  5. * dbitmap - dynamically sized bitmap library.
  6. *
  7. * Used by the binder driver to optimize the allocation of the smallest
  8. * available descriptor ID. Each bit in the bitmap represents the state
  9. * of an ID.
  10. *
  11. * A dbitmap can grow or shrink as needed. This part has been designed
  12. * considering that users might need to briefly release their locks in
  13. * order to allocate memory for the new bitmap. These operations then,
  14. * are verified to determine if the grow or shrink is sill valid.
  15. *
  16. * This library does not provide protection against concurrent access
  17. * by itself. Binder uses the proc->outer_lock for this purpose.
  18. */
  19. #ifndef _LINUX_DBITMAP_H
  20. #define _LINUX_DBITMAP_H
  21. #include <linux/bitmap.h>
  22. #define NBITS_MIN BITS_PER_TYPE(unsigned long)
  23. struct dbitmap {
  24. unsigned int nbits;
  25. unsigned long *map;
  26. };
  27. static inline int dbitmap_enabled(struct dbitmap *dmap)
  28. {
  29. return !!dmap->nbits;
  30. }
  31. static inline void dbitmap_free(struct dbitmap *dmap)
  32. {
  33. dmap->nbits = 0;
  34. kfree(dmap->map);
  35. dmap->map = NULL;
  36. }
  37. /* Returns the nbits that a dbitmap can shrink to, 0 if not possible. */
  38. static inline unsigned int dbitmap_shrink_nbits(struct dbitmap *dmap)
  39. {
  40. unsigned int bit;
  41. if (dmap->nbits <= NBITS_MIN)
  42. return 0;
  43. /*
  44. * Determine if the bitmap can shrink based on the position of
  45. * its last set bit. If the bit is within the first quarter of
  46. * the bitmap then shrinking is possible. In this case, the
  47. * bitmap should shrink to half its current size.
  48. */
  49. bit = find_last_bit(dmap->map, dmap->nbits);
  50. if (bit < (dmap->nbits >> 2))
  51. return dmap->nbits >> 1;
  52. /* find_last_bit() returns dmap->nbits when no bits are set. */
  53. if (bit == dmap->nbits)
  54. return NBITS_MIN;
  55. return 0;
  56. }
  57. /* Replace the internal bitmap with a new one of different size */
  58. static inline void
  59. dbitmap_replace(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
  60. {
  61. bitmap_copy(new, dmap->map, min(dmap->nbits, nbits));
  62. kfree(dmap->map);
  63. dmap->map = new;
  64. dmap->nbits = nbits;
  65. }
  66. static inline void
  67. dbitmap_shrink(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
  68. {
  69. if (!new)
  70. return;
  71. /*
  72. * Verify that shrinking to @nbits is still possible. The @new
  73. * bitmap might have been allocated without locks, so this call
  74. * could now be outdated. In this case, free @new and move on.
  75. */
  76. if (!dbitmap_enabled(dmap) || dbitmap_shrink_nbits(dmap) != nbits) {
  77. kfree(new);
  78. return;
  79. }
  80. dbitmap_replace(dmap, new, nbits);
  81. }
  82. /* Returns the nbits that a dbitmap can grow to. */
  83. static inline unsigned int dbitmap_grow_nbits(struct dbitmap *dmap)
  84. {
  85. return dmap->nbits << 1;
  86. }
  87. static inline void
  88. dbitmap_grow(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
  89. {
  90. /*
  91. * Verify that growing to @nbits is still possible. The @new
  92. * bitmap might have been allocated without locks, so this call
  93. * could now be outdated. In this case, free @new and move on.
  94. */
  95. if (!dbitmap_enabled(dmap) || nbits <= dmap->nbits) {
  96. kfree(new);
  97. return;
  98. }
  99. /*
  100. * Check for ENOMEM after confirming the grow operation is still
  101. * required. This ensures we only disable the dbitmap when it's
  102. * necessary. Once the dbitmap is disabled, binder will fallback
  103. * to slow_desc_lookup_olocked().
  104. */
  105. if (!new) {
  106. dbitmap_free(dmap);
  107. return;
  108. }
  109. dbitmap_replace(dmap, new, nbits);
  110. }
  111. /*
  112. * Finds and sets the next zero bit in the bitmap. Upon success @bit
  113. * is populated with the index and 0 is returned. Otherwise, -ENOSPC
  114. * is returned to indicate that a dbitmap_grow() is needed.
  115. */
  116. static inline int
  117. dbitmap_acquire_next_zero_bit(struct dbitmap *dmap, unsigned long offset,
  118. unsigned long *bit)
  119. {
  120. unsigned long n;
  121. n = find_next_zero_bit(dmap->map, dmap->nbits, offset);
  122. if (n == dmap->nbits)
  123. return -ENOSPC;
  124. *bit = n;
  125. set_bit(n, dmap->map);
  126. return 0;
  127. }
  128. static inline void
  129. dbitmap_clear_bit(struct dbitmap *dmap, unsigned long bit)
  130. {
  131. clear_bit(bit, dmap->map);
  132. }
  133. static inline int dbitmap_init(struct dbitmap *dmap)
  134. {
  135. dmap->map = bitmap_zalloc(NBITS_MIN, GFP_KERNEL);
  136. if (!dmap->map) {
  137. dmap->nbits = 0;
  138. return -ENOMEM;
  139. }
  140. dmap->nbits = NBITS_MIN;
  141. return 0;
  142. }
  143. #endif