xfs_trans_refcount.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Copyright (C) 2016 Oracle. All Rights Reserved.
  3. *
  4. * Author: Darrick J. Wong <darrick.wong@oracle.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it would be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write the Free Software Foundation,
  18. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. #include "xfs.h"
  21. #include "xfs_fs.h"
  22. #include "xfs_shared.h"
  23. #include "xfs_format.h"
  24. #include "xfs_log_format.h"
  25. #include "xfs_trans_resv.h"
  26. #include "xfs_mount.h"
  27. #include "xfs_defer.h"
  28. #include "xfs_trans.h"
  29. #include "xfs_trans_priv.h"
  30. #include "xfs_refcount_item.h"
  31. #include "xfs_alloc.h"
  32. #include "xfs_refcount.h"
  33. /*
  34. * This routine is called to allocate a "refcount update done"
  35. * log item.
  36. */
  37. struct xfs_cud_log_item *
  38. xfs_trans_get_cud(
  39. struct xfs_trans *tp,
  40. struct xfs_cui_log_item *cuip)
  41. {
  42. struct xfs_cud_log_item *cudp;
  43. cudp = xfs_cud_init(tp->t_mountp, cuip);
  44. xfs_trans_add_item(tp, &cudp->cud_item);
  45. return cudp;
  46. }
  47. /*
  48. * Finish an refcount update and log it to the CUD. Note that the
  49. * transaction is marked dirty regardless of whether the refcount
  50. * update succeeds or fails to support the CUI/CUD lifecycle rules.
  51. */
  52. int
  53. xfs_trans_log_finish_refcount_update(
  54. struct xfs_trans *tp,
  55. struct xfs_cud_log_item *cudp,
  56. struct xfs_defer_ops *dop,
  57. enum xfs_refcount_intent_type type,
  58. xfs_fsblock_t startblock,
  59. xfs_extlen_t blockcount,
  60. xfs_fsblock_t *new_fsb,
  61. xfs_extlen_t *new_len,
  62. struct xfs_btree_cur **pcur)
  63. {
  64. int error;
  65. error = xfs_refcount_finish_one(tp, dop, type, startblock,
  66. blockcount, new_fsb, new_len, pcur);
  67. /*
  68. * Mark the transaction dirty, even on error. This ensures the
  69. * transaction is aborted, which:
  70. *
  71. * 1.) releases the CUI and frees the CUD
  72. * 2.) shuts down the filesystem
  73. */
  74. tp->t_flags |= XFS_TRANS_DIRTY;
  75. cudp->cud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
  76. return error;
  77. }
  78. /* Sort refcount intents by AG. */
  79. static int
  80. xfs_refcount_update_diff_items(
  81. void *priv,
  82. struct list_head *a,
  83. struct list_head *b)
  84. {
  85. struct xfs_mount *mp = priv;
  86. struct xfs_refcount_intent *ra;
  87. struct xfs_refcount_intent *rb;
  88. ra = container_of(a, struct xfs_refcount_intent, ri_list);
  89. rb = container_of(b, struct xfs_refcount_intent, ri_list);
  90. return XFS_FSB_TO_AGNO(mp, ra->ri_startblock) -
  91. XFS_FSB_TO_AGNO(mp, rb->ri_startblock);
  92. }
  93. /* Get an CUI. */
  94. STATIC void *
  95. xfs_refcount_update_create_intent(
  96. struct xfs_trans *tp,
  97. unsigned int count)
  98. {
  99. struct xfs_cui_log_item *cuip;
  100. ASSERT(tp != NULL);
  101. ASSERT(count > 0);
  102. cuip = xfs_cui_init(tp->t_mountp, count);
  103. ASSERT(cuip != NULL);
  104. /*
  105. * Get a log_item_desc to point at the new item.
  106. */
  107. xfs_trans_add_item(tp, &cuip->cui_item);
  108. return cuip;
  109. }
  110. /* Set the phys extent flags for this reverse mapping. */
  111. static void
  112. xfs_trans_set_refcount_flags(
  113. struct xfs_phys_extent *refc,
  114. enum xfs_refcount_intent_type type)
  115. {
  116. refc->pe_flags = 0;
  117. switch (type) {
  118. case XFS_REFCOUNT_INCREASE:
  119. case XFS_REFCOUNT_DECREASE:
  120. case XFS_REFCOUNT_ALLOC_COW:
  121. case XFS_REFCOUNT_FREE_COW:
  122. refc->pe_flags |= type;
  123. break;
  124. default:
  125. ASSERT(0);
  126. }
  127. }
  128. /* Log refcount updates in the intent item. */
  129. STATIC void
  130. xfs_refcount_update_log_item(
  131. struct xfs_trans *tp,
  132. void *intent,
  133. struct list_head *item)
  134. {
  135. struct xfs_cui_log_item *cuip = intent;
  136. struct xfs_refcount_intent *refc;
  137. uint next_extent;
  138. struct xfs_phys_extent *ext;
  139. refc = container_of(item, struct xfs_refcount_intent, ri_list);
  140. tp->t_flags |= XFS_TRANS_DIRTY;
  141. cuip->cui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
  142. /*
  143. * atomic_inc_return gives us the value after the increment;
  144. * we want to use it as an array index so we need to subtract 1 from
  145. * it.
  146. */
  147. next_extent = atomic_inc_return(&cuip->cui_next_extent) - 1;
  148. ASSERT(next_extent < cuip->cui_format.cui_nextents);
  149. ext = &cuip->cui_format.cui_extents[next_extent];
  150. ext->pe_startblock = refc->ri_startblock;
  151. ext->pe_len = refc->ri_blockcount;
  152. xfs_trans_set_refcount_flags(ext, refc->ri_type);
  153. }
  154. /* Get an CUD so we can process all the deferred refcount updates. */
  155. STATIC void *
  156. xfs_refcount_update_create_done(
  157. struct xfs_trans *tp,
  158. void *intent,
  159. unsigned int count)
  160. {
  161. return xfs_trans_get_cud(tp, intent);
  162. }
  163. /* Process a deferred refcount update. */
  164. STATIC int
  165. xfs_refcount_update_finish_item(
  166. struct xfs_trans *tp,
  167. struct xfs_defer_ops *dop,
  168. struct list_head *item,
  169. void *done_item,
  170. void **state)
  171. {
  172. struct xfs_refcount_intent *refc;
  173. xfs_fsblock_t new_fsb;
  174. xfs_extlen_t new_aglen;
  175. int error;
  176. refc = container_of(item, struct xfs_refcount_intent, ri_list);
  177. error = xfs_trans_log_finish_refcount_update(tp, done_item, dop,
  178. refc->ri_type,
  179. refc->ri_startblock,
  180. refc->ri_blockcount,
  181. &new_fsb, &new_aglen,
  182. (struct xfs_btree_cur **)state);
  183. /* Did we run out of reservation? Requeue what we didn't finish. */
  184. if (!error && new_aglen > 0) {
  185. ASSERT(refc->ri_type == XFS_REFCOUNT_INCREASE ||
  186. refc->ri_type == XFS_REFCOUNT_DECREASE);
  187. refc->ri_startblock = new_fsb;
  188. refc->ri_blockcount = new_aglen;
  189. return -EAGAIN;
  190. }
  191. kmem_free(refc);
  192. return error;
  193. }
  194. /* Clean up after processing deferred refcounts. */
  195. STATIC void
  196. xfs_refcount_update_finish_cleanup(
  197. struct xfs_trans *tp,
  198. void *state,
  199. int error)
  200. {
  201. struct xfs_btree_cur *rcur = state;
  202. xfs_refcount_finish_one_cleanup(tp, rcur, error);
  203. }
  204. /* Abort all pending CUIs. */
  205. STATIC void
  206. xfs_refcount_update_abort_intent(
  207. void *intent)
  208. {
  209. xfs_cui_release(intent);
  210. }
  211. /* Cancel a deferred refcount update. */
  212. STATIC void
  213. xfs_refcount_update_cancel_item(
  214. struct list_head *item)
  215. {
  216. struct xfs_refcount_intent *refc;
  217. refc = container_of(item, struct xfs_refcount_intent, ri_list);
  218. kmem_free(refc);
  219. }
  220. static const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
  221. .type = XFS_DEFER_OPS_TYPE_REFCOUNT,
  222. .max_items = XFS_CUI_MAX_FAST_EXTENTS,
  223. .diff_items = xfs_refcount_update_diff_items,
  224. .create_intent = xfs_refcount_update_create_intent,
  225. .abort_intent = xfs_refcount_update_abort_intent,
  226. .log_item = xfs_refcount_update_log_item,
  227. .create_done = xfs_refcount_update_create_done,
  228. .finish_item = xfs_refcount_update_finish_item,
  229. .finish_cleanup = xfs_refcount_update_finish_cleanup,
  230. .cancel_item = xfs_refcount_update_cancel_item,
  231. };
  232. /* Register the deferred op type. */
  233. void
  234. xfs_refcount_update_init_defer_op(void)
  235. {
  236. xfs_defer_init_op_type(&xfs_refcount_update_defer_type);
  237. }