Skip to content

Commit 7e85fc2

Browse files
author
Darrick J. Wong
committed
xfs: implement busy extent tracking for rtgroups
For rtgroups filesystems, track newly freed (rt) space through the log until the rt EFIs have been committed to disk. This way we ensure that space cannot be reused until all traces of the old owner are gone. As a fringe benefit, we now support -o discard on the realtime device. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 0c271d9 commit 7e85fc2

File tree

5 files changed

+227
-6
lines changed

5 files changed

+227
-6
lines changed

fs/xfs/libxfs/xfs_rtbitmap.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "xfs_errortag.h"
2525
#include "xfs_log.h"
2626
#include "xfs_buf_item.h"
27+
#include "xfs_extent_busy.h"
2728

2829
/*
2930
* Realtime allocator bitmap functions shared with userspace.
@@ -1120,6 +1121,7 @@ xfs_rtfree_blocks(
11201121
{
11211122
struct xfs_mount *mp = tp->t_mountp;
11221123
xfs_extlen_t mod;
1124+
int error;
11231125

11241126
ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
11251127

@@ -1135,8 +1137,16 @@ xfs_rtfree_blocks(
11351137
return -EIO;
11361138
}
11371139

1138-
return xfs_rtfree_extent(tp, rtg, xfs_rtb_to_rtx(mp, rtbno),
1140+
error = xfs_rtfree_extent(tp, rtg, xfs_rtb_to_rtx(mp, rtbno),
11391141
xfs_extlen_to_rtxlen(mp, rtlen));
1142+
if (error)
1143+
return error;
1144+
1145+
if (xfs_has_rtgroups(mp))
1146+
xfs_extent_busy_insert(tp, rtg_group(rtg),
1147+
xfs_rtb_to_rgbno(mp, rtbno), rtlen, 0);
1148+
1149+
return 0;
11401150
}
11411151

11421152
/* Find all the free records within a given range. */

fs/xfs/libxfs/xfs_rtgroup.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,19 @@ xfs_rtbno_is_group_start(
155155
return (rtbno & mp->m_groups[XG_TYPE_RTG].blkmask) == 0;
156156
}
157157

