提交 396503fc 编写于 作者: D Dave Chinner 提交者: Dave Chinner

xfs: sanitise error handling in xfs_alloc_fix_freelist

The error handling is currently an inconsistent mess as every error
condition handles return values and releasing buffers individually.
Clean this up by using gotos and a sane error label stack.
Signed-off-by: NDave Chinner <dchinner@redhat.com>
Reviewed-by: NBrian Foster <bfoster@redhat.com>
Signed-off-by: NDave Chinner <david@fromorbit.com>
上级 72d55285
...@@ -1877,84 +1877,77 @@ xfs_alloc_space_available( ...@@ -1877,84 +1877,77 @@ xfs_alloc_space_available(
*/ */
STATIC int /* error */ STATIC int /* error */
xfs_alloc_fix_freelist( xfs_alloc_fix_freelist(
xfs_alloc_arg_t *args, /* allocation argument structure */ struct xfs_alloc_arg *args, /* allocation argument structure */
int flags) /* XFS_ALLOC_FLAG_... */ int flags) /* XFS_ALLOC_FLAG_... */
{ {
xfs_buf_t *agbp; /* agf buffer pointer */ struct xfs_mount *mp = args->mp;
xfs_buf_t *agflbp;/* agfl buffer pointer */ struct xfs_perag *pag = args->pag;
xfs_agblock_t bno; /* freelist block */ struct xfs_trans *tp = args->tp;
int error; /* error result code */ struct xfs_buf *agbp = NULL;
xfs_mount_t *mp; /* file system mount point structure */ struct xfs_buf *agflbp = NULL;
xfs_extlen_t need; /* total blocks needed in freelist */ struct xfs_alloc_arg targs; /* local allocation arguments */
xfs_perag_t *pag; /* per-ag information structure */ xfs_agblock_t bno; /* freelist block */
xfs_alloc_arg_t targs; /* local allocation arguments */ xfs_extlen_t need; /* total blocks needed in freelist */
xfs_trans_t *tp; /* transaction pointer */ int error;
mp = args->mp;
pag = args->pag;
tp = args->tp;
if (!pag->pagf_init) { if (!pag->pagf_init) {
if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
&agbp))) if (error)
return error; goto out_no_agbp;
if (!pag->pagf_init) { if (!pag->pagf_init) {
ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);
ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
args->agbp = NULL; goto out_agbp_relse;
return 0;
} }
} else }
agbp = NULL;
/* /*
* If this is a metadata preferred pag and we are user data * If this is a metadata preferred pag and we are user data then try
* then try somewhere else if we are not being asked to * somewhere else if we are not being asked to try harder at this
* try harder at this point * point
*/ */
if (pag->pagf_metadata && args->userdata && if (pag->pagf_metadata && args->userdata &&
(flags & XFS_ALLOC_FLAG_TRYLOCK)) { (flags & XFS_ALLOC_FLAG_TRYLOCK)) {
ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
args->agbp = NULL; goto out_agbp_relse;
return 0;
} }
need = XFS_MIN_FREELIST_PAG(pag, mp); need = XFS_MIN_FREELIST_PAG(pag, mp);
if (!xfs_alloc_space_available(args, need, flags)) { if (!xfs_alloc_space_available(args, need, flags))
if (agbp) goto out_agbp_relse;
xfs_trans_brelse(tp, agbp);
args->agbp = NULL;
return 0;
}
/* /*
* Get the a.g. freespace buffer. * Get the a.g. freespace buffer.
* Can fail if we're not blocking on locks, and it's held. * Can fail if we're not blocking on locks, and it's held.
*/ */
if (agbp == NULL) { if (!agbp) {
if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
&agbp))) if (error)
return error; goto out_no_agbp;
if (agbp == NULL) { if (!agbp) {
ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);
ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
args->agbp = NULL; goto out_no_agbp;
return 0;
} }
} }
/* If there isn't enough total space or single-extent, reject it. */ /* If there isn't enough total space or single-extent, reject it. */
need = XFS_MIN_FREELIST_PAG(pag, mp); need = XFS_MIN_FREELIST_PAG(pag, mp);
if (!xfs_alloc_space_available(args, need, flags)) { if (!xfs_alloc_space_available(args, need, flags))
xfs_trans_brelse(tp, agbp); goto out_agbp_relse;
args->agbp = NULL;
return 0;
}
/* /*
* Make the freelist shorter if it's too long. * Make the freelist shorter if it's too long.
* *
* Note that from this point onwards, we will always release the agf and
* agfl buffers on error. This handles the case where we error out and
* the buffers are clean or may not have been joined to the transaction
* and hence need to be released manually. If they have been joined to
* the transaction, then xfs_trans_brelse() will handle them
* appropriately based on the recursion count and dirty state of the
* buffer.
*
* XXX (dgc): When we have lots of free space, does this buy us * XXX (dgc): When we have lots of free space, does this buy us
* anything other than extra overhead when we need to put more blocks * anything other than extra overhead when we need to put more blocks
* back on the free list? Maybe we should only do this when space is * back on the free list? Maybe we should only do this when space is
...@@ -1965,10 +1958,10 @@ xfs_alloc_fix_freelist( ...@@ -1965,10 +1958,10 @@ xfs_alloc_fix_freelist(
error = xfs_alloc_get_freelist(tp, agbp, &bno, 0); error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
if (error) if (error)
return error; goto out_agbp_relse;
error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1); error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1);
if (error) if (error)
return error; goto out_agbp_relse;
bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
xfs_trans_binval(tp, bp); xfs_trans_binval(tp, bp);
} }
...@@ -1983,7 +1976,7 @@ xfs_alloc_fix_freelist( ...@@ -1983,7 +1976,7 @@ xfs_alloc_fix_freelist(
targs.pag = pag; targs.pag = pag;
error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp); error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp);
if (error) if (error)
return error; goto out_agbp_relse;
/* Make the freelist longer if it's too short. */ /* Make the freelist longer if it's too short. */
while (pag->pagf_flcount < need) { while (pag->pagf_flcount < need) {
...@@ -1992,10 +1985,9 @@ xfs_alloc_fix_freelist( ...@@ -1992,10 +1985,9 @@ xfs_alloc_fix_freelist(
/* Allocate as many blocks as possible at once. */ /* Allocate as many blocks as possible at once. */
error = xfs_alloc_ag_vextent(&targs); error = xfs_alloc_ag_vextent(&targs);
if (error) { if (error)
xfs_trans_brelse(tp, agflbp); goto out_agflbp_relse;
return error;
}
/* /*
* Stop if we run out. Won't happen if callers are obeying * Stop if we run out. Won't happen if callers are obeying
* the restrictions correctly. Can happen for free calls * the restrictions correctly. Can happen for free calls
...@@ -2004,9 +1996,7 @@ xfs_alloc_fix_freelist( ...@@ -2004,9 +1996,7 @@ xfs_alloc_fix_freelist(
if (targs.agbno == NULLAGBLOCK) { if (targs.agbno == NULLAGBLOCK) {
if (flags & XFS_ALLOC_FLAG_FREEING) if (flags & XFS_ALLOC_FLAG_FREEING)
break; break;
xfs_trans_brelse(tp, agflbp); goto out_agflbp_relse;
args->agbp = NULL;
return 0;
} }
/* /*
* Put each allocated block on the list. * Put each allocated block on the list.
...@@ -2015,12 +2005,21 @@ xfs_alloc_fix_freelist( ...@@ -2015,12 +2005,21 @@ xfs_alloc_fix_freelist(
error = xfs_alloc_put_freelist(tp, agbp, error = xfs_alloc_put_freelist(tp, agbp,
agflbp, bno, 0); agflbp, bno, 0);
if (error) if (error)
return error; goto out_agflbp_relse;
} }
} }
xfs_trans_brelse(tp, agflbp); xfs_trans_brelse(tp, agflbp);
args->agbp = agbp; args->agbp = agbp;
return 0; return 0;
out_agflbp_relse:
xfs_trans_brelse(tp, agflbp);
out_agbp_relse:
if (agbp)
xfs_trans_brelse(tp, agbp);
out_no_agbp:
args->agbp = NULL;
return error;
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册