[Ocfs2-tools-devel] [PATCH 1/4] defrag.ocfs2: Basic framework borrowed from fsck.ocfs2

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


Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
---
 defrag.ocfs2/Makefile         |   36 +++++
 defrag.ocfs2/defrag.c         |  345 +++++++++++++++++++++++++++++++++++++++++
 defrag.ocfs2/include/defrag.h |   45 ++++++
 3 files changed, 426 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..2079d0c
--- /dev/null
+++ b/defrag.ocfs2/Makefile
@@ -0,0 +1,36 @@
+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
+LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm $(DL_LIBS)
+LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a
+LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb
+LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.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) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS)
+	$(LINK) $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(COM_ERR_LIBS)
+
+include $(TOPDIR)/Postamble.make
diff --git a/defrag.ocfs2/defrag.c b/defrag.ocfs2/defrag.c
new file mode 100644
index 0000000..4238a4a
--- /dev/null
+++ b/defrag.ocfs2/defrag.c
@@ -0,0 +1,345 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+   * vim: noexpandtab sw=8 ts=8 sts=0:
+   *
+   * defrag.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 <getopt.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "defrag.h"
+
+
+int verbose = 0;
+char *whoami = "defrag.ocfs2";
+static struct defrag_state dfrag;
+static int cluster_locked = 0;
+
+extern int opterr, optind;
+extern char *optarg;
+
+static void handle_signal(int sig)
+{
+	switch (sig) {
+		case SIGTERM:
+		case SIGINT:
+			printf("\nProcess Interrupted.\n");
+
+			if (cluster_locked && dfrag.dst_fs->fs_dlm_ctxt) {
+				ocfs2_release_cluster(dfrag.dst_fs);
+				cluster_locked = 0;
+			}
+
+			if (dfrag.dst_fs->fs_dlm_ctxt)
+				ocfs2_shutdown_dlm(dfrag.dst_fs, whoami);
+
+			if (dfrag.dst_fs)
+				ocfs2_close(dfrag.dst_fs);
+
+			exit(1);
+	}
+
+	return ;
+}
+
+/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock */
+static void block_signals(int how)
+{
+	sigset_t sigs;
+
+	sigfillset(&sigs);
+	sigdelset(&sigs, SIGTRAP);
+	sigdelset(&sigs, SIGSEGV);
+	sigprocmask(how, &sigs, NULL);
+}
+
+
+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);
+	fprintf(stdout, "WARNING: Unstable version.\n");
+}
+
+static void print_help(void)
+{
+	fprintf(stderr, "Usage: %s [-hvV] 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;
+	}
+
+	if (ret) {
+		printf("Unrecoverable errors in the super block."
+				"Cannot continue.\n");
+		goto out;
+	}
+
+	dst->fs_generation = dst->dst_fs->fs_super->i_fs_generation;
+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, "12FvVh")) != EOF) {
+		switch (c) {
+			case '1':
+				dst->pass1 = 1;
+				break;
+			case '2':
+				dst->pass2 = 1;
+				break;
+			case 'F':
+				dst->skip_o2cb = 1;
+				break;
+			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)) {
+		fprintf(stdout, "\n Running defrag.ocfs2 on a "
+			"mounted filesystem will cause filesystem "
+			"damage.\n\n");
+		retval |= DEFRAG_ERROR;
+		goto out;
+	}
+
+	if (signal(SIGTERM, handle_signal) == SIG_ERR) {
+		com_err(whoami, 0, "Could not set SIGTERM");
+		exit(1);
+	}
+
+	if (signal(SIGINT, handle_signal) == SIG_ERR) {
+		com_err(whoami, 0, "Could not set SIGINT");
+		exit(1);
+	}
+
+	ret = open_and_check(dst, filename, open_flags, blkno, blksize);
+	if (ret) {
+		retval |= DEFRAG_ERROR;
+		goto out;
+	}
+
+	if (!dst->skip_o2cb && !ocfs2_mount_local(dst->dst_fs)) {
+		ret = o2cb_init();
+		if (ret) {
+			com_err(whoami, ret, "while initializing the cluster");
+			goto out_no_dlm;
+		}
+
+		block_signals(SIG_BLOCK);
+		ret = ocfs2_initialize_dlm(dst->dst_fs, whoami);
+		if (ret == O2CB_ET_INVALID_STACK_NAME) {
+			com_err(whoami, ret,
+				"while initializing DLM");
+			goto out_no_dlm;
+		}
+
+		ret = ocfs2_lock_down_cluster(dst->dst_fs);
+		if (ret) {
+			block_signals(SIG_UNBLOCK);
+			com_err(whoami, ret, "while locking down the cluster");
+			goto close;
+		}
+		cluster_locked = 1;
+		block_signals(SIG_UNBLOCK);
+	}
+
+	printf("  De-fragmenting 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 close;
+	}
+
+	if (!(dst->pass1 || dst->pass2))
+		dst->pass1 = dst->pass2 = 1;
+
+close:
+	block_signals(SIG_BLOCK);
+	if (dst->dst_fs->fs_dlm_ctxt)
+		ocfs2_shutdown_dlm(dst->dst_fs, whoami);
+	block_signals(SIG_UNBLOCK);
+out_no_dlm:
+	ret = ocfs2_close(dst->dst_fs);
+	if (ret) {
+		com_err(whoami, ret, "while closing file \"%s\"", filename);
+		retval |= DEFRAG_ERROR;
+	}
+out:
+	return retval;
+}
diff --git a/defrag.ocfs2/include/defrag.h b/defrag.ocfs2/include/defrag.h
new file mode 100644
index 0000000..536b6b3
--- /dev/null
+++ b/defrag.ocfs2/include/defrag.h
@@ -0,0 +1,45 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * defrag.h
+ *
+ * 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.
+ */
+
+#ifndef __OCFS2_DEFRAG_H__
+#define __OCFS2_DEFRAG_H__
+
+#include "ocfs2/ocfs2.h"
+
+#define DEFRAG_OK			0
+#define DEFRAG_USAGE			1
+#define DEFRAG_ERROR			2
+#define DEFRAG_EXTENTS_EXCEEDED		3
+
+struct defrag_state {
+	ocfs2_filesys *dst_fs;
+	int max_esize;
+	int fs_generation;
+	int num_inodes;
+	unsigned skip_o2cb:1;
+	unsigned pass1:1;
+	unsigned pass2:1;
+};
+
+extern int verbose;
+#define verbosef(fmt, args...) do {					\
+	if (verbose)							\
+		printf("%s:%d | " fmt, __FUNCTION__, __LINE__, args);\
+} while (0)
+
+#endif /* __OCFS2_DEFRAG_H__ */
+
-- 
1.7.1


-- 
Goldwyn



More information about the Ocfs2-tools-devel mailing list