[PATCH 4/4] xfs_repair: unconditionally free blockmaps when threads complete

Eric Sandeen
2015-08-20T18:11:22Z

blkmap_free() doesn't actually free the block map unless it's
inordinately large; this keeps us from constantly freeing
and re-allocating blockmaps for each inode, which makes sense.

However, once the threads which have allocated these structures
exit, we should actually free them; they can grow up to 2MB
for each of the data and attr maps, for each thread, and not
be freed through the normal blkmap_free() test.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
repair/bmap.c | 17 ++++++++++++++++-
repair/bmap.h | 1 +
repair/phase3.c | 2 ++
repair/phase4.c | 1 +
4 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/repair/bmap.c b/repair/bmap.c
index 2655632..abe9f48 100644
--- a/repair/bmap.c
+++ b/repair/bmap.c
@@ -82,7 +82,8 @@ blkmap_alloc(
* extents) then free it to release the memory. This prevents us from pinning
* large tracts of memory due to corrupted fork values or one-off fragmented
* files. Otherwise we have nothing to do but keep the memory around for the
- * next inode
+ * next inode.
+ * When the thread is done, it should do an unconditional, final free.
*/
void
blkmap_free(
@@ -103,6 +104,20 @@ blkmap_free(
free(blkmap);
}

+void
+blkmap_free_final(void)
+{
+ blkmap_t *blkmap;
+
+ blkmap = pthread_getspecific(dblkmap_key);
+ pthread_setspecific(dblkmap_key, NULL);
+ free(blkmap);
+
+ blkmap = pthread_getspecific(ablkmap_key);
+ pthread_setspecific(ablkmap_key, NULL);
+ free(blkmap);
+}
+
/*
* Get one entry from a block map.
*/
diff --git a/repair/bmap.h b/repair/bmap.h
index 973081a..501ef6b 100644
--- a/repair/bmap.h
+++ b/repair/bmap.h
@@ -58,6 +58,7 @@ extern pthread_key_t ablkmap_key;

blkmap_t *blkmap_alloc(xfs_extnum_t nex, int whichfork);
void blkmap_free(blkmap_t *blkmap);
+void blkmap_free_final(void);

int blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o,
xfs_fsblock_t b, xfs_filblks_t c);
diff --git a/repair/phase3.c b/repair/phase3.c
index 20786af..76c9440 100644
--- a/repair/phase3.c
+++ b/repair/phase3.c
@@ -27,6 +27,7 @@
#include "err_protos.h"
#include "dinode.h"
#include "progress.h"
+#include "bmap.h"

static void
process_agi_unlinked(
@@ -75,6 +76,7 @@ process_ag_func(
wait_for_inode_prefetch(arg);
do_log(_(" - agno = %d\n"), agno);
process_aginodes(wq->mp, arg, agno, 1, 0, 1);
+ blkmap_free_final();
cleanup_inode_prefetch(arg);
}

diff --git a/repair/phase4.c b/repair/phase4.c
index e0571e8..1a7d7b5 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -138,6 +138,7 @@ process_ag_func(
wait_for_inode_prefetch(arg);
do_log(_(" - agno = %d\n"), agno);
process_aginodes(wq->mp, arg, agno, 0, 1, 0);
+ blkmap_free_final();
cleanup_inode_prefetch(arg);