|
@@ -2658,55 +2658,79 @@ error0:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Free an extent.
|
|
|
- * Just break up the extent address and hand off to xfs_free_ag_extent
|
|
|
- * after fixing up the freelist.
|
|
|
- */
|
|
|
-int /* error */
|
|
|
-xfs_free_extent(
|
|
|
- xfs_trans_t *tp, /* transaction pointer */
|
|
|
- xfs_fsblock_t bno, /* starting block number of extent */
|
|
|
- xfs_extlen_t len) /* length of extent */
|
|
|
+/* Ensure that the freelist is at full capacity. */
|
|
|
+int
|
|
|
+xfs_free_extent_fix_freelist(
|
|
|
+ struct xfs_trans *tp,
|
|
|
+ xfs_agnumber_t agno,
|
|
|
+ struct xfs_buf **agbp)
|
|
|
{
|
|
|
- xfs_alloc_arg_t args;
|
|
|
- int error;
|
|
|
+ struct xfs_alloc_arg args;
|
|
|
+ int error;
|
|
|
|
|
|
- ASSERT(len != 0);
|
|
|
- memset(&args, 0, sizeof(xfs_alloc_arg_t));
|
|
|
+ memset(&args, 0, sizeof(struct xfs_alloc_arg));
|
|
|
args.tp = tp;
|
|
|
args.mp = tp->t_mountp;
|
|
|
+ args.agno = agno;
|
|
|
|
|
|
/*
|
|
|
* validate that the block number is legal - the enables us to detect
|
|
|
* and handle a silent filesystem corruption rather than crashing.
|
|
|
*/
|
|
|
- args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
|
|
|
if (args.agno >= args.mp->m_sb.sb_agcount)
|
|
|
return -EFSCORRUPTED;
|
|
|
|
|
|
- args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
|
|
|
- if (args.agbno >= args.mp->m_sb.sb_agblocks)
|
|
|
- return -EFSCORRUPTED;
|
|
|
-
|
|
|
args.pag = xfs_perag_get(args.mp, args.agno);
|
|
|
ASSERT(args.pag);
|
|
|
|
|
|
error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
|
|
|
if (error)
|
|
|
- goto error0;
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ *agbp = args.agbp;
|
|
|
+out:
|
|
|
+ xfs_perag_put(args.pag);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Free an extent.
|
|
|
+ * Just break up the extent address and hand off to xfs_free_ag_extent
|
|
|
+ * after fixing up the freelist.
|
|
|
+ */
|
|
|
+int /* error */
|
|
|
+xfs_free_extent(
|
|
|
+ struct xfs_trans *tp, /* transaction pointer */
|
|
|
+ xfs_fsblock_t bno, /* starting block number of extent */
|
|
|
+ xfs_extlen_t len) /* length of extent */
|
|
|
+{
|
|
|
+ struct xfs_mount *mp = tp->t_mountp;
|
|
|
+ struct xfs_buf *agbp;
|
|
|
+ xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, bno);
|
|
|
+ xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, bno);
|
|
|
+ int error;
|
|
|
+
|
|
|
+ ASSERT(len != 0);
|
|
|
+
|
|
|
+ error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ XFS_WANT_CORRUPTED_GOTO(mp, agbno < mp->m_sb.sb_agblocks, err);
|
|
|
|
|
|
/* validate the extent size is legal now we have the agf locked */
|
|
|
- if (args.agbno + len >
|
|
|
- be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) {
|
|
|
- error = -EFSCORRUPTED;
|
|
|
- goto error0;
|
|
|
- }
|
|
|
+ XFS_WANT_CORRUPTED_GOTO(mp,
|
|
|
+ agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length),
|
|
|
+ err);
|
|
|
|
|
|
- error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
|
|
|
- if (!error)
|
|
|
- xfs_extent_busy_insert(tp, args.agno, args.agbno, len, 0);
|
|
|
-error0:
|
|
|
- xfs_perag_put(args.pag);
|
|
|
+ error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, 0);
|
|
|
+ if (error)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ xfs_extent_busy_insert(tp, agno, agbno, len, 0);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ xfs_trans_brelse(tp, agbp);
|
|
|
return error;
|
|
|
}
|