[Ocfs2-tools-devel] [PATCH 1/2] defrag.ocfs2: Borrow basic structure from fsck

Goldwyn Rodrigues rgoldwyn at gmail.com
Sat Feb 20 18:47:43 PST 2010


A new tool to defrag the filesystem in offline mode. This patchset
deletes the unused inode groups from the inode allocators.

Comments on this patchset and ideas on proceeding further welcome.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>

---
 defrag.ocfs2/Makefile         |   37 ++++++
 defrag.ocfs2/defrag.c         |  271 +++++++++++++++++++++++++++++++++++++++++
 defrag.ocfs2/include/defrag.h |   46 +++++++
 3 files changed, 354 insertions(+), 0 deletions(-)
 create mode 100644 defrag.ocfs2/Makefile
 create mode 100644 defrag.ocfs2/defrag.c
 create mode 100644 defrag.ocfs2/include/defrag.h

diff --git a/defrag.ocfs2/Makefile b/defrag.ocfs2/Makefile
new file mode 100644
index 0000000..b59c6a4
--- /dev/null
+++ b/defrag.ocfs2/Makefile
@@ -0,0 +1,37 @@
+TOPDIR = ..
+
+include $(TOPDIR)/Preamble.make
+
+sbindir = $(root_sbindir)
+SBIN_PROGRAMS = defrag.ocfs2
+
+DEFINES += -DVERSION=\"$(VERSION)\"
+
+INCLUDES = -I$(TOPDIR)/include -Iinclude -I$(TOPDIR)/libocfs2
+LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
+LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
+
+CFLAGS += -g
+
+CFILES =	defrag.c
+
+HFILES = 	include/defrag.h
+
+
+OBJS = $(subst .c,.o,$(CFILES))
+
+DIST_FILES = $(CFILES) $(HFILES) $(addsuffix .in,$(MANS))
+DIST_RULES = dist-subdircreate
+
+dist-subdircreate:
+	$(TOPDIR)/mkinstalldirs $(DIST_DIR)/include
+
+defrag.ocfs2: $(OBJS) $(LIBOCFS2_DEPS)
+	$(LINK) $(LIBOCFS2_LIBS) $(COM_ERR_LIBS)
+
+CLEAN_RULES += defrag-clean
+.PHONY: defrag-clean
+defrag-clean:
+	rm -f prompt-codes.h
+
+include $(TOPDIR)/Postamble.make
diff --git a/defrag.ocfs2/defrag.c b/defrag.ocfs2/defrag.c
new file mode 100644
index 0000000..ad97d81
--- /dev/null
+++ b/defrag.ocfs2/defrag.c
@@ -0,0 +1,271 @@
+/* -*- 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"
+
+
+int verbose = 0;
+char *whoami = "defrag.ocfs2";
+static struct defrag_state dfrag;
+
+extern int opterr, optind;
+extern char *optarg;
+
+static errcode_t check_superblock(struct defrag_state *dst)
+{
+	struct ocfs2_dinode *di = dst->dst_fs->fs_super;
+	struct ocfs2_super_block *sb = OCFS2_RAW_SB(di);
+	errcode_t ret = 0;
+
+	if (sb->s_max_slots == 0) {
+		printf("The superblock max_slots field is set to 0.\n");
+		ret = OCFS2_ET_CORRUPT_SUPERBLOCK;
+	}
+
+	return ret;
+}
+
+static void scale_time(time_t secs, unsigned *scaled, char **units)
+{
+	if (secs < 60) {
+		*units = "seconds";
+		goto done;
+	}
+	secs /= 60;
+
+	if (secs < 60) {
+		*units = "minutes";
+		goto done;
+	}
+	secs /= 60;
+
+	if (secs < 24) {
+		*units = "hours";
+		goto done;
+	}
+	secs /= 24;
+	*units = "days";
+
+done:
+	*scaled = secs;
+}
+
+static int fs_clean(struct ocfs2_super_block *sb, char *filename)
+{
+	time_t now = time(NULL);
+	time_t next = sb->s_lastcheck + sb->s_checkinterval;
+
+	if (sb->s_checkinterval > 0 && now >= next) {
+		unsigned scaled_time;
+		char *scaled_units;
+
+		scale_time(now - sb->s_lastcheck, &scaled_time, &scaled_units);
+		fprintf(stderr, "Filesystem has gone %u %s without"
+				"being checked\n", scaled_time, scaled_units);
+		return 0;
+	}
+
+	if (sb->s_mnt_count > 0) {
+		fprintf(stderr, "Filesystem mounted for %u mounts without fsck. ",
+			sb->s_mnt_count);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void print_label(struct defrag_state *dst)
+{
+	unsigned char *label = OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_label;
+	size_t i, max = sizeof(OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_label);
+
+	for(i = 0; i < max && label[i]; i++) {
+		if (isprint(label[i]))
+			printf("%c", label[i]);
+		else
+			printf(".");
+	}
+	if (i == 0)
+		printf("<NONE>");
+
+	printf("\n");
+}
+
+static void print_uuid(struct defrag_state *dst)
+{
+	unsigned char *uuid = OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_uuid;
+	size_t i, max = sizeof(OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_uuid);
+
+	for(i = 0; i < max; i++)
+		printf("%02x ", uuid[i]);
+
+	printf("\n");
+}
+
+static void print_version(void)
+{
+	fprintf(stderr, "%s %s\n", whoami, VERSION);
+}
+
+static void print_help(void)
+{
+	fprintf(stderr, "Usage: %s [-vVp] [ -i <inode numer> device\n", whoami);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "-h\t\t Print this help\n");
+	fprintf(stderr, "-v\t\t Verbose output\n");
+	fprintf(stderr, "-V\t\t Print version information\n");
+}
+
+static errcode_t open_and_check(struct defrag_state *dst, char *filename,
+				int open_flags, uint64_t blkno,
+				uint64_t blksize)
+{
+	errcode_t ret;
+
+	ret = ocfs2_open(filename, open_flags, blkno, blksize, &dst->dst_fs);
+	if (ret) {
+		com_err(whoami, ret, "while opening \"%s\"", filename);
+		goto out;
+	}
+
+	ret = check_superblock(dst);
+	if (ret) {
+		printf("Unrecoverable errors in the super block. Cannot continue.\n");
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	char *filename;
+	int64_t blkno, blksize;
+	struct defrag_state *dst = &dfrag;
+	int c, open_flags = OCFS2_FLAG_RW | OCFS2_FLAG_STRICT_COMPAT_CHECK;
+	int retval = DEFRAG_OK;
+	errcode_t ret;
+	int mount_flags;
+
+	memset(dst, 0, sizeof(struct defrag_state));
+
+	/* These mean "autodetect" */
+	blksize = 0;
+	blkno = 0;
+
+	initialize_ocfs_error_table();
+	setlinebuf(stderr);
+	setlinebuf(stdout);
+
+	while((c = getopt(argc, argv, "vVphi:")) != EOF) {
+		switch (c) {
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				print_version();
+				exit(DEFRAG_USAGE);
+				break;
+			case 'h':
+				print_help();
+				exit(0);
+				break;
+
+			default:
+				retval |= DEFRAG_USAGE;
+				print_help();
+				goto out;
+				break;
+		}
+	}
+
+	if (optind >= argc) {
+		fprintf(stderr, "Missing filename\n");
+		retval |= DEFRAG_USAGE;
+		print_help();
+		goto out;
+	}
+
+	filename = argv[optind];
+	print_version();
+
+	ret = ocfs2_check_if_mounted(filename, &mount_flags);
+	if (ret) {
+		com_err(whoami, ret, "while determining whether %s is mounted.",
+				filename);
+		retval |= DEFRAG_ERROR;
+		goto out;
+	}
+
+	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");
+		else
+			fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 on a "
+					"mounted filesystem may cause SEVERE "
+					"filesystem damage.\n\n");
+	}
+
+	ret = open_and_check(dst, filename, open_flags, blkno, blksize);
+	if (ret) {
+		retval |= DEFRAG_ERROR;
+		goto out;
+	}
+
+	printf("Checking OCFS2 filesystem in %s:\n", filename);
+	printf("  label:              ");
+	print_label(dst);
+	printf("  uuid:               ");
+	print_uuid(dst);
+	printf("  number of blocks:   %"PRIu64"\n", dst->dst_fs->fs_blocks);
+	printf("  bytes per block:    %u\n", dst->dst_fs->fs_blocksize);
+	printf("  number of clusters: %"PRIu32"\n", dst->dst_fs->fs_clusters);
+	printf("  bytes per cluster:  %u\n", dst->dst_fs->fs_clustersize);
+	printf("  max slots:          %u\n\n",
+			OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_max_slots);
+	printf(" System dir block number - %lu\n", dst->dst_fs->fs_sysdir_blkno);
+	printf(" Root dir block number - %lu\n", dst->dst_fs->fs_root_blkno);
+	printf(" FS blocks - %lu\n", dst->dst_fs->fs_blocks);
+
+	if (!fs_clean(OCFS2_RAW_SB(dst->dst_fs->fs_super), filename)) {
+		fprintf(stderr, "Please run fsck.ocfs2 before performing defrag\n");
+		retval = DEFRAG_ERROR;
+		goto out;
+	}
+	ocfs2_write_super(dst->dst_fs);
+	ocfs2_close(dst->dst_fs);
+	
+out:
+	return retval;
+}
diff --git a/defrag.ocfs2/include/defrag.h b/defrag.ocfs2/include/defrag.h
new file mode 100644
index 0000000..7c25e89
--- /dev/null
+++ b/defrag.ocfs2/include/defrag.h
@@ -0,0 +1,46 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * defrag.h
+ *
+ * Copyright (C) 2002 Oracle Corporation.  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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __OCFS2_DEFRAG_H__
+#define __OCFS2_DEFRAG_H__
+
+#include "ocfs2/ocfs2.h"
+
+#define DEFRAG_OK	0
+#define DEFRAG_USAGE	1
+#define DEFRAG_ERROR	2
+
+struct defrag_state {
+	ocfs2_filesys 	*dst_fs;
+};
+
+extern int verbose;
+#define verbosef(fmt, args...) do {					\
+	if (verbose)							\
+		printf("%s:%d | " fmt, __FUNCTION__, __LINE__, args);\
+} while (0)
+
+
+#endif /* __OCFS2_DEFRAG_H__ */
+
-- 
1.6.4.2


-- 
Goldwyn



More information about the Ocfs2-tools-devel mailing list