[Ocfs2-tools-devel] [PATCH 1/4] Adds o2image header and supporting functions
Sunil Mushran
Sunil.Mushran at oracle.com
Tue May 6 16:59:33 PDT 2008
Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
Small comment inlined.
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 | 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 */
>
hdr_fsblks and hdr_fsblksz are ripe for typos. How about being
more explicit.
hdr_fsblks ==> hdr_fsblkcnt
hdr_imgblks ==> hdr_imgblkcnt
hdr_blksz ==> hdr_bmblksz
> + __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 */
>
ost_fsblks ==> ost_fsblkcnt
ost_imgblks ==> ost_imgblkcnt
> + 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;
> +}
>
More information about the Ocfs2-tools-devel
mailing list