[Ocfs2-tools-devel] [PATCH 4/4] defrag.ocfs2: Clear unused inode groups and extent block

Goldwyn Rodrigues rgoldwyn at gmail.com
Tue Sep 7 20:49:34 PDT 2010


Scans the INODE_ALLOC_SYSTEM_INODE and EXTENT_ALLOC_SYSTEM_INODE
and clears any unused groups. This should get some extent block
groups to free if the previous step ran successfully.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
---
 defrag.ocfs2/Makefile         |    2 +-
 defrag.ocfs2/alloc.c          |  251 +++++++++++++++++++++++++++++++++++++++++
 defrag.ocfs2/defrag.c         |   10 ++
 defrag.ocfs2/include/defrag.h |    1 +
 4 files changed, 263 insertions(+), 1 deletions(-)
 create mode 100644 defrag.ocfs2/alloc.c

diff --git a/defrag.ocfs2/Makefile b/defrag.ocfs2/Makefile
index 685624e..1ff1f1d 100644
--- a/defrag.ocfs2/Makefile
+++ b/defrag.ocfs2/Makefile
@@ -17,7 +17,7 @@ LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a

 CFLAGS += -g

-CFILES =	defrag.c file.c dir.c
+CFILES =	defrag.c file.c dir.c alloc.c

 HFILES = 	include/defrag.h

