@@ -12,6 +12,7 @@
#include "dinode.h"
#include "slab.h"
#include "rmap.h"
+#include "bitmap.h"
#undef RMAP_DEBUG
@@ -450,15 +451,16 @@ rmap_store_ag_btree_rec(
struct xfs_buf *agflbp = NULL;
struct xfs_trans *tp;
__be32 *agfl_bno, *b;
+ struct xfs_ag_rmap *ag_rmap = &ag_rmaps[agno];
+ struct bitmap *own_ag_bitmap = NULL;
int error = 0;
if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
return 0;
/* Release the ar_rmaps; they were put into the rmapbt during p5. */
- free_slab(&ag_rmaps[agno].ar_rmaps);
- error = init_slab(&ag_rmaps[agno].ar_rmaps,
- sizeof(struct xfs_rmap_irec));
+ free_slab(&ag_rmap->ar_rmaps);
+ error = init_slab(&ag_rmap->ar_rmaps, sizeof(struct xfs_rmap_irec));
if (error)
goto err;
@@ -478,19 +480,50 @@ rmap_store_ag_btree_rec(
* rmap, we only need to add rmap records for AGFL blocks past
* that point in the AGFL because those blocks are a result of a
* no-rmap no-shrink freelist fixup that we did earlier.
+ *
+ * However, some blocks end up on the AGFL because the free space
+ * btrees shed blocks as a result of allocating space to fix the
+ * freelist. We already created in-core rmap records for the free
+ * space btree blocks, so we must be careful not to create those
+ * records again. Create a bitmap of already-recorded OWN_AG rmaps.
*/
+ error = init_slab_cursor(ag_rmap->ar_raw_rmaps, rmap_compare, &rm_cur);
+ if (error)
+ goto err;
+ if (!bitmap_init(&own_ag_bitmap)) {
+ error = -ENOMEM;
+ goto err_slab;
+ }
+ while ((rm_rec = pop_slab_cursor(rm_cur)) != NULL) {
+ if (rm_rec->rm_owner != XFS_RMAP_OWN_AG)
+ continue;
+ if (!bitmap_set(own_ag_bitmap, rm_rec->rm_startblock,
+ rm_rec->rm_blockcount)) {
+ error = EFSCORRUPTED;
+ goto err_slab;
+ }
+ }
+ free_slab_cursor(&rm_cur);
+
+ /* Create rmaps for any AGFL blocks that aren't already rmapped. */
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
- b = agfl_bno + ag_rmaps[agno].ar_flcount;
+ b = agfl_bno + ag_rmap->ar_flcount;
while (*b != cpu_to_be32(NULLAGBLOCK) &&
b - agfl_bno < libxfs_agfl_size(mp)) {
- error = rmap_add_ag_rec(mp, agno, be32_to_cpu(*b), 1,
- XFS_RMAP_OWN_AG);
- if (error)
- goto err;
+ xfs_agblock_t agbno;
+
+ agbno = be32_to_cpu(*b);
+ if (!bitmap_test(own_ag_bitmap, agbno, 1)) {
+ error = rmap_add_ag_rec(mp, agno, agbno, 1,
+ XFS_RMAP_OWN_AG);
+ if (error)
+ goto err;
+ }
b++;
}
libxfs_putbuf(agflbp);
agflbp = NULL;
+ bitmap_free(&own_ag_bitmap);
/* Merge all the raw rmaps into the main list */
error = rmap_fold_raw_recs(mp, agno);
@@ -498,8 +531,7 @@ rmap_store_ag_btree_rec(
goto err;
/* Create cursors to refcount structures */
- error = init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare,
- &rm_cur);
+ error = init_slab_cursor(ag_rmap->ar_rmaps, rmap_compare, &rm_cur);
if (error)
goto err;
@@ -542,6 +574,8 @@ rmap_store_ag_btree_rec(
err:
if (agflbp)
libxfs_putbuf(agflbp);
+ if (own_ag_bitmap)
+ bitmap_free(&own_ag_bitmap);
return error;
}