xfs_trans_extfree.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (c) 2000,2005 Silicon Graphics, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it would be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write the Free Software Foundation,
  16. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "xfs.h"
  19. #include "xfs_fs.h"
  20. #include "xfs_shared.h"
  21. #include "xfs_format.h"
  22. #include "xfs_log_format.h"
  23. #include "xfs_trans_resv.h"
  24. #include "xfs_bit.h"
  25. #include "xfs_mount.h"
  26. #include "xfs_defer.h"
  27. #include "xfs_trans.h"
  28. #include "xfs_trans_priv.h"
  29. #include "xfs_extfree_item.h"
  30. #include "xfs_alloc.h"
  31. #include "xfs_bmap.h"
  32. #include "xfs_trace.h"
  33. /*
  34. * This routine is called to allocate an "extent free done"
  35. * log item that will hold nextents worth of extents. The
  36. * caller must use all nextents extents, because we are not
  37. * flexible about this at all.
  38. */
  39. struct xfs_efd_log_item *
  40. xfs_trans_get_efd(struct xfs_trans *tp,
  41. struct xfs_efi_log_item *efip,
  42. uint nextents)
  43. {
  44. struct xfs_efd_log_item *efdp;
  45. ASSERT(tp != NULL);
  46. ASSERT(nextents > 0);
  47. efdp = xfs_efd_init(tp->t_mountp, efip, nextents);
  48. ASSERT(efdp != NULL);
  49. /*
  50. * Get a log_item_desc to point at the new item.
  51. */
  52. xfs_trans_add_item(tp, &efdp->efd_item);
  53. return efdp;
  54. }
  55. /*
  56. * Free an extent and log it to the EFD. Note that the transaction is marked
  57. * dirty regardless of whether the extent free succeeds or fails to support the
  58. * EFI/EFD lifecycle rules.
  59. */
  60. int
  61. xfs_trans_free_extent(
  62. struct xfs_trans *tp,
  63. struct xfs_efd_log_item *efdp,
  64. xfs_fsblock_t start_block,
  65. xfs_extlen_t ext_len,
  66. struct xfs_owner_info *oinfo)
  67. {
  68. struct xfs_mount *mp = tp->t_mountp;
  69. uint next_extent;
  70. xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, start_block);
  71. xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, start_block);
  72. struct xfs_extent *extp;
  73. int error;
  74. trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno, ext_len);
  75. error = xfs_free_extent(tp, start_block, ext_len, oinfo,
  76. XFS_AG_RESV_NONE);
  77. /*
  78. * Mark the transaction dirty, even on error. This ensures the
  79. * transaction is aborted, which:
  80. *
  81. * 1.) releases the EFI and frees the EFD
  82. * 2.) shuts down the filesystem
  83. */
  84. tp->t_flags |= XFS_TRANS_DIRTY;
  85. efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY;
  86. next_extent = efdp->efd_next_extent;
  87. ASSERT(next_extent < efdp->efd_format.efd_nextents);
  88. extp = &(efdp->efd_format.efd_extents[next_extent]);
  89. extp->ext_start = start_block;
  90. extp->ext_len = ext_len;
  91. efdp->efd_next_extent++;
  92. return error;
  93. }
  94. /* Sort bmap items by AG. */
  95. static int
  96. xfs_extent_free_diff_items(
  97. void *priv,
  98. struct list_head *a,
  99. struct list_head *b)
  100. {
  101. struct xfs_mount *mp = priv;
  102. struct xfs_extent_free_item *ra;
  103. struct xfs_extent_free_item *rb;
  104. ra = container_of(a, struct xfs_extent_free_item, xefi_list);
  105. rb = container_of(b, struct xfs_extent_free_item, xefi_list);
  106. return XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) -
  107. XFS_FSB_TO_AGNO(mp, rb->xefi_startblock);
  108. }
  109. /* Get an EFI. */
  110. STATIC void *
  111. xfs_extent_free_create_intent(
  112. struct xfs_trans *tp,
  113. unsigned int count)
  114. {
  115. struct xfs_efi_log_item *efip;
  116. ASSERT(tp != NULL);
  117. ASSERT(count > 0);
  118. efip = xfs_efi_init(tp->t_mountp, count);
  119. ASSERT(efip != NULL);
  120. /*
  121. * Get a log_item_desc to point at the new item.
  122. */
  123. xfs_trans_add_item(tp, &efip->efi_item);
  124. return efip;
  125. }
  126. /* Log a free extent to the intent item. */
  127. STATIC void
  128. xfs_extent_free_log_item(
  129. struct xfs_trans *tp,
  130. void *intent,
  131. struct list_head *item)
  132. {
  133. struct xfs_efi_log_item *efip = intent;
  134. struct xfs_extent_free_item *free;
  135. uint next_extent;
  136. struct xfs_extent *extp;
  137. free = container_of(item, struct xfs_extent_free_item, xefi_list);
  138. tp->t_flags |= XFS_TRANS_DIRTY;
  139. efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
  140. /*
  141. * atomic_inc_return gives us the value after the increment;
  142. * we want to use it as an array index so we need to subtract 1 from
  143. * it.
  144. */
  145. next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
  146. ASSERT(next_extent < efip->efi_format.efi_nextents);
  147. extp = &efip->efi_format.efi_extents[next_extent];
  148. extp->ext_start = free->xefi_startblock;
  149. extp->ext_len = free->xefi_blockcount;
  150. }
  151. /* Get an EFD so we can process all the free extents. */
  152. STATIC void *
  153. xfs_extent_free_create_done(
  154. struct xfs_trans *tp,
  155. void *intent,
  156. unsigned int count)
  157. {
  158. return xfs_trans_get_efd(tp, intent, count);
  159. }
  160. /* Process a free extent. */
  161. STATIC int
  162. xfs_extent_free_finish_item(
  163. struct xfs_trans *tp,
  164. struct xfs_defer_ops *dop,
  165. struct list_head *item,
  166. void *done_item,
  167. void **state)
  168. {
  169. struct xfs_extent_free_item *free;
  170. int error;
  171. free = container_of(item, struct xfs_extent_free_item, xefi_list);
  172. error = xfs_trans_free_extent(tp, done_item,
  173. free->xefi_startblock,
  174. free->xefi_blockcount,
  175. &free->xefi_oinfo);
  176. kmem_free(free);
  177. return error;
  178. }
  179. /* Abort all pending EFIs. */
  180. STATIC void
  181. xfs_extent_free_abort_intent(
  182. void *intent)
  183. {
  184. xfs_efi_release(intent);
  185. }
  186. /* Cancel a free extent. */
  187. STATIC void
  188. xfs_extent_free_cancel_item(
  189. struct list_head *item)
  190. {
  191. struct xfs_extent_free_item *free;
  192. free = container_of(item, struct xfs_extent_free_item, xefi_list);
  193. kmem_free(free);
  194. }
  195. static const struct xfs_defer_op_type xfs_extent_free_defer_type = {
  196. .type = XFS_DEFER_OPS_TYPE_FREE,
  197. .max_items = XFS_EFI_MAX_FAST_EXTENTS,
  198. .diff_items = xfs_extent_free_diff_items,
  199. .create_intent = xfs_extent_free_create_intent,
  200. .abort_intent = xfs_extent_free_abort_intent,
  201. .log_item = xfs_extent_free_log_item,
  202. .create_done = xfs_extent_free_create_done,
  203. .finish_item = xfs_extent_free_finish_item,
  204. .cancel_item = xfs_extent_free_cancel_item,
  205. };
  206. /* Register the deferred op type. */
  207. void
  208. xfs_extent_free_init_defer_op(void)
  209. {
  210. xfs_defer_init_op_type(&xfs_extent_free_defer_type);
  211. }