[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