[Ocfs2-tools-devel] [PATCH 3/4] Adds o2image tool

Sunil Mushran Sunil.Mushran at oracle.com
Mon May 5 14:13:01 PDT 2008


Other than the trivial alignment issue, there are issues in the 
prompt_image_creation(). Those comments have been inlined.


Align the code properly.

For e.g., instead of:
+static errcode_t traverse_group_desc(ocfs2_filesys *ofs,
+		struct ocfs2_group_desc *grp, int dump_type)

do:

+static errcode_t traverse_group_desc(ocfs2_filesys *ofs,
+				      struct ocfs2_group_desc *grp,
+				      int dump_type)


or:
+	fprintf(stderr, ("Usage: %s [-rI] device image_file\n"),
+			program_name);

should be:

+	fprintf(stderr, ("Usage: %s [-rI] device image_file\n"),
+		program_name);



Srinivas Eeda wrote:
> This patch adds o2image tool. A tool that can be used to save restore
> critical ocfs2 filesystem metadata.
>
> The patch also adds man pages and other build related changes
>
> Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com>
> ---
>  Makefile                                  |    2 +-
>  configure.in                              |    1 +
>  debian/ocfs2-tools.manpages               |    1 +
>  o2image/Makefile                          |   37 ++
>  o2image/o2image.8.in                      |   59 +++
>  o2image/o2image.c                         |  677 +++++++++++++++++++++++++++++
>  vendor/common/ocfs2-tools.spec-generic.in |    2 +
>  7 files changed, 778 insertions(+), 1 deletions(-)
>  create mode 100644 o2image/Makefile
>  create mode 100644 o2image/o2image.8.in
>  create mode 100644 o2image/o2image.c
>
> diff --git a/Makefile b/Makefile
> index d5c56fa..38e0b06 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -20,7 +20,7 @@ CHKCONFIG_DEP = chkconfig
>  COMPILE_PY = 1
>  endif
>  
> -SUBDIRS = include libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2cdsl listuuid sizetest extras patches
> +SUBDIRS = include libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2cdsl o2image listuuid sizetest extras patches
>  
>  ifdef BUILD_OCFS2CONSOLE
>  SUBDIRS += ocfs2console
> diff --git a/configure.in b/configure.in
> index d3bf6bc..ee8bfa1 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -247,6 +247,7 @@ ocfs2_hb_ctl/ocfs2_hb_ctl.8
>  ocfs2cdsl/ocfs2cdsl.8
>  ocfs2console/ocfs2console.8
>  tunefs.ocfs2/tunefs.ocfs2.8
> +o2image/o2image.8
>  vendor/common/ocfs2-tools.spec-generic
>  ])
>  
> diff --git a/debian/ocfs2-tools.manpages b/debian/ocfs2-tools.manpages
> index 59e95e1..8e46efc 100644
> --- a/debian/ocfs2-tools.manpages
> +++ b/debian/ocfs2-tools.manpages
> @@ -7,3 +7,4 @@ debian/tmp/usr/share/man/man8/mounted.ocfs2.8
>  debian/tmp/usr/share/man/man8/o2cb_ctl.8
>  debian/tmp/usr/share/man/man8/ocfs2_hb_ctl.8
>  debian/tmp/usr/share/man/man8/ocfs2cdsl.8
> +debian/tmp/usr/share/man/man8/o2image.8
> diff --git a/o2image/Makefile b/o2image/Makefile
> new file mode 100644
> index 0000000..0259161
> --- /dev/null
> +++ b/o2image/Makefile
> @@ -0,0 +1,37 @@
> +TOPDIR = ..
> +
> +include $(TOPDIR)/Preamble.make
> +
> +WARNINGS = -Wall -Wstrict-prototypes -Wno-format -Wmissing-prototypes \
> +           -Wmissing-declarations
> +
> +CFLAGS = $(OPTS) $(WARNINGS)
> +
> +LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
> +LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
> +
> +LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm
> +LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a
> +
> +LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb
> +LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a
> +
> +sbindir = $(root_sbindir)
> +SBIN_PROGRAMS = o2image
> +
> +INCLUDES = -I$(TOPDIR)/include -I.
> +INCLUDES += $(GLIB_CFLAGS)
> +DEFINES = -DVERSION=\"$(VERSION)\"
> +
> +MANS = o2image.8
> +
> +CFILES = o2image.c
> +
> +OBJS = $(subst .c,.o,$(CFILES))
> +
> +DIST_FILES = $(CFILES) $(HFILES) o2image.8.in
> +
> +o2image: $(OBJS) $(LIBOCFS2_DEPS)
> +	$(LINK) $(GLIB_LIBS) $(LIBOCFS2_LIBS) $(COM_ERR_LIBS)
> +
> +include $(TOPDIR)/Postamble.make
> diff --git a/o2image/o2image.8.in b/o2image/o2image.8.in
> new file mode 100644
> index 0000000..06bdea3
> --- /dev/null
> +++ b/o2image/o2image.8.in
> @@ -0,0 +1,59 @@
> +.TH "o2image" "8" "December 2007" "Version @VERSION@" "OCFS2 Manual Pages"
> +.SH "NAME"
> +o2image \- Save/Restore critical ocfs2 filesystem data to a file.
> +.SH "SYNOPSIS"
> +\fBo2image\fR [\fB\-r\fR] [\fB\-I\fR] [\fIdevice\fR] [\fIimage-file\fR]
> +.SH "DESCRIPTION"
> +.PP
> +\fBo2image\fR is an OCFS2 tool that can save critical OCFS2 filesystem data
> +located on a device to a specified image-file. The image-file may be examined
> +using debugfs.ocfs2 to analyze filesystem layout affecting performance. Image-
> +file may also be used to analyze and/or restore data in catastrophic corrupted
> +filesystems.
> +(NOTE: Data may only be restored if it is intact and metadata hasn't
> +changed since it's backup)
> +
> +Image-file format can be either packed(default) or raw.
> +
> +Packed format contains o2image header, filesystem data, and bitmap.
> +
> +Raw format is a sparse file which stores metadata at the same offsets
> +as on the device. Since the raw image file is created as sparse it does not
> +use space for files data (NOTE: It is critical to store image file on a
> +different filesystem which support sparsefile otherwise the image file uses
> +the same amount of space as the device). An image file stores metadata
> +blocks sequentially and consumes little less space.
> +
> +The -I option will cause o2image to install the metadata from image-file on
> +to the device. This can be used to restore the filesystem metadata back
> +to the device in emergency situations.
> +
> +.SH "OPTIONS"
> +.TP
> +\fB\-r\fR
> +Backups the \fIOCFS2\fR volumes metadata to an image-file in a raw format.
> +
> +.TP
> +\fB\-I\fR
> +Restores \fIOCFS2\fR volumes metadata from image-file to the device.
> +
> +.SH "EXAMPLES"
> +.br
> +\	\fBo2image \-r /dev/sda1 sda1.raw\fR
> +.br
> +Copies metadata blocks from /dev/sda1 device to sda1.raw file
> +.br
> +\	\fBo2image -rI /dev/sda1 sda1.raw\fR
> +.br
> +Installs metadata structures from sda.image file onto the device.
> +.br
> +
> +.SH "SEE ALSO"
> +.BR debugfs.ocfs2(8)
> +.BR fsck.ocfs2(8)
> +
> +.SH "AUTHORS"
> +Oracle Corporation
> +
> +.SH "COPYRIGHT"
> +Copyright \(co 2007, 2008 Oracle. All rights reserved.
> diff --git a/o2image/o2image.c b/o2image/o2image.c
> new file mode 100644
> index 0000000..a809c08
> --- /dev/null
> +++ b/o2image/o2image.c
> @@ -0,0 +1,677 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * o2image.c
> + *
> + * o2image utility to backup/restore OCFS2 metadata structures
> + *
> + * Copyright (C) 2008 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.
> + */
> +
> +#define _XOPEN_SOURCE 600 /* Triggers magic in features.h */
> +#define _LARGEFILE64_SOURCE
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <getopt.h>
> +#include <limits.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <ocfs2/bitops.h>
> +
> +#include "ocfs2/ocfs2.h"
> +#include "ocfs2/image.h"
> +
> +static errcode_t traverse_inode(ocfs2_filesys *ofs, uint64_t inode);
> +char *program_name = NULL;
> +
> +static void usage(void)
> +{
> +	fprintf(stderr, ("Usage: %s [-rI] device image_file\n"),
> +			program_name);
> +	exit(1);
> +}
> +
> +static errcode_t mark_localalloc_bits(ocfs2_filesys *ofs,
> +		struct ocfs2_local_alloc *loc)
> +{
> +	/* no need to dump space reserved in local alloc inode */
> +	return 0;
> +}
> +
> +static errcode_t traverse_group_desc(ocfs2_filesys *ofs,
> +		struct ocfs2_group_desc *grp, int dump_type)
> +{
> +	errcode_t ret = 0;
> +	uint64_t blkno;
> +	int i;
> +
> +	blkno = grp->bg_blkno;
> +	for (i = 1; i < grp->bg_bits; i++) {
> +		if ((dump_type == OCFS2_IMAGE_READ_INODE_YES) &&
> +				ocfs2_test_bit(i, grp->bg_bitmap))
> +			ret = traverse_inode(ofs, (blkno + i));
> +		else
> +			ocfs2_image_mark_bitmap(ofs, blkno + i);
> +	}
> +	return ret;
> +}
> +
> +static errcode_t mark_dealloc_bits(ocfs2_filesys *ofs,
> +		struct ocfs2_truncate_log *tl)
> +{
> +	/* no need to dump deleted space */
> +	return 0;
> +}
> +
> +static errcode_t traverse_extents(ocfs2_filesys *ofs,
> +		struct ocfs2_extent_list *el)
> +{
> +	struct ocfs2_super_block *super;
> +	struct ocfs2_extent_block *eb;
> +	struct ocfs2_extent_rec *rec;
> +	struct ocfs2_image_state *ost = ofs->ost;
> +	errcode_t ret = 0;
> +	char *buf = NULL;
> +	__le32 bits;
> +	int i, j;
> +
> +	super = OCFS2_RAW_SB(ofs->fs_super);
> +	bits = super->s_clustersize_bits - super->s_blocksize_bits;
> +	ret = ocfs2_malloc_block(ofs->fs_io, &buf);
> +	if (ret)
> +		goto out;
> +
> +	for (i = 0; i < el->l_next_free_rec; ++i) {
> +		rec = &(el->l_recs[i]);
> +		ocfs2_image_mark_bitmap(ofs, rec->e_blkno);
> +		if (el->l_tree_depth) {
> +			ret = ocfs2_read_extent_block(ofs, rec->e_blkno, buf);
> +			if (ret)
> +				goto out;
> +			eb = (struct ocfs2_extent_block *)buf;
> +			ret = traverse_extents(ofs, &(eb->h_list));
> +			if (ret)
> +				goto out;
> +		} else {
> +			for (j = 0; j < (rec->e_int_clusters*ost->ost_bpc); j++)
> +			ocfs2_image_mark_bitmap(ofs, (rec->e_blkno + j));
>   

Alignment.


> +		}
> +	}
> +out:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	return ret;
> +}
> +
> +static errcode_t traverse_chains(ocfs2_filesys *ofs,
> +		struct ocfs2_chain_list *cl, int dump_type)
> +{
> +	struct ocfs2_group_desc *grp;
> +	struct ocfs2_chain_rec *rec;
> +	errcode_t ret = 0;
> +	char *buf = NULL;
> +	uint64_t blkno;
> +	int i;
> +
> +	ret = ocfs2_malloc_block(ofs->fs_io, &buf);
> +	if (ret) {
> +		com_err(program_name, ret, "while allocating block buffer "
> +				"to group descriptor");
> +		goto out;
> +	}
> +
> +	for (i = 0; i < cl->cl_next_free_rec; i++) {
> +		rec = &(cl->cl_recs[i]);
> +		blkno = rec->c_blkno;
> +		while (blkno) {
> +			ocfs2_image_mark_bitmap(ofs, blkno);
> +			ret = ocfs2_read_group_desc(ofs, blkno, buf);
> +			if (ret)
> +				goto out;
> +
> +			grp = (struct ocfs2_group_desc *)buf;
> +			if (dump_type) {
> +				ret = traverse_group_desc(ofs, grp, dump_type);
> +				if (ret)
> +					goto out;
> +			}
> +			blkno = grp->bg_next_group;
> +		}
> +	}
> +
> +out:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	return ret;
> +}
> +
> +static errcode_t traverse_inode(ocfs2_filesys *ofs, uint64_t inode)
> +{
> +	struct ocfs2_super_block *super;
> +	struct ocfs2_image_state *ost = ofs->ost;
> +	struct ocfs2_dinode *di;
> +	errcode_t ret = 0;
> +	int dump_type = 0;
> +	char *buf = NULL;
> +	int slot;
> +
> +	super = OCFS2_RAW_SB(ofs->fs_super);
> +	ocfs2_image_mark_bitmap(ofs, inode);
> +	ret = ocfs2_malloc_block(ofs->fs_io, &buf);
> +	if (ret) {
> +		com_err(program_name, ret, "while allocating block buffer "
> +				"to bitmap inode");
> +		goto out;
> +	}
> +
> +	di = (struct ocfs2_dinode *)buf;
> +	ret = ocfs2_read_inode(ofs, inode, (char *)di);
> +	if (ret) {
> +		com_err(program_name, ret, "while reading global bitmap inode"
> +				" %"PRIu64"", inode);
> +		goto out;
> +	}
> +
> +	/*
> +	 * Do not scan inode if it's regular file. Extent blocks of regular
> +	 * files get backedup when scanning extent_alloc system files
> +	 */
> +	if (!S_ISDIR(di->i_mode) && !(di->i_flags & OCFS2_SYSTEM_FL))
> +		goto out;
> +
> +	/* Read and traverse group descriptors */
> +	if (di->i_flags & OCFS2_SYSTEM_FL)
> +		dump_type = OCFS2_IMAGE_READ_INODE_NO;
> +
> +	/* Do not traverse chains of a global bitmap inode */
> +	if (inode == ost->ost_glbl_bitmap_inode)
> +		dump_type = OCFS2_IMAGE_READ_CHAIN_NO;
> +
> +	/*
> +	 * If inode is an alloc inode, read the inodes(files/directories) and
> +	 * traverse inode if it's a directory
> +	 */
> +	for (slot = 0; slot < super->s_max_slots; slot++)
> +		if (inode == ost->ost_inode_allocs[slot])
> +			dump_type = OCFS2_IMAGE_READ_INODE_YES;
> +
> +	if (inode == ost->ost_glbl_inode_alloc) {
> +		if (ost->ost_glbl_inode_traversed) {
> +			goto out;
> +		} else {
> +			dump_type = OCFS2_IMAGE_READ_INODE_YES;
> +			ost->ost_glbl_inode_traversed = 1;
> +		}
> +	}
> +
> +	if ((di->i_flags & OCFS2_LOCAL_ALLOC_FL))
> +		ret = mark_localalloc_bits(ofs, &(di->id2.i_lab));
> +	else if (di->i_flags & OCFS2_CHAIN_FL)
> +		ret = traverse_chains(ofs, &(di->id2.i_chain), dump_type);
> +	else if (di->i_flags & OCFS2_DEALLOC_FL)
> +		ret = mark_dealloc_bits(ofs, &(di->id2.i_dealloc));
> +	else
> +		/* traverse extents for system files */
> +		ret = traverse_extents(ofs, &(di->id2.i_list));
> +
> +	if (ret) {
> +		com_err(program_name, ret, "while scanning inode %"PRIu64"",
> +				inode);
> +		goto out;
> +	}
> +out:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	return ret;
> +}
> +
> +static errcode_t o2image_initialize(ocfs2_filesys *ofs, int raw_flag,
> +		int install_flag)
> +{
> +	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
> +	struct ocfs2_super_block *super;
> +	struct ocfs2_image_state *ost = ofs->ost;
> +	errcode_t ret = 0;
> +	uint64_t blkno;
> +	int i, len;
> +
> +	ost->ost_fsblks = ofs->fs_blocks;
> +	ret = ocfs2_image_alloc_bitmap(ofs);
> +	if (ret) {
> +		com_err(program_name, ret, "while allocating bitmap");
> +		goto out;
> +	}
> +
> +	super = OCFS2_RAW_SB(ofs->fs_super);
> +	ost->ost_bpc = ofs->fs_clustersize/ofs->fs_blocksize;
> +
> +	/* traverse and mark super blocks for backup */
> +	if (super->s_feature_compat & OCFS2_FEATURE_COMPAT_BACKUP_SB) {
> +		len = ocfs2_get_backup_super_offset(ofs, blocks,
> +				ARRAY_SIZE(blocks));
> +		for (i = 0; i < len; i++)
> +			ocfs2_image_mark_bitmap(ofs, blocks[i]);
> +	}
> +
> +	/* mark blocks before first cluster group for backup */
> +	blkno = 0;
> +	while(blkno <= super->s_first_cluster_group)
> +		ocfs2_image_mark_bitmap(ofs, blkno++);
> +
> +
> +	/* get global bitmap system inode number */
> +	ret = ocfs2_lookup_system_inode(ofs, GLOBAL_BITMAP_SYSTEM_INODE, 0,
> +			&ost->ost_glbl_bitmap_inode);
> +	if (ret) {
> +		com_err(program_name, ret, "while looking for bitmap inode");
> +		goto out;
> +	}
> +
> +	/* track global_inode_alloc inode number */
> +	ret = ocfs2_lookup_system_inode(ofs, GLOBAL_INODE_ALLOC_SYSTEM_INODE,
> +			0, &ost->ost_glbl_inode_alloc);
> +	if (ret) {
> +		com_err(program_name, ret, "while looking for global inode");
> +		goto out;
> +	}
> +	ost->ost_glbl_inode_traversed = 0;
> +
> +	/* track local alloc inode numbers for all slots */
> +	ret = ocfs2_malloc(((super->s_max_slots) * sizeof(blkno)),
> +			&ost->ost_inode_allocs);
> +	if (ret) {
> +		com_err(program_name, ret, "while allocating mem for "
> +				"local_allocs");
> +		goto out;
> +	}
> +
> +	for (i = 0; i < super->s_max_slots; i++) {
> +		ret = ocfs2_lookup_system_inode(ofs, INODE_ALLOC_SYSTEM_INODE,
> +				i, &ost->ost_inode_allocs[i]);
> +		if (ret) {
> +			com_err(program_name, ret, "while reading inode for "
> +					"slot %d", i);
> +			goto out;
> +		}
> +	}
> +
> +out:
> +	return ret;
> +}
> +
> +static errcode_t write_raw_image_file(ocfs2_filesys *ofs, int fd)
> +{
> +	struct ocfs2_super_block *super;
> +	char *zero_buf = NULL;
> +	char *blk_buf = NULL;
> +	uint64_t blk = -1;
> +	ssize_t count;
> +	errcode_t ret;
> +
> +	super = OCFS2_RAW_SB(ofs->fs_super);
> +	ret = ocfs2_malloc_block(ofs->fs_io, &blk_buf);
> +	if (ret) {
> +		com_err(program_name, ret, "error while allocating buffer ");
> +		goto out;
> +	}
> +
> +	ret = ocfs2_malloc_block(ofs->fs_io, &zero_buf);
> +	if (ret) {
> +		com_err(program_name, ret, "error while allocating buffer ");
> +		goto out;
> +	}
> +	memset(zero_buf, 0, ofs->fs_blocksize);
> +
> +	while (++blk < ofs->fs_blocks) {
> +		if (ocfs2_image_test_bit(ofs, blk)) {
> +			ret = ocfs2_read_blocks(ofs, blk, 1, blk_buf);
> +			if (ret) {
> +				com_err(program_name, ret, "error occurred "
> +					"during read cluster %"PRIu64"", blk);
> +				goto out;
> +			}
> +
> +			if (fd == 1)
> +				count = write(fd, blk_buf, ofs->fs_blocksize);
> +			else
> +				count = pwrite64(fd, blk_buf, ofs->fs_blocksize,
> +					(__off64_t)(blk * ofs->fs_blocksize));
> +		} else if (fd == 1) {
> +			count = write(fd, zero_buf, ofs->fs_blocksize);
> +		} else
> +			continue;
> +
> +		if ((count == -1) || (count < ofs->fs_blocksize)) {
> +			com_err(program_name, errno, "error writing "
> +					"blk %"PRIu64"", blk);
> +			goto out;
> +		}
> +	}
> +out:
> +	if (blk_buf)
> +		ocfs2_free(&blk_buf);
> +	if (zero_buf)
> +		ocfs2_free(&zero_buf);
> +	return ret;
> +}
> +
> +static errcode_t write_image_file(ocfs2_filesys *ofs, int fd)
> +{
> +	uint64_t supers[OCFS2_MAX_BACKUP_SUPERBLOCKS];
> +	struct ocfs2_image_state *ost = ofs->ost;
> +	struct ocfs2_image_hdr *hdr;
> +	uint64_t i, blk;
> +	errcode_t ret;
> +	int bytes;
> +	char *buf;
> +
> +	ret = ocfs2_malloc_block(ofs->fs_io, &buf);
> +	if (ret) {
> +		com_err(program_name, ret, "allocating %lu bytes ",
> +				ofs->fs_blocksize);
> +		return ret;
> +	}
> +	hdr = (struct ocfs2_image_hdr *)buf;
> +	hdr->hdr_magic = OCFS2_IMAGE_MAGIC;
> +	memcpy(hdr->hdr_magic_desc, OCFS2_IMAGE_DESC,
> +			sizeof(OCFS2_IMAGE_DESC));
> +
> +	/* count metadata blocks that will be backedup */
> +	blk = 0;
> +	for (i = 0; i<ofs->fs_blocks; i++)
> +		if (ocfs2_image_test_bit(ofs, i))
> +			blk++;
> +
> +	hdr->hdr_timestamp 	= time(0);
> +	hdr->hdr_version 	= OCFS2_IMAGE_VERSION;
> +	hdr->hdr_fsblks 	= ofs->fs_blocks;
> +	hdr->hdr_fsblksz 	= ofs->fs_blocksize;
> +	hdr->hdr_imgblks	= blk;
> +	hdr->hdr_blksz 		= ost->ost_bmpblksz;
> +	hdr->hdr_superblkcnt 	= ocfs2_get_backup_super_offset(ofs, supers,
> +			ARRAY_SIZE(supers));
> +	for (i = 0; i < hdr->hdr_superblkcnt; i++)
> +		hdr->hdr_superblocks[i] = ocfs2_image_get_blockno(ofs,
> +				supers[i]);
> +
> +	ocfs2_image_swap_header(hdr);
> +	/* o2image header size is smaller than ofs->fs_blocksize */
> +	bytes = write(fd, hdr, ofs->fs_blocksize);
> +	if (bytes < 0) {
> +		perror("writing header");
> +		ret = bytes;
> +		goto out;
> +	}
> +	if (bytes != ofs->fs_blocksize) {
> +		fprintf(stderr, "write_image: short write %d bytes", bytes);
> +		goto out;
> +	}
> +
> +	/* copy metadata blocks to image files */
> +	for (blk = 0; blk < ofs->fs_blocks; blk++) {
> +		if (ocfs2_image_test_bit(ofs, blk)) {
> +			ret = ocfs2_read_blocks(ofs, blk, 1, buf);
> +			if (ret) {
> +				com_err(program_name, ret, "error occurred "
> +					"during read block %"PRIu64"", blk);
> +				goto out;
> +			}
> +
> +			bytes = write(fd, buf, ofs->fs_blocksize);
> +			if ((bytes == -1) || (bytes < ofs->fs_blocksize)) {
> +				com_err(program_name, errno, "error writing "
> +						"blk %"PRIu64"", blk);
> +				goto out;
> +			}
> +		}
> +	}
> +	/* write bitmap blocks at the end */
> +	for(blk = 0; blk < ost->ost_bmpblks; blk++) {
> +		bytes = write(fd, ost->ost_bmparr[blk].arr_map,
> +				ost->ost_bmpblksz);
> +		if ((bytes == -1) || (bytes < ost->ost_bmpblksz)) {
> +			com_err(program_name, errno, "error writing bitmap "
> +					"blk %"PRIu64" bytes %u", blk, bytes);
> +			goto out;
> +		}
> +	}
> +out:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	if (bytes < 0)
> +		ret = bytes;
> +
> +	return ret;
> +}
> +
> +static errcode_t scan_raw_disk(ocfs2_filesys *ofs)
> +{
> +	struct ocfs2_image_state *ost = ofs->ost;
> +	uint64_t bits_set = 0;
> +	errcode_t ret;
> +	int i, j;
> +
> +	/*
> +	 * global inode alloc has list of all metadata inodes blocks.
> +	 * traverse_inode recursively traverses each inode
> +	 */
> +	ret = traverse_inode(ofs, ofs->ost->ost_glbl_inode_alloc);
> +	if (ret)
> +		goto out;
> +
> +	/* update set_bit_cnt for future use */
> +	for (i = 0; i < ost->ost_bmpblks; i++) {
> +		ost->ost_bmparr[i].arr_set_bit_cnt = bits_set;
> +		for (j = 0; j < (ost->ost_bmpblksz * 8); j++)
> +			if (ocfs2_test_bit(j, ost->ost_bmparr[i].arr_map))
> +				bits_set++;
> +	}
> +
> +out:
> +	return ret;
> +}
> +
> +static int prompt_image_creation(ocfs2_filesys *ofs)
> +{
> +	int i, n, i_unit = 0, f_unit = 0;
> +	char *units = "BKMGTP";
> +	float img_size;
> +	float fs_size;
>   

Use unsigned long long (instead of float) as we use that everywhere.

> +
> +	fs_size = ofs->fs_blocks * ofs->fs_blocksize;
>   

This looks wrong. Aren't we supposed to determine whether the
target volume has enough freespace to hold the image? ofs is the
source volume.

> +
> +	n = ofs->ost->ost_bmpblks - 1;
> +	img_size += ofs->ost->ost_bmpblks * ofs->ost->ost_bmpblksz;
> +	img_size = ofs->ost->ost_bmparr[n].arr_set_bit_cnt * 
> +		ofs->fs_blocksize;
> +
> +	for (i = 0; i < (ofs->ost->ost_bmpblksz * 8); i++)
> +		if (ocfs2_test_bit(i, ofs->ost->ost_bmparr[n].arr_map))
> +			img_size += ofs->fs_blocksize;
> +
> +	while (fs_size > 1024.0) {
> +		fs_size /= 1024.0;
> +		if (++f_unit == 5) break;
> +	}
> +
> +	while (img_size > 1024.0) {
> +		img_size /= 1024.0;
> +		if (++i_unit == 5) break;
> +	}
> +
> +	fprintf(stdout, "Filesystem size %.2f%c, "
> +			"Image needs %.2f%c. Continue? (y/N): ",
> +			fs_size, units[f_unit], 
> +			img_size, units[i_unit]);
>   

The message can be improved.

"The image file is expected to be xxx. Please make enough free
space before continuing. Continue or Abort? (c/A): "

> +	if (toupper(getchar()) != 'Y') {
> +		fprintf(stdout, "Aborting image creation.\n");
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	ocfs2_filesys *ofs;
> +	errcode_t ret;
> +	char *src_file	= NULL;
> +	char *dest_file	= NULL;
> +	int open_flags		= 0;
> +	int raw_flag      	= 0;
> +	int install_flag  	= 0;
> +	int fd            	= 0;
> +	int c;
> +
> +	if (argc && *argv)
> +		program_name = *argv;
> +
> +	initialize_ocfs_error_table();
> +
> +	optind = 0;
> +	while((c = getopt(argc, argv, "rI")) != EOF) {
> +		switch (c) {
> +		case 'r':
> +			raw_flag++;
> +			break;
> +		case 'I':
> +			install_flag++;
> +			break;
> +		default:
> +			usage();
> +		}
> +	}
> +
> +	if (optind != argc -2)
> +		usage();
> +
> +	/* We interchange src_file and image file if installing */
> +	if (install_flag) {
> +		dest_file    = argv[optind];
> +		src_file = argv[optind + 1];
> +		if ((strcmp(src_file, "-") == 0) ||
> +				(strcmp(dest_file, "-") == 0)) {
> +			com_err(program_name, 1, "cannot install to/from "
> +					"file - ");
> +			exit(1);
> +		}
> +
> +		fprintf(stdout, "Install %s image to %s. Continue? (y/N): ",
> +				src_file, dest_file);
> +		if (toupper(getchar()) != 'Y') {
> +			fprintf(stderr, "Aborting operation.\n");
> +			return 1;
> +		}
> +		/* if raw is not specified then we are opening image file */
> +		if (!raw_flag)
> +			open_flags = OCFS2_FLAG_IMAGE_FILE;
> +	} else {
> +		src_file  = argv[optind];
> +		dest_file = argv[optind + 1];
> +	}
> +
> +	/*
> +	 * ocfs2_open is modified to be aware of OCFS2_FLAG_IMAGE_FILE.
> +	 * open routine allocates ocfs2_image_state and loads the bitmap if
> +	 * OCFS2_FLAG_IMAGE_FILE flag is passed in
> +	 */
> +	ret = ocfs2_open(src_file, OCFS2_FLAG_RO|open_flags, 0, 0, &ofs);
> +	if (ret) {
> +		com_err(program_name, ret, "while trying to open \"%s\"",
> +				src_file);
> +		exit(1);
> +	}
> +
> +	/*
> +	 * If src_file is opened with OCFS2_FLAG_IMAGE_FILE, then no need to
> +	 * allocate and initialize ocfs2_image_state. ocfs2_open would have
> +	 * allocated one already.
> +	 */
> +	if (!(open_flags & OCFS2_FLAG_IMAGE_FILE)) {
> +		ret = ocfs2_malloc0(sizeof(struct ocfs2_image_state),&ofs->ost);
> +		if (ret) {
> +			com_err(program_name, ret, "allocating memory for "
> +					"ocfs2_image_state");
> +			goto out;
> +		}
> +
> +		ret = o2image_initialize(ofs, raw_flag, install_flag);
> +		if (ret) {
> +			com_err(program_name, ret, "during o2image initialize");
> +			goto out;
> +		}
> +
> +		ret = scan_raw_disk(ofs);
> +		if (ret) {
> +			com_err(program_name, ret, "while scanning disk \"%s\"",
> +					src_file);
> +			goto out;
> +		}
> +	}
> +
> +	/* prompt user for image creation */
> +	if (!install_flag && !prompt_image_creation(ofs))
> +		goto out;
> +
> +	if (strcmp(dest_file, "-") == 0)
> +		fd = 1;
> +	else {
> +#ifdef HAVE_OPEN64
> +		fd = open64(dest_file, O_CREAT|O_TRUNC|O_WRONLY, 0600);
> +#else
> +		fd = open(dest_file, O_CREAT|O_TRUNC|O_WRONLY, 0600);
> +#endif
> +		if (fd < 0) {
> +			com_err(program_name, errno,
> +			"while trying to open \"%s\"", argv[optind + 1]);
> +			goto out;
> +		}
> +	}
> +
> +	/* Installs always are done in raw format */
> +	if (raw_flag || install_flag)
> +		ret = write_raw_image_file(ofs, fd);
> +	else
> +		ret = write_image_file(ofs, fd);
> +
> +	if (ret) {
> +		com_err(program_name, ret, "while writing to image \"%s\"",
> +				dest_file);
> +		goto out;
> +	}
> +
> +out:
> +	ocfs2_image_free_bitmap(ofs);
> +
> +	if (ofs->ost->ost_inode_allocs)
> +		ocfs2_free(&ofs->ost->ost_inode_allocs);
> +
> +	ret = ocfs2_close(ofs);
> +	if (ret)
> +		com_err(program_name, ret, "while closing file \"%s\"",
> +				src_file);
> +
> +	if (fd && (fd != 1))
> +		close(fd);
> +
> +	return ret;
> +}
> diff --git a/vendor/common/ocfs2-tools.spec-generic.in b/vendor/common/ocfs2-tools.spec-generic.in
> index 01de00d..884ef73 100644
> --- a/vendor/common/ocfs2-tools.spec-generic.in
> +++ b/vendor/common/ocfs2-tools.spec-generic.in
> @@ -118,6 +118,7 @@ fi
>  /sbin/o2cb_ctl
>  /sbin/mount.ocfs2
>  /sbin/ocfs2cdsl
> +/sbin/o2image
>  /sbin/ocfs2_hb_ctl
>  /etc/init.d/o2cb
>  /etc/init.d/ocfs2
> @@ -132,6 +133,7 @@ fi
>  /usr/share/man/man8/o2cb_ctl.8.gz
>  /usr/share/man/man8/ocfs2_hb_ctl.8.gz
>  /usr/share/man/man8/ocfs2cdsl.8.gz
> +/usr/share/man/man8/o2image.8.gz
>  
>  
>  %files -n ocfs2console
>   




More information about the Ocfs2-tools-devel mailing list