trace_xfs_extent_free_defer(mp, xefi);
- if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
+ if (xfs_efi_is_realtime(xefi))
+ optype = XFS_DEFER_OPS_TYPE_FREE_RT;
+ else if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
optype = XFS_DEFER_OPS_TYPE_AGFL_FREE;
else
optype = XFS_DEFER_OPS_TYPE_FREE;
- xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
+ if (xfs_efi_is_realtime(xefi)) {
+ xfs_rgnumber_t rgno;
+
+ rgno = xfs_rtb_to_rgno(mp, xefi->xefi_startblock);
+ xefi->xefi_rtg = xfs_rtgroup_get(mp, rgno);
+ } else {
+ xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
+ }
*dfpp = xfs_defer_add(tp, optype, &xefi->xefi_list);
}
.cancel_item = xfs_extent_free_cancel_item,
};
+/* Sort bmap items by rtgroup. */
+static int
+xfs_rtextent_free_diff_items(
+ void *priv,
+ const struct list_head *a,
+ const struct list_head *b)
+{
+ struct xfs_extent_free_item *ra = xefi_entry(a);
+ struct xfs_extent_free_item *rb = xefi_entry(b);
+
+ return ra->xefi_rtg->rtg_rgno - rb->xefi_rtg->rtg_rgno;
+}
+
+static struct xfs_log_item *
+xfs_rtextent_free_create_intent(
+ struct xfs_trans *tp,
+ struct list_head *items,
+ unsigned int count,
+ bool sort)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+
+ if (sort)
+ list_sort(mp, items, xfs_rtextent_free_diff_items);
+ return NULL;
+}
+
+/* Cancel a free extent. */
+STATIC void
+xfs_rtextent_free_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
+
+ xfs_rtgroup_put(xefi->xefi_rtg);
+ kmem_cache_free(xfs_extfree_item_cache, xefi);
+}
+
+STATIC int
+xfs_rtextent_free_finish_item(
+ struct xfs_trans *tp,
+ struct xfs_log_item *done,
+ struct list_head *item,
+ struct xfs_btree_cur **state)
+{
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
+ int error;
+
+ error = xfs_rtfree_blocks(tp, xefi->xefi_startblock,
+ xefi->xefi_blockcount);
+ if (error != -EAGAIN)
+ xfs_rtextent_free_cancel_item(item);
+ return error;
+}
+
+const struct xfs_defer_op_type xfs_rtextent_free_defer_type = {
+ .create_intent = xfs_rtextent_free_create_intent,
+ .abort_intent = xfs_extent_free_abort_intent,
+ .create_done = xfs_extent_free_create_done,
+ .finish_item = xfs_rtextent_free_finish_item,
+ .cancel_item = xfs_rtextent_free_cancel_item,
+};
+
/*
* AGFL blocks are accounted differently in the reserve pools and are not
* inserted into the busy extent list.
ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
ASSERT(!isnullstartblock(bno));
ASSERT(!(free_flags & ~XFS_FREE_EXTENT_ALL_FLAGS));
- ASSERT(type != XFS_AG_RESV_AGFL);
- if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
- return -EFSCORRUPTED;
+ if (free_flags & XFS_FREE_EXTENT_REALTIME) {
+ if (type != XFS_AG_RESV_NONE) {
+ ASSERT(type == XFS_AG_RESV_NONE);
+ return -EFSCORRUPTED;
+ }
+ if (XFS_IS_CORRUPT(mp, !xfs_verify_rtbext(mp, bno, len)))
+ return -EFSCORRUPTED;
+ } else {
+ if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
+ return -EFSCORRUPTED;
+ }
xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
GFP_KERNEL | __GFP_NOFAIL);
xefi->xefi_agresv = type;
if (free_flags & XFS_FREE_EXTENT_SKIP_DISCARD)
xefi->xefi_flags |= XFS_EFI_SKIP_DISCARD;
+ if (free_flags & XFS_FREE_EXTENT_REALTIME)
+ xefi->xefi_flags |= XFS_EFI_REALTIME;
if (oinfo) {
ASSERT(oinfo->oi_offset == 0);
/* Don't issue a discard for the blocks freed. */
#define XFS_FREE_EXTENT_SKIP_DISCARD (1U << 0)
-#define XFS_FREE_EXTENT_ALL_FLAGS (XFS_FREE_EXTENT_SKIP_DISCARD)
+/* Free blocks on the realtime device. */
+#define XFS_FREE_EXTENT_REALTIME (1U << 1)
+
+#define XFS_FREE_EXTENT_ALL_FLAGS (XFS_FREE_EXTENT_SKIP_DISCARD | \
+ XFS_FREE_EXTENT_REALTIME)
/*
* List of extents to be free "later".
uint64_t xefi_owner;
xfs_fsblock_t xefi_startblock;/* starting fs block number */
xfs_extlen_t xefi_blockcount;/* number of blocks in extent */
- struct xfs_perag *xefi_pag;
+ union {
+ struct xfs_perag *xefi_pag;
+ struct xfs_rtgroup *xefi_rtg;
+ };
unsigned int xefi_flags;
enum xfs_ag_resv_type xefi_agresv;
};
#define XFS_EFI_ATTR_FORK (1U << 1) /* freeing attr fork block */
#define XFS_EFI_BMBT_BLOCK (1U << 2) /* freeing bmap btree block */
#define XFS_EFI_CANCELLED (1U << 3) /* dont actually free the space */
+#define XFS_EFI_REALTIME (1U << 4) /* freeing realtime extent */
+
+static inline bool xfs_efi_is_realtime(const struct xfs_extent_free_item *xefi)
+{
+ return xefi->xefi_flags & XFS_EFI_REALTIME;
+}
struct xfs_alloc_autoreap {
struct xfs_defer_pending *dfp;
.cancel_item = xfs_defer_barrier_cancel_item,
};
-static const struct xfs_defer_op_type *defer_op_types[] = {
+static const struct xfs_defer_op_type *defer_op_types[XFS_DEFER_OPS_TYPE_MAX] = {
[XFS_DEFER_OPS_TYPE_BMAP] = &xfs_bmap_update_defer_type,
[XFS_DEFER_OPS_TYPE_REFCOUNT] = &xfs_refcount_update_defer_type,
[XFS_DEFER_OPS_TYPE_RMAP] = &xfs_rmap_update_defer_type,
[XFS_DEFER_OPS_TYPE_ATTR] = &xfs_attr_defer_type,
[XFS_DEFER_OPS_TYPE_BARRIER] = &xfs_barrier_defer_type,
[XFS_DEFER_OPS_TYPE_SWAPEXT] = &xfs_swapext_defer_type,
+#ifdef CONFIG_XFS_RT
+ [XFS_DEFER_OPS_TYPE_FREE_RT] = &xfs_rtextent_free_defer_type,
+#endif
};
/*
if (dfp->dfp_intent)
return 1;
+ if (!ops) {
+ ASSERT(ops != NULL);
+ return -EFSCORRUPTED;
+ }
+
lip = ops->create_intent(tp, &dfp->dfp_work, dfp->dfp_count, sort);
if (!lip)
return 0;
XFS_DEFER_OPS_TYPE_ATTR,
XFS_DEFER_OPS_TYPE_BARRIER,
XFS_DEFER_OPS_TYPE_SWAPEXT,
+ XFS_DEFER_OPS_TYPE_FREE_RT,
XFS_DEFER_OPS_TYPE_MAX,
};
extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
+extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
extern const struct xfs_defer_op_type xfs_attr_defer_type;
extern const struct xfs_defer_op_type xfs_swapext_defer_type;
#define XFS_LI_ATTRD 0x1247 /* attr set/remove done */
#define XFS_LI_SXI 0x1248 /* extent swap intent */
#define XFS_LI_SXD 0x1249 /* extent swap done */
+#define XFS_LI_EFI_RT 0x124a /* realtime extent free intent */
+#define XFS_LI_EFD_RT 0x124b /* realtime extent free done */
#define XFS_LI_TYPE_DESC \
{ XFS_LI_EFI, "XFS_LI_EFI" }, \
{ XFS_LI_ATTRI, "XFS_LI_ATTRI" }, \
{ XFS_LI_ATTRD, "XFS_LI_ATTRD" }, \
{ XFS_LI_SXI, "XFS_LI_SXI" }, \
- { XFS_LI_SXD, "XFS_LI_SXD" }
+ { XFS_LI_SXD, "XFS_LI_SXD" }, \
+ { XFS_LI_EFI_RT, "XFS_LI_EFI_RT" }, \
+ { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }
/*
* Inode Log Item Format definitions.