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

Srinivas Eeda srinivas.eeda at oracle.com
Tue May 6 16:32:12 PDT 2008


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                         |  672 +++++++++++++++++++++++++++++
 vendor/common/ocfs2-tools.spec-generic.in |    2 +
 7 files changed, 773 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..80884f4
--- /dev/null
+++ b/o2image/o2image.c
@@ -0,0 +1,672 @@
+/* -*- 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 <libgen.h>
+#include <sys/vfs.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));
+		}
+	}
+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 rawflg, char *filename)
+{
+	int i, n;
+	uint64_t free_spc;
+	struct statfs stat;
+	uint64_t img_size = 0;
+
+	statfs(dirname(filename), &stat);
+	free_spc = stat.f_bsize * stat.f_bavail;
+
+	n = ofs->ost->ost_bmpblks - 1;
+	if (!rawflg)
+		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;
+
+	fprintf(stdout, "Image file expected to be %luK, "
+			"Available free space %luK. Continue ? (y/N): ",
+			img_size/1024, free_spc/1024);
+	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;
+		}
+	}
+
+	if (strcmp(dest_file, "-") == 0)
+		fd = 1;
+	else {
+		/* prompt user for image creation */
+		if (!install_flag && !prompt_image_creation(ofs, raw_flag,
+					dest_file))
+			goto out;
+#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
-- 
1.5.2.1




More information about the Ocfs2-tools-devel mailing list