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

Srinivas Eeda srinivas.eeda at oracle.com
Tue May 6 16:32:10 PDT 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/image.h |  108 +++++++++++++++++++
 libocfs2/Makefile     |    3 +-
 libocfs2/image.c      |  283 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 393 insertions(+), 1 deletions(-)
 create mode 100644 include/ocfs2/image.h
 create mode 100644 libocfs2/image.c

diff --git a/include/ocfs2/image.h b/include/ocfs2/image.h
new file mode 100644
index 0000000..57c8bdf
--- /dev/null
+++ b/include/ocfs2/image.h
@@ -0,0 +1,108 @@
+/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * image.h
+ *
+ * Header file describing image disk/memory structures for ocfs2 image
+ *
+ * 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 is 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 ocfs2 image 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_IMAGE_MAGIC		0x72a3d45f
+#define OCFS2_IMAGE_DESC 		"OCFS2 IMAGE"
+#define OCFS2_IMAGE_VERSION		1
+#define OCFS2_IMAGE_READ_CHAIN_NO	0
+#define OCFS2_IMAGE_READ_INODE_NO	1
+#define OCFS2_IMAGE_READ_INODE_YES	2
+#define OCFS2_IMAGE_BITMAP_BLOCKSIZE	4096
+#define OCFS2_IMAGE_BITS_IN_BLOCK	(OCFS2_IMAGE_BITMAP_BLOCKSIZE * 8)
+
+/* on disk ocfs2 image header format */
+struct ocfs2_image_hdr {
+	__le32	hdr_magic;
+	__le32	hdr_timestamp;		/* Time of image creation */
+	__u8	hdr_magic_desc[16];	/* "OCFS2 IMAGE" */
+	__le64	hdr_version;		/* ocfs2 image 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 OCFS2_IMAGE_BITMAP_BLOCKSIZE. Each block maps to
+ * OCFS2_IMAGE_BITS_IN_BLOCK number of filesystem blocks.
+ */
+struct _ocfs2_image_bitmap_arr {
+	uint64_t	arr_set_bit_cnt;
+	char		*arr_self;
+	char    	*arr_map;
+};
+typedef struct _ocfs2_image_bitmap_arr ocfs2_image_bitmap_arr;
+
+/* ocfs2 image state holds runtime values */
+struct ocfs2_image_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 */
+	ocfs2_image_bitmap_arr	*ost_bmparr; 	/* points to bitmap blocks */
+};
+
+errcode_t ocfs2_image_load_bitmap(ocfs2_filesys *ofs);
+errcode_t ocfs2_image_free_bitmap(ocfs2_filesys *ofs);
+errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs);
+void ocfs2_image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno);
+int ocfs2_image_test_bit(ocfs2_filesys *ofs, uint64_t blkno);
+uint64_t ocfs2_image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno);
+void ocfs2_image_swap_header(struct ocfs2_image_hdr *hdr);
diff --git a/libocfs2/Makefile b/libocfs2/Makefile
index 7fd0042..762c93a 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\
+	image.c
 
 HFILES =		\
 	bitmap.h	\
diff --git a/libocfs2/image.c b/libocfs2/image.c
new file mode 100644
index 0000000..0140cda
--- /dev/null
+++ b/libocfs2/image.c
@@ -0,0 +1,283 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * image.c
+ *
+ * supporting structures/functions to handle ocfs2 image file
+ *
+ * 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/image.h"
+
+void ocfs2_image_swap_header(struct ocfs2_image_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 ocfs2_image_free_bitmap(ocfs2_filesys *ofs)
+{
+	struct ocfs2_image_state *ost = ofs->ost;
+	int i;
+
+	/* image bitmaps are allocated only for ocfs2 image image files */
+	if (!ofs->fs_flags & OCFS2_FLAG_IMAGE_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 ocfs2_image_bitmap_arr and ocfs2 image bitmap blocks. o2image bitmap
+ * block is of size OCFS2_IMAGE_BITMAP_BLOCKSIZE and ocfs2_image_bitmap_arr
+ * tracks the bitmap blocks
+ */
+errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs)
+{
+	uint64_t blks, allocsize, leftsize;
+	struct ocfs2_image_state *ost = ofs->ost;
+	int indx, i, n;
+	errcode_t ret;
+	char *buf;
+
+	ost->ost_bmpblks =
+		((ost->ost_fsblks - 1) / (OCFS2_IMAGE_BITS_IN_BLOCK)) + 1;
+	ost->ost_bmpblksz = OCFS2_IMAGE_BITMAP_BLOCKSIZE;
+	blks = ost->ost_bmpblks;
+
+	/* allocate memory for an array to track bitmap blocks */
+	ret = ocfs2_malloc0((blks * sizeof(ocfs2_image_bitmap_arr)),
+			&ost->ost_bmparr);
+	if (ret)
+		return ret;
+
+	allocsize = blks * OCFS2_IMAGE_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 == OCFS2_IMAGE_BITMAP_BLOCKSIZE)
+				goto out;
+			allocsize >>= 1;
+			continue;
+		}
+
+		n = allocsize / OCFS2_IMAGE_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 *
+					OCFS2_IMAGE_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 ocfs2_image_load_bitmap(ocfs2_filesys *ofs)
+{
+	struct ocfs2_image_state *ost;
+	struct ocfs2_image_hdr *hdr;
+	uint64_t blk_off, bits_set;
+	int count, i, j, fd;
+	errcode_t ret;
+	char *blk;
+
+	ret = ocfs2_malloc0(sizeof(struct ocfs2_image_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 ocfs2 image header */
+	ret = io_read_block(ofs->fs_io, 0, 1, blk);
+	if (ret)
+		goto out;
+
+	hdr = (struct ocfs2_image_hdr *)blk;
+	ocfs2_image_swap_header(hdr);
+
+	ret = OCFS2_ET_BAD_MAGIC;
+	if (hdr->hdr_magic != OCFS2_IMAGE_MAGIC)
+		goto out;
+
+	if (memcmp(hdr->hdr_magic_desc, OCFS2_IMAGE_DESC,
+				sizeof(OCFS2_IMAGE_DESC)))
+		goto out;
+
+	ret = OCFS2_ET_OCFS_REV;
+	if (hdr->hdr_version > OCFS2_IMAGE_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 = ocfs2_image_alloc_bitmap(ofs);
+	if (ret)
+		return ret;
+
+	/* load bitmap blocks ocfs2 image 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 ocfs2 image 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 ocfs2_image_mark_bitmap(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct ocfs2_image_state *ost = ofs->ost;
+	int bitmap_blk;
+	int bit;
+
+	bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / OCFS2_IMAGE_BITS_IN_BLOCK;
+
+	ocfs2_set_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map);
+}
+
+int ocfs2_image_test_bit(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct ocfs2_image_state *ost = ofs->ost;
+	int bitmap_blk;
+	int bit;
+
+	bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / OCFS2_IMAGE_BITS_IN_BLOCK;
+
+	if (ocfs2_test_bit(bit, ost->ost_bmparr[bitmap_blk].arr_map))
+		return 1;
+	else
+		return 0;
+}
+
+uint64_t ocfs2_image_get_blockno(ocfs2_filesys *ofs, uint64_t blkno)
+{
+	struct ocfs2_image_state *ost = ofs->ost;
+	uint64_t ret_blk;
+	int bitmap_blk;
+	int i, bit;
+
+	bit = blkno % OCFS2_IMAGE_BITS_IN_BLOCK;
+	bitmap_blk = blkno / OCFS2_IMAGE_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.2.1




More information about the Ocfs2-tools-devel mailing list