mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 14:44:10 +08:00
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: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
parent
7ac2ff8bb3
commit
76257a1587
@ -237,7 +237,6 @@ xfs_perag_next(
|
||||
#define for_each_perag_from(mp, agno, pag) \
|
||||
for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, (pag))
|
||||
|
||||
|
||||
#define for_each_perag(mp, agno, pag) \
|
||||
(agno) = 0; \
|
||||
for_each_perag_from((mp), (agno), (pag))
|
||||
@ -249,6 +248,50 @@ xfs_perag_next(
|
||||
xfs_perag_rele(pag), \
|
||||
(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 {
|
||||
/* per ag data */
|
||||
xfs_agblock_t agno; /* ag to init */
|
||||
|
@ -3136,17 +3136,14 @@ xfs_bmap_adjacent(
|
||||
|
||||
static int
|
||||
xfs_bmap_longest_free_extent(
|
||||
struct xfs_perag *pag,
|
||||
struct xfs_trans *tp,
|
||||
xfs_agnumber_t ag,
|
||||
xfs_extlen_t *blen,
|
||||
int *notinit)
|
||||
{
|
||||
struct xfs_mount *mp = tp->t_mountp;
|
||||
struct xfs_perag *pag;
|
||||
xfs_extlen_t longest;
|
||||
int error = 0;
|
||||
|
||||
pag = xfs_perag_get(mp, ag);
|
||||
if (!xfs_perag_initialised_agf(pag)) {
|
||||
error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_TRYLOCK,
|
||||
NULL);
|
||||
@ -3156,19 +3153,17 @@ xfs_bmap_longest_free_extent(
|
||||
*notinit = 1;
|
||||
error = 0;
|
||||
}
|
||||
goto out;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
if (*blen < longest)
|
||||
*blen = longest;
|
||||
|
||||
out:
|
||||
xfs_perag_put(pag);
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3206,9 +3201,10 @@ xfs_bmap_btalloc_select_lengths(
|
||||
xfs_extlen_t *blen)
|
||||
{
|
||||
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 error;
|
||||
int error = 0;
|
||||
|
||||
args->type = XFS_ALLOCTYPE_START_BNO;
|
||||
if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
|
||||
@ -3218,24 +3214,24 @@ xfs_bmap_btalloc_select_lengths(
|
||||
}
|
||||
|
||||
args->total = ap->total;
|
||||
startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||
startag = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||
if (startag == NULLAGNUMBER)
|
||||
startag = ag = 0;
|
||||
startag = 0;
|
||||
|
||||
while (*blen < args->maxlen) {
|
||||
error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
|
||||
*blen = 0;
|
||||
for_each_perag_wrap(mp, startag, agno, pag) {
|
||||
error = xfs_bmap_longest_free_extent(pag, args->tp, blen,
|
||||
¬init);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (++ag == mp->m_sb.sb_agcount)
|
||||
ag = 0;
|
||||
if (ag == startag)
|
||||
break;
|
||||
if (*blen >= args->maxlen)
|
||||
break;
|
||||
}
|
||||
if (pag)
|
||||
xfs_perag_rele(pag);
|
||||
|
||||
xfs_bmap_select_minlen(ap, args, blen, notinit);
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@ -3245,7 +3241,8 @@ xfs_bmap_btalloc_filestreams(
|
||||
xfs_extlen_t *blen)
|
||||
{
|
||||
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 error;
|
||||
|
||||
@ -3259,33 +3256,50 @@ xfs_bmap_btalloc_filestreams(
|
||||
args->type = XFS_ALLOCTYPE_NEAR_BNO;
|
||||
args->total = ap->total;
|
||||
|
||||
ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||
if (ag == NULLAGNUMBER)
|
||||
ag = 0;
|
||||
start_agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||
if (start_agno == NULLAGNUMBER)
|
||||
start_agno = 0;
|
||||
|
||||
error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init);
|
||||
if (error)
|
||||
return error;
|
||||
pag = xfs_perag_grab(mp, start_agno);
|
||||
if (pag) {
|
||||
error = xfs_bmap_longest_free_extent(pag, args->tp, blen,
|
||||
¬init);
|
||||
xfs_perag_rele(pag);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
return error;
|
||||
if (agno == NULLAGNUMBER)
|
||||
goto out_select;
|
||||
|
||||
pag = xfs_perag_grab(mp, agno);
|
||||
if (!pag)
|
||||
goto out_select;
|
||||
|
||||
error = xfs_bmap_longest_free_extent(pag, args->tp,
|
||||
blen, ¬init);
|
||||
xfs_perag_rele(pag);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
|
||||
¬init);
|
||||
if (error)
|
||||
return error;
|
||||
start_agno = agno;
|
||||
|
||||
}
|
||||
|
||||
out_select:
|
||||
xfs_bmap_select_minlen(ap, args, blen, notinit);
|
||||
|
||||
/*
|
||||
* Set the failure fallback case to look in the selected AG as stream
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
@ -1725,7 +1725,7 @@ xfs_dialloc(
|
||||
bool ok_alloc = true;
|
||||
bool low_space = false;
|
||||
int flags;
|
||||
xfs_ino_t ino;
|
||||
xfs_ino_t ino = NULLFSINO;
|
||||
|
||||
/*
|
||||
* Directories, symlinks, and regular files frequently allocate at least
|
||||
@ -1773,39 +1773,37 @@ xfs_dialloc(
|
||||
* or in which we can allocate some inodes. Iterate through the
|
||||
* allocation groups upward, wrapping at the end.
|
||||
*/
|
||||
agno = start_agno;
|
||||
flags = XFS_ALLOC_FLAG_TRYLOCK;
|
||||
for (;;) {
|
||||
pag = xfs_perag_grab(mp, agno);
|
||||
retry:
|
||||
for_each_perag_wrap_at(mp, start_agno, mp->m_maxagi, agno, pag) {
|
||||
if (xfs_dialloc_good_ag(pag, *tpp, mode, flags, ok_alloc)) {
|
||||
error = xfs_dialloc_try_ag(pag, tpp, parent,
|
||||
&ino, ok_alloc);
|
||||
if (error != -EAGAIN)
|
||||
break;
|
||||
error = 0;
|
||||
}
|
||||
|
||||
if (xfs_is_shutdown(mp)) {
|
||||
error = -EFSCORRUPTED;
|
||||
break;
|
||||
}
|
||||
if (++agno == mp->m_maxagi)
|
||||
agno = 0;
|
||||
if (agno == start_agno) {
|
||||
if (!flags) {
|
||||
error = -ENOSPC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pag)
|
||||
xfs_perag_rele(pag);
|
||||
if (error)
|
||||
return error;
|
||||
if (ino == NULLFSINO) {
|
||||
if (flags) {
|
||||
flags = 0;
|
||||
if (low_space)
|
||||
ok_alloc = true;
|
||||
goto retry;
|
||||
}
|
||||
xfs_perag_rele(pag);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
*new_ino = ino;
|
||||
xfs_perag_rele(pag);
|
||||
return error;
|
||||
*new_ino = ino;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user