[Ocfs2-tools-devel] [PATCH 1/4] Adds o2image header and supporting functions

Srinivas Eeda srinivas.eeda at oracle.com
Wed Mar 5 19:00:50 PST 2008


o2image - An ocfs2 tool to save critical ocfs2 filesystem metadata to a
specified image-file. Image-file may be examined using debugfs.ocfs2 or
may be used to restore using o2image. Image-file can be of two formats:

	1. Packed - This format(default) contains a o2image header, packed
	metadata blocks and a bitmap.
	2. raw    - A raw image is a sparse file containing the metadata blocks.

	Usage: o2image [-rI] <device> <imagefile>

Packed format contains bitmap towards the end of the image-file. Each bit in
the bitmap represents a block in the filesystem.

When the packed image is opened using o2image or debugfs.ocfs2, bitmap is
loaded into memory and used to map disk blocks to image blocks.

Raw image is a sparse file containing metadata blocks at the same offset as
the filesystem.

debugfs.ocfs2 is modified to detect image-file when the image-file is
specified with -i option.

This patch adds o2image header files and supporting functions to read
write to image-file

Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com>
---
 include/ocfs2/o2image.h |  108 ++++++++++++++++++
 libocfs2/Makefile       |    3 +-
 libocfs2/o2image.c      |  290 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 400 insertions(+), 1 deletions(-)
 create mode 100644 include/ocfs2/o2image.h
 create mode 100644 libocfs2/o2image.c

diff --git a/include/ocfs2/o2image.h b/include/ocfs2/o2image.h
new file mode 100644
index 0000000..72f519a
--- /dev/null
+++ b/include/ocfs2/o2image.h
@@ -0,0 +1,108 @@
+/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * o2image.h
+ *
+ * Header file describing o2image image 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.
+ */
+
+/*
+ * o2image - An ocfs2 tool to save critical ocfs2 filesystem metadata to a
+ * specified image-file. Image-file may be examined using debugfs.ocfs2 or
+ * may be used to restore using o2image. Image-file can be of two formats:
+ *
+ * 1. Packed - This format(default) contains a o2image header, packed metadata
+ *		blocks and a bitmap.
+ * 2. raw    - A raw image is a sparse file containing the metadata blocks.
+ *
+ * 		Usage: o2image [-rI] <device> <imagefile>
+ *
+ * Packed format contains bitmap towards the end of the image-file. Each bit in
+ * the bitmap represents a block in the filesystem.
+ *
+ * When the packed image is opened using o2image or debugfs.ocfs2, bitmap is
+ * loaded into memory and used to map disk blocks to image blocks.
+ *
+ * Raw image is a sparse file containing metadata blocks at the same offset as
+ * the filesystem.
+ *
+ * debugfs.ocfs2 is modified to detect image-file when the image-file is
+ * specified with -i option.
+ */
+
+#define OCFS2_FS_MAGIC_O2IMAGE 0x72a3d45f
+#define OCFS2_FS_O2IMAGE_DESC "OCFS2 IMAGE"
+#define O2IMAGE_VERSION		0
+#define O2IMAGE_READ_CHAIN_NO	0
+#define O2IMAGE_READ_INODE_NO	1
+#define O2IMAGE_READ_INODE_YES	2
+#define O2IMAGE_BITMAP_BLOCKSIZE	4096
+#define O2IMAGE_BITS_IN_BLOCK	(O2IMAGE_BITMAP_BLOCKSIZE * 8)
+
+/* on disk o2image header format */
+struct o2image_hdr {
+	__le32	hdr_magic;
+	__le32	hdr_timestamp;		/* Time of image creation */
+	__u8	hdr_magic_desc[16];	/* "OCFS2 IMAGE" */
+	__le64	hdr_version;		/* o2image version */
+	__le64	hdr_fsblks;		/* blocks in filesystem */
+	__le64	hdr_fsblksz;		/* Filesystem block size */
+	__le64	hdr_imgblks;		/* Filesystem blocks in image */
+	__le64	hdr_blksz;		/* bitmap block size */
+	__le64	hdr_superblkcnt;	/* number of super blocks */
+	__le64	hdr_superblocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+};
+
+/*
+ * array to hold pointers to bitmap blocks. arr_set_bit_cnt holds cumulative
+ * count of bits used previous to the current block. arr_self will be pointing
+ * to the memory chunks allocated. arr_map will be pointing to bitmap blocks
+ * of size O2IMAGE_BITMAP_BLOCKSIZE. Each block maps to O2IMAGE_BITS_IN_BLOCK
+ * number of filesystem blocks.
+ */
+struct _o2image_bitmap_arr {
+	uint64_t	arr_set_bit_cnt;
+	char		*arr_self;
+	char    	*arr_map;
+};
+typedef struct _o2image_bitmap_arr o2image_bitmap_arr;
+
+/* o2image state holds runtime values */
+struct o2image_state {
+	uint64_t	ost_fsblksz;
+	uint64_t	ost_fsblks;
+	uint64_t	ost_imgblks;	/* filesystem blocks in image */
+	uint64_t 	ost_glbl_bitmap_inode;
+	uint64_t 	ost_glbl_inode_alloc;
+	uint64_t 	*ost_inode_allocs; 	/* holds inode_alloc inodes */
+	uint64_t	ost_bmpblks; 		/* blocks that store bitmaps */
+	uint64_t	ost_bmpblksz; 		/* size of each bitmap blk */
+	uint64_t	ost_superblocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+	int		ost_glbl_inode_traversed;
+	int		ost_bpc; 		/* blocks per cluster */
+	int 		ost_superblkcnt; 	/* number of super blocks */
+	o2image_bitmap_arr	*ost_bmparr; 	/* points to bitmap blocks */
+};
+
+extern errcode_t o2image_load_bitmap(ocfs2_filesys *ofs);
+extern errcode_t o2image_free_bitmap(ocfs2_filesys *ofs);
+extern errcode_t o2image_alloc_bitmap(ocfs2_filesys *ofs);
+extern void o2image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno);
+extern int o2image_test_bit(ocfs2_filesys *ofs, uint64_t blkno);
+uint64_t o2image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno);
+void o2image_swap_header(struct o2image_hdr *hdr);
diff --git a/libocfs2/Makefile b/libocfs2/Makefile
index 7fd0042..51d4ad8 100644
--- a/libocfs2/Makefile
+++ b/libocfs2/Makefile
@@ -72,7 +72,8 @@ CFILES = 		\
 	unlink.c	\
 	lockid.c	\
 	backup_super.c	\
