Commit 76257a15 authored by Dave Chinner's avatar Dave Chinner

xfs: introduce xfs_for_each_perag_wrap()

In several places we iterate every AG from a specific start agno and
wrap back to the first AG when we reach the end of the filesystem to
continue searching. We don't have a primitive for this iteration
yet, so add one for conversion of these algorithms to per-ag based
iteration.

The filestream AG select code is a mess, and this initially makes it
worse. The per-ag selection needs to be driven completely into the
filestream code to clean this up and it will be done in a future
patch that makes the filestream allocator use active per-ag
references correctly.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
parent 7ac2ff8b
...@@ -237,7 +237,6 @@ xfs_perag_next( ...@@ -237,7 +237,6 @@ xfs_perag_next(
#define for_each_perag_from(mp, agno, pag) \ #define for_each_perag_from(mp, agno, pag) \
for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, (pag)) for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, (pag))
#define for_each_perag(mp, agno, pag) \ #define for_each_perag(mp, agno, pag) \
(agno) = 0; \ (agno) = 0; \
for_each_perag_from((mp), (agno), (pag)) for_each_perag_from((mp), (agno), (pag))
...@@ -249,6 +248,50 @@ xfs_perag_next( ...@@ -249,6 +248,50 @@ xfs_perag_next(
xfs_perag_rele(pag), \ xfs_perag_rele(pag), \
(pag) = xfs_perag_grab_tag((mp), (agno), (tag))) (pag) = xfs_perag_grab_tag((mp), (agno), (tag)))
static inline struct xfs_perag *
xfs_perag_next_wrap(
struct xfs_perag *pag,
xfs_agnumber_t *agno,
xfs_agnumber_t stop_agno,
xfs_agnumber_t wrap_agno)
{
struct xfs_mount *mp = pag->pag_mount;
*agno = pag->pag_agno + 1;
xfs_perag_rele(pag);
while (*agno != stop_agno) {
if (*agno >= wrap_agno)
*agno = 0;
if (*agno == stop_agno)
break;
pag = xfs_perag_grab(mp, *agno);
if (pag)
return pag;
(*agno)++;
}
return NULL;
}
/*
* Iterate all AGs from start_agno through wrap_agno, then 0 through
* (start_agno - 1).
*/
#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) \
for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), (agno)); \
(pag) != NULL; \
(pag) = xfs_perag_next_wrap((pag), &(agno), (start_agno), \
(wrap_agno)))
/*
* Iterate all AGs from start_agno through to the end of the filesystem, then 0
* through (start_agno - 1).
*/
#define for_each_perag_wrap(mp, start_agno, agno, pag) \
for_each_perag_wrap_at((mp), (start_agno), (mp)->m_sb.sb_agcount, \
(agno), (pag))
struct aghdr_init_data { struct aghdr_init_data {
/* per ag data */ /* per ag data */
xfs_agblock_t agno; /* ag to init */ xfs_agblock_t agno; /* ag to init */
......
...@@ -3136,17 +3136,14 @@ xfs_bmap_adjacent( ...@@ -3136,17 +3136,14 @@ xfs_bmap_adjacent(
static int static int
xfs_bmap_longest_free_extent( xfs_bmap_longest_free_extent(
struct xfs_perag *pag,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t ag,
xfs_extlen_t *blen, xfs_extlen_t *blen,
int *notinit) int *notinit)
{ {
struct xfs_mount *mp = tp->t_mountp;
struct xfs_perag *pag;
xfs_extlen_t longest; xfs_extlen_t longest;
int error = 0; int error = 0;
pag = xfs_perag_get(mp, ag);
if (!xfs_perag_initialised_agf(pag)) { if (!xfs_perag_initialised_agf(pag)) {
error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_TRYLOCK, error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_TRYLOCK,
NULL); NULL);
...@@ -3156,19 +3153,17 @@ xfs_bmap_longest_free_extent( ...@@ -3156,19 +3153,17 @@ xfs_bmap_longest_free_extent(
*notinit = 1; *notinit = 1;
error = 0; error = 0;
} }
goto out; return error;
} }
} }
longest = xfs_alloc_longest_free_extent(pag, longest = xfs_alloc_longest_free_extent(pag,
xfs_alloc_min_freelist(mp, pag), xfs_alloc_min_freelist(pag->pag_mount, pag),
xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE)); xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE));
if (*blen < longest) if (*blen < longest)
*blen = longest; *blen = longest;
out: return 0;
xfs_perag_put(pag);
return error;
} }
static void static void
...@@ -3206,9 +3201,10 @@ xfs_bmap_btalloc_select_lengths( ...@@ -3206,9 +3201,10 @@ xfs_bmap_btalloc_select_lengths(
xfs_extlen_t *blen) xfs_extlen_t *blen)
{ {
struct xfs_mount *mp = ap->ip->i_mount; struct xfs_mount *mp = ap->ip->i_mount;
xfs_agnumber_t ag, startag; struct xfs_perag *pag;
xfs_agnumber_t agno, startag;
int notinit = 0; int notinit = 0;
int error; int error = 0;
args->type = XFS_ALLOCTYPE_START_BNO; args->type = XFS_ALLOCTYPE_START_BNO;
if (ap->tp->t_flags & XFS_TRANS_LOWMODE) { if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
...@@ -3218,24 +3214,24 @@ xfs_bmap_btalloc_select_lengths( ...@@ -3218,24 +3214,24 @@ xfs_bmap_btalloc_select_lengths(
} }
args->total = ap->total; args->total = ap->total;
startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); startag = XFS_FSB_TO_AGNO(mp, args->fsbno);
if (startag == NULLAGNUMBER) if (startag == NULLAGNUMBER)
startag = ag = 0; startag = 0;
while (*blen < args->maxlen) { *blen = 0;
error = xfs_bmap_longest_free_extent(args->tp, ag, blen, for_each_perag_wrap(mp, startag, agno, pag) {
error = xfs_bmap_longest_free_extent(pag, args->tp, blen,
&notinit); &notinit);
if (error) if (error)
return error; break;
if (*blen >= args->maxlen)
if (++ag == mp->m_sb.sb_agcount)
ag = 0;
if (ag == startag)
break; break;
} }
if (pag)
xfs_perag_rele(pag);
xfs_bmap_select_minlen(ap, args, blen, notinit); xfs_bmap_select_minlen(ap, args, blen, notinit);
return 0; return error;
} }
STATIC int STATIC int
...@@ -3245,7 +3241,8 @@ xfs_bmap_btalloc_filestreams( ...@@ -3245,7 +3241,8 @@ xfs_bmap_btalloc_filestreams(
xfs_extlen_t *blen) xfs_extlen_t *blen)
{ {
struct xfs_mount *mp = ap->ip->i_mount; struct xfs_mount *mp = ap->ip->i_mount;
xfs_agnumber_t ag; struct xfs_perag *pag;
xfs_agnumber_t start_agno;
int notinit = 0; int notinit = 0;
int error; int error;
...@@ -3259,33 +3256,50 @@ xfs_bmap_btalloc_filestreams( ...@@ -3259,33 +3256,50 @@ xfs_bmap_btalloc_filestreams(
args->type = XFS_ALLOCTYPE_NEAR_BNO; args->type = XFS_ALLOCTYPE_NEAR_BNO;
args->total = ap->total; args->total = ap->total;
ag = XFS_FSB_TO_AGNO(mp, args->fsbno); start_agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
if (ag == NULLAGNUMBER) if (start_agno == NULLAGNUMBER)
ag = 0; start_agno = 0;
error = xfs_bmap_longest_free_extent(args->tp, ag, blen, &notinit); pag = xfs_perag_grab(mp, start_agno);
if (error) if (pag) {
return error; error = xfs_bmap_longest_free_extent(pag, args->tp, blen,
&notinit);
xfs_perag_rele(pag);
if (error)
return error;
}
if (*blen < args->maxlen) { if (*blen < args->maxlen) {
error = xfs_filestream_new_ag(ap, &ag); xfs_agnumber_t agno = start_agno;
error = xfs_filestream_new_ag(ap, &agno);
if (error) if (error)
return error; return error;
if (agno == NULLAGNUMBER)
goto out_select;
error = xfs_bmap_longest_free_extent(args->tp, ag, blen, pag = xfs_perag_grab(mp, agno);
&notinit); if (!pag)
goto out_select;
error = xfs_bmap_longest_free_extent(pag, args->tp,
blen, &notinit);
xfs_perag_rele(pag);
if (error) if (error)
return error; return error;
start_agno = agno;
} }
out_select:
xfs_bmap_select_minlen(ap, args, blen, notinit); xfs_bmap_select_minlen(ap, args, blen, notinit);
/* /*
* Set the failure fallback case to look in the selected AG as stream * Set the failure fallback case to look in the selected AG as stream
* may have moved. * may have moved.
*/ */
ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, start_agno, 0);
return 0; return 0;
} }
......
...@@ -1725,7 +1725,7 @@ xfs_dialloc( ...@@ -1725,7 +1725,7 @@ xfs_dialloc(
bool ok_alloc = true; bool ok_alloc = true;
bool low_space = false; bool low_space = false;
int flags; int flags;
xfs_ino_t ino; xfs_ino_t ino = NULLFSINO;
/* /*
* Directories, symlinks, and regular files frequently allocate at least * Directories, symlinks, and regular files frequently allocate at least
...@@ -1773,39 +1773,37 @@ xfs_dialloc( ...@@ -1773,39 +1773,37 @@ xfs_dialloc(
* or in which we can allocate some inodes. Iterate through the * or in which we can allocate some inodes. Iterate through the
* allocation groups upward, wrapping at the end. * allocation groups upward, wrapping at the end.
*/ */
agno = start_agno;
flags = XFS_ALLOC_FLAG_TRYLOCK; flags = XFS_ALLOC_FLAG_TRYLOCK;
for (;;) { retry:
pag = xfs_perag_grab(mp, agno); for_each_perag_wrap_at(mp, start_agno, mp->m_maxagi, agno, pag) {
if (xfs_dialloc_good_ag(pag, *tpp, mode, flags, ok_alloc)) { if (xfs_dialloc_good_ag(pag, *tpp, mode, flags, ok_alloc)) {
error = xfs_dialloc_try_ag(pag, tpp, parent, error = xfs_dialloc_try_ag(pag, tpp, parent,
&ino, ok_alloc); &ino, ok_alloc);
if (error != -EAGAIN) if (error != -EAGAIN)
break; break;
error = 0;
} }
if (xfs_is_shutdown(mp)) { if (xfs_is_shutdown(mp)) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
break; break;
} }
if (++agno == mp->m_maxagi) }
agno = 0; if (pag)
if (agno == start_agno) { xfs_perag_rele(pag);
if (!flags) { if (error)
error = -ENOSPC; return error;
break; if (ino == NULLFSINO) {
} if (flags) {
flags = 0; flags = 0;
if (low_space) if (low_space)
ok_alloc = true; ok_alloc = true;
goto retry;
} }
xfs_perag_rele(pag); return -ENOSPC;
} }
*new_ino = ino;
if (!error) return 0;
*new_ino = ino;
xfs_perag_rele(pag);
return error;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment