/* -*- 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 #include #include #include #include #include #include #include #include #include #include #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_fsblkcnt = bswap_64(hdr->hdr_fsblkcnt); hdr->hdr_fsblksz = bswap_64(hdr->hdr_fsblksz); hdr->hdr_imgblkcnt = bswap_64(hdr->hdr_imgblkcnt); hdr->hdr_bmpblksz = bswap_64(hdr->hdr_bmpblksz); 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; iost_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_fsblkcnt - 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_malloc_blocks(ofs->fs_io, allocsize/io_get_blksize(ofs->fs_io), &buf); if (ret && (ret != -ENOMEM)) goto out; if (ret == -ENOMEM) { if (allocsize == OCFS2_IMAGE_BITMAP_BLOCKSIZE) goto out; allocsize >>= 1; if (allocsize % OCFS2_IMAGE_BITMAP_BLOCKSIZE) { allocsize /= OCFS2_IMAGE_BITMAP_BLOCKSIZE; allocsize *= OCFS2_IMAGE_BITMAP_BLOCKSIZE; } 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; if (leftsize <= allocsize) allocsize = leftsize; } 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_malloc_block(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_fsblkcnt = hdr->hdr_fsblkcnt; ost->ost_fsblksz = hdr->hdr_fsblksz; ost->ost_imgblkcnt = hdr->hdr_imgblkcnt; ost->ost_bmpblksz = hdr->hdr_bmpblksz; 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_imgblkcnt + 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; }