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

Sunil Mushran Sunil.Mushran at oracle.com
Mon May 5 13:28:59 PDT 2008


See inline.

Srinivas Eeda wrote:
> 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      |  291 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 401 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..6f898cb
> --- /dev/null
> +++ b/libocfs2/image.c
> @@ -0,0 +1,291 @@
> +/* -*- 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) {
> +		fprintf(stderr, "invalid magic number %u\n",
> +				hdr->hdr_magic);
>   

This is a library... meaning no printfs. Add a appropriate return code
+ description to the error file and return that code to the o2image tool.
Let it print the error.

> +		goto out;
> +	}
> +
> +	if (memcmp(hdr->hdr_magic_desc, OCFS2_IMAGE_DESC,
> +				sizeof(OCFS2_IMAGE_DESC))) {
> +		fprintf(stderr, "invalid magic descriptor %s\n",
> +				hdr->hdr_magic_desc);
>   

And here.

> +		goto out;
> +	}
> +
> +	if (hdr->hdr_version > OCFS2_IMAGE_VERSION) {
> +		fprintf(stderr, "incompatible ocfs2 image version %u\n",
> +				hdr->hdr_version);
>   

And here.

> +		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;
> +}
>   




More information about the Ocfs2-tools-devel mailing list