[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