striper.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #include <linux/ceph/ceph_debug.h>
  3. #include <linux/math64.h>
  4. #include <linux/slab.h>
  5. #include <linux/ceph/striper.h>
  6. #include <linux/ceph/types.h>
  7. /*
  8. * Map a file extent to a stripe unit within an object.
  9. * Fill in objno, offset into object, and object extent length (i.e. the
  10. * number of bytes mapped, less than or equal to @l->stripe_unit).
  11. *
  12. * Example for stripe_count = 3, stripes_per_object = 4:
  13. *
  14. * blockno | 0 3 6 9 | 1 4 7 10 | 2 5 8 11 | 12 15 18 21 | 13 16 19
  15. * stripeno | 0 1 2 3 | 0 1 2 3 | 0 1 2 3 | 4 5 6 7 | 4 5 6
  16. * stripepos | 0 | 1 | 2 | 0 | 1
  17. * objno | 0 | 1 | 2 | 3 | 4
  18. * objsetno | 0 | 1
  19. */
  20. void ceph_calc_file_object_mapping(struct ceph_file_layout *l,
  21. u64 off, u64 len,
  22. u64 *objno, u64 *objoff, u32 *xlen)
  23. {
  24. u32 stripes_per_object = l->object_size / l->stripe_unit;
  25. u64 blockno; /* which su in the file (i.e. globally) */
  26. u32 blockoff; /* offset into su */
  27. u64 stripeno; /* which stripe */
  28. u32 stripepos; /* which su in the stripe,
  29. which object in the object set */
  30. u64 objsetno; /* which object set */
  31. u32 objsetpos; /* which stripe in the object set */
  32. blockno = div_u64_rem(off, l->stripe_unit, &blockoff);
  33. stripeno = div_u64_rem(blockno, l->stripe_count, &stripepos);
  34. objsetno = div_u64_rem(stripeno, stripes_per_object, &objsetpos);
  35. *objno = objsetno * l->stripe_count + stripepos;
  36. *objoff = objsetpos * l->stripe_unit + blockoff;
  37. *xlen = min_t(u64, len, l->stripe_unit - blockoff);
  38. }
  39. EXPORT_SYMBOL(ceph_calc_file_object_mapping);
  40. /*
  41. * Return the last extent with given objno (@object_extents is sorted
  42. * by objno). If not found, return NULL and set @add_pos so that the
  43. * new extent can be added with list_add(add_pos, new_ex).
  44. */
  45. static struct ceph_object_extent *
  46. lookup_last(struct list_head *object_extents, u64 objno,
  47. struct list_head **add_pos)
  48. {
  49. struct list_head *pos;
  50. list_for_each_prev(pos, object_extents) {
  51. struct ceph_object_extent *ex =
  52. list_entry(pos, typeof(*ex), oe_item);
  53. if (ex->oe_objno == objno)
  54. return ex;
  55. if (ex->oe_objno < objno)
  56. break;
  57. }
  58. *add_pos = pos;
  59. return NULL;
  60. }
  61. static struct ceph_object_extent *
  62. lookup_containing(struct list_head *object_extents, u64 objno,
  63. u64 objoff, u32 xlen)
  64. {
  65. struct ceph_object_extent *ex;
  66. list_for_each_entry(ex, object_extents, oe_item) {
  67. if (ex->oe_objno == objno &&
  68. ex->oe_off <= objoff &&
  69. ex->oe_off + ex->oe_len >= objoff + xlen) /* paranoia */
  70. return ex;
  71. if (ex->oe_objno > objno)
  72. break;
  73. }
  74. return NULL;
  75. }
  76. /*
  77. * Map a file extent to a sorted list of object extents.
  78. *
  79. * We want only one (or as few as possible) object extents per object.
  80. * Adjacent object extents will be merged together, each returned object
  81. * extent may reverse map to multiple different file extents.
  82. *
  83. * Call @alloc_fn for each new object extent and @action_fn for each
  84. * mapped stripe unit, whether it was merged into an already allocated
  85. * object extent or started a new object extent.
  86. *
  87. * Newly allocated object extents are added to @object_extents.
  88. * To keep @object_extents sorted, successive calls to this function
  89. * must map successive file extents (i.e. the list of file extents that
  90. * are mapped using the same @object_extents must be sorted).
  91. *
  92. * The caller is responsible for @object_extents.
  93. */
  94. int ceph_file_to_extents(struct ceph_file_layout *l, u64 off, u64 len,
  95. struct list_head *object_extents,
  96. struct ceph_object_extent *alloc_fn(void *arg),
  97. void *alloc_arg,
  98. ceph_object_extent_fn_t action_fn,
  99. void *action_arg)
  100. {
  101. struct ceph_object_extent *last_ex, *ex;
  102. while (len) {
  103. struct list_head *add_pos = NULL;
  104. u64 objno, objoff;
  105. u32 xlen;
  106. ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
  107. &xlen);
  108. last_ex = lookup_last(object_extents, objno, &add_pos);
  109. if (!last_ex || last_ex->oe_off + last_ex->oe_len != objoff) {
  110. ex = alloc_fn(alloc_arg);
  111. if (!ex)
  112. return -ENOMEM;
  113. ex->oe_objno = objno;
  114. ex->oe_off = objoff;
  115. ex->oe_len = xlen;
  116. if (action_fn)
  117. action_fn(ex, xlen, action_arg);
  118. if (!last_ex)
  119. list_add(&ex->oe_item, add_pos);
  120. else
  121. list_add(&ex->oe_item, &last_ex->oe_item);
  122. } else {
  123. last_ex->oe_len += xlen;
  124. if (action_fn)
  125. action_fn(last_ex, xlen, action_arg);
  126. }
  127. off += xlen;
  128. len -= xlen;
  129. }
  130. for (last_ex = list_first_entry(object_extents, typeof(*ex), oe_item),
  131. ex = list_next_entry(last_ex, oe_item);
  132. &ex->oe_item != object_extents;
  133. last_ex = ex, ex = list_next_entry(ex, oe_item)) {
  134. if (last_ex->oe_objno > ex->oe_objno ||
  135. (last_ex->oe_objno == ex->oe_objno &&
  136. last_ex->oe_off + last_ex->oe_len >= ex->oe_off)) {
  137. WARN(1, "%s: object_extents list not sorted!\n",
  138. __func__);
  139. return -EINVAL;
  140. }
  141. }
  142. return 0;
  143. }
  144. EXPORT_SYMBOL(ceph_file_to_extents);
  145. /*
  146. * A stripped down, non-allocating version of ceph_file_to_extents(),
  147. * for when @object_extents is already populated.
  148. */
  149. int ceph_iterate_extents(struct ceph_file_layout *l, u64 off, u64 len,
  150. struct list_head *object_extents,
  151. ceph_object_extent_fn_t action_fn,
  152. void *action_arg)
  153. {
  154. while (len) {
  155. struct ceph_object_extent *ex;
  156. u64 objno, objoff;
  157. u32 xlen;
  158. ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
  159. &xlen);
  160. ex = lookup_containing(object_extents, objno, objoff, xlen);
  161. if (!ex) {
  162. WARN(1, "%s: objno %llu %llu~%u not found!\n",
  163. __func__, objno, objoff, xlen);
  164. return -EINVAL;
  165. }
  166. action_fn(ex, xlen, action_arg);
  167. off += xlen;
  168. len -= xlen;
  169. }
  170. return 0;
  171. }
  172. EXPORT_SYMBOL(ceph_iterate_extents);
  173. /*
  174. * Reverse map an object extent to a sorted list of file extents.
  175. *
  176. * On success, the caller is responsible for:
  177. *
  178. * kfree(file_extents)
  179. */
  180. int ceph_extent_to_file(struct ceph_file_layout *l,
  181. u64 objno, u64 objoff, u64 objlen,
  182. struct ceph_file_extent **file_extents,
  183. u32 *num_file_extents)
  184. {
  185. u32 stripes_per_object = l->object_size / l->stripe_unit;
  186. u64 blockno; /* which su */
  187. u32 blockoff; /* offset into su */
  188. u64 stripeno; /* which stripe */
  189. u32 stripepos; /* which su in the stripe,
  190. which object in the object set */
  191. u64 objsetno; /* which object set */
  192. u32 i = 0;
  193. if (!objlen) {
  194. *file_extents = NULL;
  195. *num_file_extents = 0;
  196. return 0;
  197. }
  198. *num_file_extents = DIV_ROUND_UP_ULL(objoff + objlen, l->stripe_unit) -
  199. DIV_ROUND_DOWN_ULL(objoff, l->stripe_unit);
  200. *file_extents = kmalloc_array(*num_file_extents, sizeof(**file_extents),
  201. GFP_NOIO);
  202. if (!*file_extents)
  203. return -ENOMEM;
  204. div_u64_rem(objoff, l->stripe_unit, &blockoff);
  205. while (objlen) {
  206. u64 off, len;
  207. objsetno = div_u64_rem(objno, l->stripe_count, &stripepos);
  208. stripeno = div_u64(objoff, l->stripe_unit) +
  209. objsetno * stripes_per_object;
  210. blockno = stripeno * l->stripe_count + stripepos;
  211. off = blockno * l->stripe_unit + blockoff;
  212. len = min_t(u64, objlen, l->stripe_unit - blockoff);
  213. (*file_extents)[i].fe_off = off;
  214. (*file_extents)[i].fe_len = len;
  215. blockoff = 0;
  216. objoff += len;
  217. objlen -= len;
  218. i++;
  219. }
  220. BUG_ON(i != *num_file_extents);
  221. return 0;
  222. }
  223. EXPORT_SYMBOL(ceph_extent_to_file);