[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