158+
/* Convert an rtgroups rt extent number into an rgbno. */
159+
static inline xfs_rgblock_t
160+
xfs_rtx_to_rgbno(
161+
struct xfs_rtgroup *rtg,
162+
xfs_rtxnum_t rtx)
163+
{
164+
struct xfs_mount *mp = rtg_mount(rtg);
165+
166+
if (likely(mp->m_rtxblklog >= 0))
167+
return rtx << mp->m_rtxblklog;
168+
return rtx * mp->m_sb.sb_rextsize;
169+
}
170+
158171
static inline xfs_daddr_t
159172
xfs_rtb_to_daddr(
160173
struct xfs_mount *mp,

fs/xfs/xfs_extent_busy.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "xfs_trans.h"
1919
#include "xfs_log.h"
2020
#include "xfs_ag.h"
21+
#include "xfs_rtgroup.h"
2122

2223
struct xfs_extent_busy_tree {
2324
spinlock_t eb_lock;
@@ -665,9 +666,14 @@ xfs_extent_busy_wait_all(
665666
struct xfs_mount *mp)
666667
{
667668
struct xfs_perag *pag = NULL;
669+
struct xfs_rtgroup *rtg = NULL;
668670

669671
while ((pag = xfs_perag_next(mp, pag)))
670672
xfs_extent_busy_wait_group(pag_group(pag));
673+
674+
if (xfs_has_rtgroups(mp))
675+
while ((rtg = xfs_rtgroup_next(mp, rtg)))
676+
xfs_extent_busy_wait_group(rtg_group(rtg));
671677
}
672678

673679
/*

fs/xfs/xfs_rtalloc.c

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "xfs_metafile.h"
3030
#include "xfs_rtgroup.h"
3131
#include "xfs_error.h"
32+
#include "xfs_trace.h"
3233

3334
/*
3435
* Return whether there are any free extents in the size range given
@@ -1659,6 +1660,114 @@ xfs_rtalloc_align_minmax(
16591660
*raminlen = newminlen;
16601661
}
16611662

1663+
/* Given a free extent, find any part of it that isn't busy, if possible. */
1664+
STATIC bool
1665+
xfs_rtalloc_check_busy(
1666+
struct xfs_rtalloc_args *args,
1667+
xfs_rtxnum_t start,
1668+
xfs_rtxlen_t minlen_rtx,
1669+
xfs_rtxlen_t maxlen_rtx,
1670+
xfs_rtxlen_t len_rtx,
1671+
xfs_rtxlen_t prod,
1672+
xfs_rtxnum_t rtx,
1673+
xfs_rtxlen_t *reslen,
1674+
xfs_rtxnum_t *resrtx,
1675+
unsigned *busy_gen)
1676+
{
1677+
struct xfs_rtgroup *rtg = args->rtg;
1678+
struct xfs_mount *mp = rtg_mount(rtg);
1679+
xfs_agblock_t rgbno = xfs_rtx_to_rgbno(rtg, rtx);
1680+
xfs_rgblock_t min_rgbno = xfs_rtx_to_rgbno(rtg, start);
1681+
xfs_extlen_t minlen = xfs_rtxlen_to_extlen(mp, minlen_rtx);
1682+
xfs_extlen_t len = xfs_rtxlen_to_extlen(mp, len_rtx);
1683+
xfs_extlen_t diff;
1684+
bool busy;
1685+
1686+
busy = xfs_extent_busy_trim(rtg_group(rtg), minlen,
1687+
xfs_rtxlen_to_extlen(mp, maxlen_rtx), &rgbno, &len,
1688+
busy_gen);
1689+
1690+
/*
1691+
* If we have a largish extent that happens to start before min_rgbno,
1692+
* see if we can shift it into range...
1693+
*/
1694+
if (rgbno < min_rgbno && rgbno + len > min_rgbno) {
1695+
diff = min_rgbno - rgbno;
1696+
if (len > diff) {
1697+
rgbno += diff;
1698+
len -= diff;
1699+
}
1700+
}
1701+
1702+
if (prod > 1 && len >= minlen) {
1703+
xfs_rgblock_t aligned_rgbno = roundup(rgbno, prod);
1704+
1705+
diff = aligned_rgbno - rgbno;
1706+
1707+
*resrtx = xfs_rgbno_to_rtx(mp, aligned_rgbno);
1708+
*reslen = xfs_extlen_to_rtxlen(mp,
1709+
diff >= len ? 0 : len - diff);
1710+
} else {
1711+
*resrtx = xfs_rgbno_to_rtx(mp, rgbno);
1712+
*reslen = xfs_extlen_to_rtxlen(mp, len);
1713+
}
1714+
1715+
return busy;
1716+
}
1717+
1718+
/*
1719+
* Adjust the given free extent so that it isn't busy, or flush the log and
1720+
* wait for the space to become unbusy. Only needed for rtgroups.
1721+
*/
1722+
STATIC int
1723+
xfs_rtallocate_adjust_for_busy(
1724+
struct xfs_rtalloc_args *args,
1725+
xfs_rtxnum_t start,
1726+
xfs_rtxlen_t minlen,
1727+
xfs_rtxlen_t maxlen,
1728+
xfs_rtxlen_t *len,
1729+
xfs_rtxlen_t prod,
1730+
xfs_rtxnum_t *rtx)
1731+
{
1732+
xfs_rtxnum_t resrtx;
1733+
xfs_rtxlen_t reslen;
1734+
unsigned busy_gen;
1735+
bool busy;
1736+
int error;
1737+
1738+
again:
1739+
busy = xfs_rtalloc_check_busy(args, start, minlen, maxlen, *len, prod,
1740+
*rtx, &reslen, &resrtx, &busy_gen);
1741+
if (!busy)
1742+
return 0;
1743+
1744+
if (reslen < minlen || (start != 0 && resrtx != *rtx)) {
1745+
/*
1746+
* Enough of the extent was busy that we cannot satisfy the
1747+
* allocation, or this is a near allocation and the start of
1748+
* the extent is busy. Flush the log and wait for the busy
1749+
* situation to resolve.
1750+
*/
1751+
trace_xfs_rtalloc_extent_busy(args->rtg, start, minlen, maxlen,
1752+
*len, prod, *rtx, busy_gen);
1753+
1754+
error = xfs_extent_busy_flush(args->tp, rtg_group(args->rtg),
1755+
busy_gen, 0);
1756+
if (error)
1757+
return error;
1758+
1759+
goto again;
1760+
}
1761+
1762+
/* Some of the free space wasn't busy, hand that back to the caller. */
1763+
trace_xfs_rtalloc_extent_busy_trim(args->rtg, *rtx, *len, resrtx,
1764+
reslen);
1765+
*len = reslen;
1766+
*rtx = resrtx;
1767+
1768+
return 0;
1769+
}
1770+
16621771
static int
16631772
xfs_rtallocate_rtg(
16641773
struct xfs_trans *tp,
@@ -1740,15 +1849,19 @@ xfs_rtallocate_rtg(
17401849
}
17411850

17421851
if (error) {
1743-
if (xfs_has_rtgroups(args.mp)) {
1744-
xfs_rtgroup_unlock(args.rtg, XFS_RTGLOCK_BITMAP);
1745-
*rtlocked = false;
1746-
}
1852+
if (xfs_has_rtgroups(args.mp))
1853+
goto out_unlock;
17471854
goto out_release;
17481855
}
17491856

1750-
if (xfs_has_rtgroups(args.mp))
1857+
if (xfs_has_rtgroups(args.mp)) {
1858+
error = xfs_rtallocate_adjust_for_busy(&args, start, minlen,
1859+
maxlen, &len, prod, &rtx);
1860+
if (error)
1861+
goto out_unlock;
1862+
17511863
xfs_rtgroup_trans_join(tp, args.rtg, XFS_RTGLOCK_BITMAP);
1864+
}
17521865

17531866
error = xfs_rtallocate_range(&args, rtx, len);
17541867
if (error)
@@ -1764,6 +1877,10 @@ xfs_rtallocate_rtg(
17641877
xfs_rtgroup_rele(args.rtg);
17651878
xfs_rtbuf_cache_relse(&args);
17661879
return error;
1880+
out_unlock:
1881+
xfs_rtgroup_unlock(args.rtg, XFS_RTGLOCK_BITMAP);
1882+
*rtlocked = false;
1883+
goto out_release;
17671884
}
17681885

17691886
static int

fs/xfs/xfs_trace.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct xfs_extent_free_item;
9797
struct xfs_rmap_intent;
9898
struct xfs_refcount_intent;
9999
struct xfs_metadir_update;
100+
struct xfs_rtgroup;
100101

101102
#define XFS_ATTR_FILTER_FLAGS \
102103
{ XFS_ATTR_ROOT, "ROOT" }, \
@@ -1744,6 +1745,80 @@ TRACE_EVENT(xfs_extent_busy_trim,
17441745
__entry->tlen)
17451746
);
17461747

1748+
#ifdef CONFIG_XFS_RT
1749+
TRACE_EVENT(xfs_rtalloc_extent_busy,
1750+
TP_PROTO(struct xfs_rtgroup *rtg, xfs_rtxnum_t start,
1751+
xfs_rtxlen_t minlen, xfs_rtxlen_t maxlen,
1752+
xfs_rtxlen_t len, xfs_rtxlen_t prod, xfs_rtxnum_t rtx,
1753+
unsigned busy_gen),
1754+
TP_ARGS(rtg, start, minlen, maxlen, len, prod, rtx, busy_gen),
1755+
TP_STRUCT__entry(
1756+
__field(dev_t, dev)
1757+
__field(xfs_rgnumber_t, rgno)
1758+
__field(xfs_rtxnum_t, start)
1759+
__field(xfs_rtxlen_t, minlen)
1760+
__field(xfs_rtxlen_t, maxlen)
1761+
__field(xfs_rtxlen_t, mod)
1762+
__field(xfs_rtxlen_t, prod)
1763+
__field(xfs_rtxlen_t, len)
1764+
__field(xfs_rtxnum_t, rtx)
1765+
__field(unsigned, busy_gen)
1766+
),
1767+
TP_fast_assign(
1768+
__entry->dev = rtg_mount(rtg)->m_super->s_dev;
1769+
__entry->rgno = rtg_rgno(rtg);
1770+
__entry->start = start;
1771+
__entry->minlen = minlen;
1772+
__entry->maxlen = maxlen;
1773+
__entry->prod = prod;
1774+
__entry->len = len;
1775+
__entry->rtx = rtx;
1776+
__entry->busy_gen = busy_gen;
1777+
),
1778+
TP_printk("dev %d:%d rgno 0x%x startrtx 0x%llx minlen %u maxlen %u "
1779+
"prod %u len %u rtx 0%llx busy_gen 0x%x",
1780+
MAJOR(__entry->dev), MINOR(__entry->dev),
1781+
__entry->rgno,
1782+
__entry->start,
1783+
__entry->minlen,
1784+
__entry->maxlen,
1785+
__entry->prod,
1786+
__entry->len,
1787+
__entry->rtx,
1788+
__entry->busy_gen)
1789+
)
1790+
1791+
TRACE_EVENT(xfs_rtalloc_extent_busy_trim,
1792+
TP_PROTO(struct xfs_rtgroup *rtg, xfs_rtxnum_t old_rtx,
1793+
xfs_rtxlen_t old_len, xfs_rtxnum_t new_rtx,
1794+
xfs_rtxlen_t new_len),
1795+
TP_ARGS(rtg, old_rtx, old_len, new_rtx, new_len),
1796+
TP_STRUCT__entry(
1797+
__field(dev_t, dev)
1798+
__field(xfs_rgnumber_t, rgno)
1799+
__field(xfs_rtxnum_t, old_rtx)
1800+
__field(xfs_rtxnum_t, new_rtx)
1801+
__field(xfs_rtxlen_t, old_len)
1802+
__field(xfs_rtxlen_t, new_len)
1803+
),
1804+
TP_fast_assign(
1805+
__entry->dev = rtg_mount(rtg)->m_super->s_dev;
1806+
__entry->rgno = rtg_rgno(rtg);
1807+
__entry->old_rtx = old_rtx;
1808+
__entry->old_len = old_len;
1809+
__entry->new_rtx = new_rtx;
1810+
__entry->new_len = new_len;
1811+
),
1812+
TP_printk("dev %d:%d rgno 0x%x rtx 0x%llx rtxcount 0x%x -> rtx 0x%llx rtxcount 0x%x",
1813+
MAJOR(__entry->dev), MINOR(__entry->dev),
1814+
__entry->rgno,
1815+
__entry->old_rtx,
1816+
__entry->old_len,
1817+
__entry->new_rtx,
1818+
__entry->new_len)
1819+
);
1820+
#endif /* CONFIG_XFS_RT */
1821+
17471822
DECLARE_EVENT_CLASS(xfs_agf_class,
17481823
TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags,
17491824
unsigned long caller_ip),

0 commit comments

Comments
 (0)