diff --git a/defrag.ocfs2/alloc.c b/defrag.ocfs2/alloc.c
new file mode 100644
index 0000000..5a3e6dc
--- /dev/null
+++ b/defrag.ocfs2/alloc.c
@@ -0,0 +1,251 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * alloc.c
+ *
+ * Copyright (C) 2010 Novell. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <inttypes.h>
+
+#include "ocfs2/bitops.h"
+#include "defrag.h"
+
+
+extern int verbose;
+extern char *whoami;
+
+static errcode_t cr_clear_unused(ocfs2_filesys *fs, struct ocfs2_chain_rec *cr,
+		int chain_num, int *total, int *used)
+{
+	char *buf = NULL, *pbuf = NULL, *tbuf;
+	struct ocfs2_group_desc *gd = NULL, *pgd = NULL;
+	errcode_t ret = 0;
+	uint64_t blkno = cr->c_blkno;
+	int check_free, check_total;
+
+	if (!blkno)
+		return 0;
+	*total = *used = 0;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret) {
+		com_err(whoami, ret, "while allocating block\n");
+		goto out;
+	}
+	memset(buf, 0, fs->fs_blocksize);
+
+	ret = ocfs2_malloc_block(fs->fs_io, &pbuf);
+	if (ret) {
+		com_err(whoami, ret, "while allocating memory\n");
+		goto out;
+	}
+	memset(pbuf, 0, fs->fs_blocksize);
+
+	check_total = check_free = 0;
+
+	while (blkno) {
+		ret = ocfs2_read_group_desc(fs, blkno, buf);
+		if (ret) {
+			com_err(whoami, ret, "while reading group %"PRIu64"\n",
+					blkno);
+			goto out;
+		}
+		gd = (struct ocfs2_group_desc *)buf;
+
+
+		if (gd->bg_blkno != blkno) {
+			ret = OCFS2_CHAIN_ERROR;
+			goto out;
+		}
+		verbosef("gd blkno:%"PRIu64" free:%d tot:%d\n",
+				(uint64_t) gd->bg_blkno, gd->bg_free_bits_count,
+				gd->bg_bits);
+
+		if ((gd->bg_free_bits_count + 1 == gd->bg_bits) &&
+			ocfs2_test_bit(0, gd->bg_bitmap)) {
+			/* Clear corresponding in global bitmap */
+			verbosef("Freeing blkno %lu bits %u size %u\n",
+					(uint64_t)gd->bg_blkno, gd->bg_bits,
+					gd->bg_size);
+			ret = ocfs2_free_clusters(fs, gd->bg_bits,
+					gd->bg_blkno);
+			if (ret) {
+				com_err(whoami, ret,
+					"while freeing clusters\n");
+				goto out;
+			}
+
+			cr->c_total -= gd->bg_bits;
+			cr->c_free -= gd->bg_free_bits_count;
+			*used += 1;
+			*total += gd->bg_bits;
+			if (pgd) {
+				blkno = pgd->bg_next_group = gd->bg_next_group;
+				/* XXX - Resulting in dual write. Improvise */
+				ret = ocfs2_write_group_desc(fs,
+						pgd->bg_blkno, pbuf);
+				if (ret) {
+					com_err(whoami, ret, "while writing"
+						"group %"PRIu64"\n",
+						(uint64_t) pgd->bg_blkno);
+					goto out;
+				}
+
+			} else
+				blkno = cr->c_blkno = gd->bg_next_group;
+			continue;
+		} else {
+			check_total += gd->bg_bits;
+			check_free += gd->bg_free_bits_count;
+		}
+
+		if (gd->bg_chain != chain_num) {
+			verbosef("Changing chain value of group desc %"PRIu64
+				" from %d to %d\n", (uint64_t)gd->bg_blkno,
+				gd->bg_chain, chain_num);
+			gd->bg_chain = chain_num;
+			ret = ocfs2_write_group_desc(fs, blkno, buf);
+			if (ret) {
+				com_err(whoami, ret, "while writing group %"
+						PRIu64"\n", blkno);
+				goto out;
+			}
+		}
+		/* Swap buf and previous buf */
+		tbuf = pbuf;
+		pbuf = buf;
+		buf = tbuf;
+
+		/* Get the next group desc block number in the chain */
+		pgd = (struct ocfs2_group_desc *)pbuf;
+		blkno = pgd->bg_next_group;
+	}
+
+	if ((check_free != cr->c_free) || (check_total != cr->c_total)) {
+		fprintf(stderr, "Chain rec[%d] count (%d/%d) does not match "
+			"with calculated (%d/%d)", chain_num, cr->c_free,
+			cr->c_total, check_free, check_total);
+		ret = OCFS2_CHAIN_ERROR;
+	}
+out:
+	if (buf)
+		ocfs2_free(&buf);
+	if (pbuf)
+		ocfs2_free(&pbuf);
+	return ret;
+}
+
+
+static errcode_t clear_unused_regions(ocfs2_filesys *fs, uint64_t blkno)
+{
+	char *buf = NULL;
+	struct ocfs2_dinode *inode;
+	int n, i;
+	errcode_t ret = 0;
+	struct ocfs2_chain_list *cl = &inode->id2.i_chain;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		return ret;
+	verbosef("Reading inode: %"PRIu64"\n", blkno);
+	ret = ocfs2_read_inode(fs, blkno, buf);
+	if (ret) {
+		com_err(whoami, ret, "while reading inode %"PRIu64"\n",
+				blkno);
+		goto out_buf;
+	}
+
+	inode = (struct ocfs2_dinode *)buf;
+
+	ret = OCFS2_ET_INODE_NOT_VALID;
+	if (!(inode->i_flags & OCFS2_VALID_FL)) {
+		printf("Allocator inode %"PRIu64" not active\n", blkno);
+		goto out_buf;
+	}
+
+	if (!(inode->i_flags & OCFS2_CHAIN_FL)) {
+		fprintf(stderr, "Allocator inode %"PRIu64" not a valid chain\n",
+				blkno);
+		goto out_buf;
+	}
+
+	cl = &inode->id2.i_chain;
+	n = cl->cl_next_free_rec;
+
+	verbosef("Total chain recs to process: %d cpg:%d\n",
+			n, cl->cl_cpg);
+	i = 0;
+	while (i < n) {
+		struct ocfs2_chain_rec *cr = &cl->cl_recs[i];
+		int total = 0, used = 0;
+		ret = cr_clear_unused(fs, cr, i, &total, &used);
+		if (ret)
+			goto out;
+		/* Update inode parameters with the cleared regions */
+		inode->id1.bitmap1.i_used -= used;
+		inode->id1.bitmap1.i_total -= total;
+		verbosef("cr i:%d blkno:%"PRIu64" tot:%d free:%d\n", i,
+				(uint64_t)cr->c_blkno, cr->c_total, cr->c_free);
+
+		if (cr->c_blkno == 0) {
+			/* Move the last rec to current position
+			   and process it next*/
+			cl->cl_recs[i] = cl->cl_recs[n-1];
+			memset(&cl->cl_recs[n-1], 0,
+					sizeof(struct ocfs2_chain_rec));
+			n--;
+		} else
+			i++;
+	}
+	cl->cl_next_free_rec = n;
+
+out:
+	/* Correct the rest of inode values */
+	inode->i_clusters = inode->id1.bitmap1.i_total / cl->cl_bpc;
+	inode->i_size = inode->i_clusters * fs->fs_clustersize;
+	ret = ocfs2_write_inode(fs, blkno, buf);
+out_buf:
+	if (buf)
+		ocfs2_free(&buf);
+	return ret;
+
+}
+
+/* Clears all unused inode groups and block groups */
+errcode_t allocators_clear_unused(struct defrag_state *dst)
+{
+	int slot, max_slots = OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_max_slots;
+	errcode_t ret = 0;
+	uint64_t blkno;
+
+	for (slot = 0; slot < max_slots; slot++) {
+		ret = ocfs2_lookup_system_inode(dst->dst_fs,
+				INODE_ALLOC_SYSTEM_INODE, slot, &blkno);
+		if (ret) {
+			com_err(whoami, ret, "while looking up system inode\n");
+			return ret;
+		}
+		verbosef("Inode allocator[%d] -\n", slot);
+		clear_unused_regions(dst->dst_fs, blkno);
+		ret = ocfs2_lookup_system_inode(dst->dst_fs,
+				EXTENT_ALLOC_SYSTEM_INODE, slot, &blkno);
+		if (ret) {
+			com_err(whoami, ret, "while looking up system inode\n");
+			return ret;
+		}
+		verbosef("Extent allocator[%d] -\n", slot);
+		clear_unused_regions(dst->dst_fs, blkno);
+	}
+	return ret;
+}
+
diff --git a/defrag.ocfs2/defrag.c b/defrag.ocfs2/defrag.c
index 6b9ddd8..349d18a 100644
--- a/defrag.ocfs2/defrag.c
+++ b/defrag.ocfs2/defrag.c
@@ -339,6 +339,16 @@ int main(int argc, char **argv)
 		    goto close;
 		}
 	}
+	if (dst->pass2) {
+		printf("Pass 2: Clear unused allocators\n");
+		ret = allocators_clear_unused(dst);
+		if (ret) {
+			fprintf(stderr, "Error while clearing allocators\n"
+					"Please execute fsck.ocfs2\n");
+			retval |= DEFRAG_ERROR;
+			goto close;
+		}
+	}

 close:
 	block_signals(SIG_BLOCK);
diff --git a/defrag.ocfs2/include/defrag.h b/defrag.ocfs2/include/defrag.h
index e0f1331..03c1ed0 100644
--- a/defrag.ocfs2/include/defrag.h
+++ b/defrag.ocfs2/include/defrag.h
@@ -44,6 +44,7 @@ extern int verbose;
 errcode_t defrag_files_and_dirs(struct defrag_state *dst);
 errcode_t defrag_file(struct defrag_state *dst, struct ocfs2_dinode *);
 errcode_t defrag_dir(struct defrag_state *dst, struct ocfs2_dinode *);
+errcode_t allocators_clear_unused(struct defrag_state *dst);

 #endif /* __OCFS2_DEFRAG_H__ */

-- 
1.7.1


-- 
Goldwyn



More information about the Ocfs2-tools-devel mailing list