-	feature_string.c
+	feature_string.c\
+	o2image.c
 
 HFILES =		\
 	bitmap.h	\
diff --git a/libocfs2/o2image.c b/libocfs2/o2image.c
new file mode 100644
index 0000000..b62ddfe
--- /dev/null
+++ b/libocfs2/o2image.c
@@ -0,0 +1,290 @@
+/* -*- 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/byteorder.h"
+#include "ocfs2/o2image.h"
+
+void o2image_swap_header(struct o2image_hdr *hdr)
+{
+	int i;
+
+	if (cpu_is_little_endian)
+		return;
+
+	for (i = 0; i < hdr->hdr_superblkcnt; i++)
+		hdr->hdr_superblocks[i]	= bswap_64(hdr->hdr_superblocks[i]);
+
+	hdr->hdr_magic 		= bswap_32(hdr->hdr_magic);
+	hdr->hdr_version 	= bswap_32(hdr->hdr_version);
+	hdr->hdr_timestamp	= bswap_32(hdr->hdr_timestamp);
+	hdr->hdr_fsblks		= bswap_64(hdr->hdr_fsblks);
+	hdr->hdr_fsblksz 	= bswap_64(hdr->hdr_fsblksz);
+	hdr->hdr_imgblks	= bswap_64(hdr->hdr_imgblks);
+	hdr->hdr_blksz		= bswap_64(hdr->hdr_blksz);
+	hdr->hdr_superblkcnt	= bswap_64(hdr->hdr_superblkcnt);
+}
+
+errcode_t o2image_free_bitmap(ocfs2_filesys *ofs)
+{
+	struct o2image_state *ost = ofs->ost;
+	int i;
+
+	/* image bitmaps are allocated only for o2image image files */
+	if (!ofs->fs_flags & OCFS2_FLAG_O2IMAGE_FILE)
+		return 0;
+
+	if (!ost->ost_bmparr)
+		return 0;
+
+	for (i=0; i<ost->ost_bmpblks; i++)
+		if (ost->ost_bmparr[i].arr_self)
+			ocfs2_free(&ost->ost_bmparr[i].arr_self);
+
+	if (ost->ost_bmparr)
+		ocfs2_free(&ost->ost_bmparr);
+	return 0;
+}
+
+/*
+ * allocate o2image_bitmap_arr and o2image bitmap blocks. o2image bitmap block
+ * is of size O2IMAGE_BITMAP_BLOCKSIZE and o2image_bitmap_arr tracks the
+ * bitmap blocks
+ */
+errcode_t o2image_alloc_bitmap(ocfs2_filesys *ofs)
+{
+	uint64_t blks, allocsize, leftsize;
+	struct o2image_state *ost = ofs->ost;
+	int indx, i, n;
+	errcode_t ret;
+	char *buf;
+
+	ost->ost_bmpblks =
+		((ost->ost_fsblks - 1) / (O2IMAGE_BITS_IN_BLOCK)) + 1;
+	ost->ost_bmpblksz = O2IMAGE_BITMAP_BLOCKSIZE;
+	blks = ost->ost_bmpblks;
+
+	/* allocate memory for an array to track bitmap blocks */
+	ret = ocfs2_malloc0((blks * sizeof(o2image_bitmap_arr)),
+			&ost->ost_bmparr);
+	if (ret)
+		return ret;
+
+	allocsize = blks * O2IMAGE_BITMAP_BLOCKSIZE;
+	leftsize = allocsize;
+	indx = 0;
+
+	/* allocate bitmap blocks and assign blocks to above array */
+	while (leftsize) {
+		ret = ocfs2_malloc0(allocsize, &buf);
+		if (ret && (ret != -ENOMEM))
+			goto out;
+
+		if (ret == -ENOMEM) {
+			if (allocsize == O2IMAGE_BITMAP_BLOCKSIZE)
+				goto out;
+			allocsize >>= 1;
+			continue;
+		}
+
+		n = allocsize / O2IMAGE_BITMAP_BLOCKSIZE;
+		for (i = 0; i < n; i++) {
+			ost->ost_bmparr[indx].arr_set_bit_cnt = 0;
+			ost->ost_bmparr[indx].arr_map =
+				((char *)buf + (i * O2IMAGE_BITMAP_BLOCKSIZE));
+
+			/* remember buf address to free it later */
+			if (!i)
+				ost->ost_bmparr[indx].arr_self = buf;
+			indx++;
+		}
+		leftsize -= allocsize;
+	}
+out:
+	/* If allocation failed free and return error */
+	if (leftsize) {
+		for (i = 0; i < indx; i++)
+			if (ost->ost_bmparr[i].arr_self)
+				ocfs2_free(&ost->ost_bmparr[i].arr_self);
+		ocfs2_free(&ost->ost_bmparr);
+	}
+
+	return ret;
+}
+
+/*
+ * This routine loads bitmap blocks from an o2image image file into memory.
+ * This process happens during file open. bitmap blocks reside towards
+ * the end of the imagefile.
+ */
+errcode_t o2image_load_bitmap(ocfs2_filesys *ofs)
+{
+	struct o2image_state *ost;
+	struct o2image_hdr *hdr;
+	uint64_t blk_off, bits_set;
+	int count, i, j, fd;
+	errcode_t ret;
+	char *blk;
+
+	ret = ocfs2_malloc0(sizeof(struct o2image_state), &ofs->ost);
+	if (ret)
+		return ret;
+
+	ost = ofs->ost;
+	ret = ocfs2_malloc0(io_get_blksize(ofs->fs_io), &blk);
+	if (ret)
+		return ret;
+
+	/* read o2image header */
+	ret = io_read_block(ofs->fs_io, 0, 1, blk);
+	if (ret)
+		goto out;
+
+	hdr = (struct o2image_hdr *)blk;
+	o2image_swap_header(hdr);
+
+	ret = OCFS2_ET_BAD_MAGIC;
+	if (hdr->hdr_magic != OCFS2_FS_MAGIC_O2IMAGE) {
+		fprintf(stderr, "invalid magic number %lu\n",
+				hdr->hdr_magic);
+		goto out;
+	}
+
+	if (memcmp(hdr->hdr_magic_desc, OCFS2_FS_O2IMAGE_DESC,
+				sizeof(OCFS2_FS_O2IMAGE_DESC))) {
+		fprintf(stderr, "invalid magic descriptor %s\n",
+				hdr->hdr_magic_desc);
+		goto out;
+	}
+
+	if (hdr->hdr_version > O2IMAGE_VERSION) {
+		fprintf(stderr, "incompatible o2image version\n",
+				hdr->hdr_version);
+		goto out;
+	}
+
+	ost->ost_fsblks 	= hdr->hdr_fsblks;
+	ost->ost_fsblksz 	= hdr->hdr_fsblksz;
+	ost->ost_imgblks 	= hdr->hdr_imgblks;
+	ost->ost_bmpblksz 	= hdr->hdr_blksz;
+
+	ret = o2image_alloc_bitmap(ofs);
+	if (ret)
+		return ret;
+
+	/* load bitmap blocks o2image state */
+	bits_set = 0;
+	fd 	= io_get_fd(ofs->fs_io);
+	blk_off = (ost->ost_imgblks + 1)* ost->ost_fsblksz;
+
+	for (i = 0; i < ost->ost_bmpblks; i++) {
+		ost->ost_bmparr[i].arr_set_bit_cnt = bits_set;
+		/*
+		 * we don't use io_read_block as o2image bitmap block size
+		 * could be different from filesystem block size
+		 */
+		count = pread64(fd, ost->ost_bmparr[i].arr_map,
+				ost->ost_bmpblksz, blk_off);
+		if (count < ost->ost_bmpblksz)
+			goto out;
+
+		/* add bits set in this bitmap */
+		for (j = 0; j < (ost->ost_bmpblksz * 8); j++)
+			if (ocfs2_test_bit(j, ost->ost_bmparr[i].arr_map))
+				bits_set++;
+
+		blk_off += ost->ost_bmpblksz;
+	}
+
+out:
+	if (blk)
+		ocfs2_free(&blk);
+	return ret;
+}
+
+void o2image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct o2image_state *ost = ofs->ost;
+	int bitmap_blk;
+	int bit;
+
+	bit = blkno % O2IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / O2IMAGE_BITS_IN_BLOCK;
+
+	ocfs2_set_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map);
+}
+
+int o2image_test_bit(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct o2image_state *ost = ofs->ost;
+	int bitmap_blk;
+	int bit;
+
+	bit = blkno % O2IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / O2IMAGE_BITS_IN_BLOCK;
+
+	if (ocfs2_test_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map))
+		return 1;
+	else
+		return 0;
+}
+
+uint64_t o2image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct o2image_state *ost = ofs->ost;
+	uint64_t ret_blk;
+	int bitmap_blk;
+	int i, bit;
+
+	bit = blkno % O2IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / O2IMAGE_BITS_IN_BLOCK;
+
+	if (ocfs2_test_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map)) {
+		ret_blk = ost->ost_bmparr[bitmap_blk].arr_set_bit_cnt + 1;
+
+		/* add bits set in this block before the block no */
+		for (i = 0; i < bit; i++)
+			if (ocfs2_test_bit(i,
+					ost->ost_bmparr[bitmap_blk].arr_map))
+				ret_blk++;
+	} else
+		ret_blk = -1;
+
+	return ret_blk;
+}
-- 
1.5.3.4




More information about the Ocfs2-tools-devel mailing list