[Ocfs2-tools-devel] [PATCH 1/4] Borrow basic structure from fsck

tristan tristan.ye at oracle.com
Thu Mar 18 20:17:24 PDT 2010


Hi goldwyn,

Comments inlined;)

Goldwyn Rodrigues wrote:
> Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
>
> ---
>  defrag.ocfs2/Makefile         |   37 ++++++
>  defrag.ocfs2/defrag.c         |  273 +++++++++++++++++++++++++++++++++++++++++
>  defrag.ocfs2/include/defrag.h |   46 +++++++
>  3 files changed, 356 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
Oh, you're required to add a manual help txt when it goes to a stable 
version;)

It's more likely to be a TO-DO task, just a reminder.

> +
> +
> +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

oh, such a extra cleanup is not necessary for defrag.ocfs2, since we're 
not going to remove a prompt-codes.h like fsck.ocfs2.

> +
> +include $(TOPDIR)/Postamble.make
> diff --git a/defrag.ocfs2/defrag.c b/defrag.ocfs2/defrag.c
> new file mode 100644
> index 0000000..cf81aa6
> --- /dev/null
> +++ b/defrag.ocfs2/defrag.c
> @@ -0,0 +1,273 @@
> +/* -*- 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.

Use the latest GPL license as:

/* -*- mode: c; c-basic-offset: 8; -*-
* vim: noexpandtab sw=8 ts=8 sts=0:
*
* defrag.c
*
* Copyright (C) 2010 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.
*/


> + *
> + */
> +#include <getopt.h>
> +#include <limits.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <inttypes.h>
> +#include <signal.h>
> +#include <libgen.h>

Do you really want to use following headers?

#include <limits.h>
#include <stdint.h>
#include <string.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;
> +}

Oh, I realised that you may follow exactly the same rules as fsck.ocfs2 
to determine if a fs is clean or not, since you've been learning partly 
from it already;)

> +
> +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);

What were '-p' and '-i' used for? I didn't saw any handling on this.

> +	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");
> +	}+

Here you're learning everything from fsck.ocfs2, so why not do the same 
thing as fsck:

1. prompt the user to determine if they want to continue

2. If so, lock down the cluster.

> +	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);
Do you really want to write back the superblock here? since I didn't see 
any explicit changes being made for superblock.

> +	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.
> + *
> + */
Oh, the same issue of license.

> +
> +#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__ */
> +

Oh, I suddenly realised you're missing to handle some interrupts like 
SIGINT and SIGTERM, they need to be well setuped, and some cleanup works 
like ocfs2_close() need to be done in the handler.




More information about the Ocfs2-tools-devel mailing list