[Ocfs2-tools-devel] [PATCH 2/4] Clear unallocated inode groups
Goldwyn Rodrigues
rgoldwyn at gmail.com
Wed Mar 17 18:28:14 PDT 2010
Clears all inode groups which have no allocated inodes, freeing
space in the global_bitmap
Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
---
Makefile | 2 +-
defrag.ocfs2/Makefile | 2 +-
defrag.ocfs2/alloc.c | 230 +++++++++++++++++++++++++++++++++++++++++
defrag.ocfs2/defrag.c | 21 +++-
defrag.ocfs2/include/defrag.h | 4 +-
5 files changed, 250 insertions(+), 9 deletions(-)
create mode 100644 defrag.ocfs2/alloc.c
diff --git a/Makefile b/Makefile
index 88106fb..ecb56dc 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ CHKCONFIG_DEP = chkconfig
COMPILE_PY = 1
endif
-SUBDIRS = include libtools-internal libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image listuuid sizetest extras fswreck patches
+SUBDIRS = include libtools-internal libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image listuuid sizetest extras fswreck patches defrag.ocfs2
ifdef BUILD_OCFS2CONSOLE
SUBDIRS += ocfs2console
diff --git a/defrag.ocfs2/Makefile b/defrag.ocfs2/Makefile
index b59c6a4..8bc48e0 100644
--- a/defrag.ocfs2/Makefile
+++ b/defrag.ocfs2/Makefile
@@ -13,7 +13,7 @@ LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
CFLAGS += -g
-CFILES = defrag.c
+CFILES = defrag.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..7eb7079
--- /dev/null
+++ b/defrag.ocfs2/alloc.c
@@ -0,0 +1,230 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 1993-2004 Theodore Ts'o.
+ * Copyright (C) 2004 Oracle. 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+#include <getopt.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <libgen.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)
+ return ret;
+ memset(buf, 0, fs->fs_blocksize);
+
+ ret = ocfs2_malloc_block(fs->fs_io, &pbuf);
+ if (ret)
+ return ret;
+ memset(pbuf, 0, fs->fs_blocksize);
+
+ check_total = check_free = 0;
+
+ while (blkno) {
+ ret = ocfs2_read_group_desc(fs, blkno, buf);
+ if (ret)
+ 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) &&
+ (gd->bg_bitmap[0] == 1)) {
+ /* Clear corresponding in global bitmap */
+ ret = ocfs2_free_clusters(fs, gd->bg_bits, gd->bg_blkno);
+ if (ret)
+ return ret;
+
+ cr->c_total -= gd->bg_bits;
+ cr->c_free -= gd->bg_free_bits_count;
+ *used += 1;
+ *total += gd->bg_bits;
+ if (pgd) {
+ 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)
+ goto out;
+
+ } else
+ cr->c_blkno = gd->bg_next_group;
+ } 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)
+ 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)
+ 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)) {
+ printf("Allocator inode %"PRIu64" not a valid chain\n", blkno);
+ goto out_buf;
+ }
+
+ cl = &inode->id2.i_chain;
+ n = ocfs2_chain_recs_per_inode(fs->fs_blocksize);
+ n--;
+ while ((cl->cl_recs[n].c_blkno == 0) && (n > 0))
+ n--;
+ verbosef("Total chain recs to process: %d next_free:%d\n",
+ n, cl->cl_next_free_rec);
+
+ 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];
+ memset(&cl->cl_recs[n], 0,
+ sizeof(struct ocfs2_chain_rec));
+ n--;
+ } else
+ i++;
+ }
+ cl->cl_next_free_rec = n+1;
+
+out:
+ /* Correct the rest of inode values */
+ inode->i_clusters = inode->id1.bitmap1.i_total;
+ 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)
+ return ret;
+ verbosef("Inode 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 cf81aa6..22b71d7 100644
--- a/defrag.ocfs2/defrag.c
+++ b/defrag.ocfs2/defrag.c
@@ -132,6 +132,7 @@ static void print_uuid(struct defrag_state *dst)
static void print_version(void)
{
fprintf(stderr, "%s %s\n", whoami, VERSION);
+ fprintf(stdout, "WARNING: Unstable version.\n");
}
static void print_help(void)
@@ -229,13 +230,13 @@ int main(int argc, char **argv)
if (mount_flags & (OCFS2_MF_MOUNTED | OCFS2_MF_BUSY)) {
if (!(open_flags & OCFS2_FLAG_RW))
- fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 (read-"
- "only) on a mounted filesystem may detect "
- "invalid errors.\n\n");
+ fprintf(stdout, "\nWARNING!!! Running defrag.ocfs2 "
+ "(read-only) on a mounted filesystem "
+ "may corrupt the filesystem.\n\n");
else
- fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 on a "
- "mounted filesystem may cause SEVERE "
- "filesystem damage.\n\n");
+ fprintf(stdout, "\nWARNING!!! Running defrag.ocfs2 on"
+ " a mounted filesystem may cause "
+ "SEVERE filesystem damage.\n\n");
}
ret = open_and_check(dst, filename, open_flags, blkno, blksize);
@@ -265,6 +266,14 @@ int main(int argc, char **argv)
retval = DEFRAG_ERROR;
goto out;
}
+ printf("Pass 1: Clearing unused groups in Allocators\n");
+ ret = allocators_clear_unused(dst);
+ if (ret) {
+ fprintf(stderr, "Error while clearing unused inode groups\n"
+ "Please execute fsck.ocfs2\n");
+ retval |= DEFRAG_ERROR;
+ }
+
ocfs2_write_super(dst->dst_fs);
ocfs2_close(dst->dst_fs);
diff --git a/defrag.ocfs2/include/defrag.h b/defrag.ocfs2/include/defrag.h
index 7c25e89..e845893 100644
--- a/defrag.ocfs2/include/defrag.h
+++ b/defrag.ocfs2/include/defrag.h
@@ -1,7 +1,7 @@
/* -*- mode: c; c-basic-offset: 8; -*-
* vim: noexpandtab sw=8 ts=8 sts=0:
*
- * defrag.h
+ * fsck.h
*
* Copyright (C) 2002 Oracle Corporation. All rights reserved.
*
@@ -42,5 +42,7 @@ extern int verbose;
} while (0)
+errcode_t allocators_clear_unused(struct defrag_state *);
+
#endif /* __OCFS2_DEFRAG_H__ */
--
1.6.4.2
--
Goldwyn
More information about the Ocfs2-tools-devel
mailing list