blkmap64_ba.c revision 9288e3be665bb8d5657d7f710687a50fad859acf
1/* 2 * blkmap64_ba.c --- Simple bitarray implementation for bitmaps 3 * 4 * Copyright (C) 2008 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include "config.h" 13#include <stdio.h> 14#include <string.h> 15#if HAVE_UNISTD_H 16#include <unistd.h> 17#endif 18#include <fcntl.h> 19#include <time.h> 20#if HAVE_SYS_STAT_H 21#include <sys/stat.h> 22#endif 23#if HAVE_SYS_TYPES_H 24#include <sys/types.h> 25#endif 26 27#include "ext2_fs.h" 28#include "ext2fsP.h" 29#include "bmap64.h" 30 31/* 32 * Private data for bit array implementation of bitmap ops. 33 * Currently, this is just a pointer to our big flat hunk of memory, 34 * exactly equivalent to the old-skool char * bitmap member. 35 */ 36 37struct ext2fs_ba_private_struct { 38 char *bitarray; 39}; 40 41typedef struct ext2fs_ba_private_struct *ext2fs_ba_private; 42 43static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap bitmap) 44{ 45 ext2fs_ba_private bp; 46 errcode_t retval; 47 size_t size; 48 49 /* 50 * Since we only have the one pointer, we could just shove our 51 * private data in the void *private field itself, but then 52 * we'd have to do a fair bit of rewriting if we ever added a 53 * field. I'm agnostic. 54 */ 55 retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp); 56 if (retval) 57 return retval; 58 59 size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); 60 61 retval = ext2fs_get_mem(size, &bp->bitarray); 62 if (retval) { 63 ext2fs_free_mem(&bp); 64 bp = 0; 65 return retval; 66 } 67 bitmap->private = (void *) bp; 68 return 0; 69} 70 71static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), 72 ext2fs_generic_bitmap bitmap) 73{ 74 ext2fs_ba_private bp; 75 errcode_t retval; 76 size_t size; 77 78 retval = ba_alloc_private_data (bitmap); 79 if (retval) 80 return retval; 81 82 bp = (ext2fs_ba_private) bitmap->private; 83 size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); 84 memset(bp->bitarray, 0, size); 85 86 return 0; 87} 88 89static void ba_free_bmap(ext2fs_generic_bitmap bitmap) 90{ 91 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 92 93 if (!bp) 94 return; 95 96 if (bp->bitarray) { 97 ext2fs_free_mem (&bp->bitarray); 98 bp->bitarray = 0; 99 } 100 ext2fs_free_mem (&bp); 101 bp = 0; 102} 103 104static errcode_t ba_copy_bmap(ext2fs_generic_bitmap src, 105 ext2fs_generic_bitmap dest) 106{ 107 ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private; 108 ext2fs_ba_private dest_bp; 109 errcode_t retval; 110 size_t size; 111 112 retval = ba_alloc_private_data (dest); 113 if (retval) 114 return retval; 115 116 dest_bp = (ext2fs_ba_private) dest->private; 117 118 size = (size_t) (((src->real_end - src->start) / 8) + 1); 119 memcpy (dest_bp->bitarray, src_bp->bitarray, size); 120 121 return 0; 122} 123 124static errcode_t ba_resize_bmap(ext2fs_generic_bitmap bmap, 125 __u64 new_end, __u64 new_real_end) 126{ 127 ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private; 128 errcode_t retval; 129 size_t size, new_size; 130 __u64 bitno; 131 132 /* 133 * If we're expanding the bitmap, make sure all of the new 134 * parts of the bitmap are zero. 135 */ 136 if (new_end > bmap->end) { 137 bitno = bmap->real_end; 138 if (bitno > new_end) 139 bitno = new_end; 140 for (; bitno > bmap->end; bitno--) 141 ext2fs_clear_bit64(bitno - bmap->start, bp->bitarray); 142 } 143 if (new_real_end == bmap->real_end) { 144 bmap->end = new_end; 145 return 0; 146 } 147 148 size = ((bmap->real_end - bmap->start) / 8) + 1; 149 new_size = ((new_real_end - bmap->start) / 8) + 1; 150 151 if (size != new_size) { 152 retval = ext2fs_resize_mem(size, new_size, &bp->bitarray); 153 if (retval) 154 return retval; 155 } 156 if (new_size > size) 157 memset(bp->bitarray + size, 0, new_size - size); 158 159 bmap->end = new_end; 160 bmap->real_end = new_real_end; 161 return 0; 162 163} 164 165static int ba_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) 166{ 167 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 168 blk64_t bitno = (blk64_t) arg; 169 170 return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray); 171} 172 173static int ba_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) 174{ 175 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 176 blk64_t bitno = (blk64_t) arg; 177 178 return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray); 179} 180 181static int ba_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) 182{ 183 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 184 blk64_t bitno = (blk64_t) arg; 185 186 return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray); 187} 188 189static void ba_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, 190 unsigned int num) 191{ 192 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 193 blk64_t bitno = (blk64_t) arg; 194 unsigned int i; 195 196 for (i = 0; i < num; i++) 197 ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray); 198} 199 200static void ba_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, 201 unsigned int num) 202{ 203 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 204 blk64_t bitno = (blk64_t) arg; 205 unsigned int i; 206 207 for (i = 0; i < num; i++) 208 ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray); 209} 210 211static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap, 212 __u64 start, unsigned int len) 213{ 214 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 215 __u64 start_byte, len_byte = len >> 3; 216 unsigned int start_bit, len_bit = len % 8; 217 unsigned int first_bit = 0; 218 unsigned int last_bit = 0; 219 int mark_count = 0; 220 int mark_bit = 0; 221 int i; 222 const char *ADDR; 223 224 ADDR = bp->bitarray; 225 start -= bitmap->start; 226 start_byte = start >> 3; 227 start_bit = start % 8; 228 229 if (start_bit != 0) { 230 /* 231 * The compared start block number or start inode number 232 * is not the first bit in a byte. 233 */ 234 mark_count = 8 - start_bit; 235 if (len < 8 - start_bit) { 236 mark_count = (int)len; 237 mark_bit = len + start_bit - 1; 238 } else 239 mark_bit = 7; 240 241 for (i = mark_count; i > 0; i--, mark_bit--) 242 first_bit |= 1 << mark_bit; 243 244 /* 245 * Compare blocks or inodes in the first byte. 246 * If there is any marked bit, this function returns 0. 247 */ 248 if (first_bit & ADDR[start_byte]) 249 return 0; 250 else if (len <= 8 - start_bit) 251 return 1; 252 253 start_byte++; 254 len_bit = (len - mark_count) % 8; 255 len_byte = (len - mark_count) >> 3; 256 } 257 258 /* 259 * The compared start block number or start inode number is 260 * the first bit in a byte. 261 */ 262 if (len_bit != 0) { 263 /* 264 * The compared end block number or end inode number is 265 * not the last bit in a byte. 266 */ 267 for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--) 268 last_bit |= 1 << mark_bit; 269 270 /* 271 * Compare blocks or inodes in the last byte. 272 * If there is any marked bit, this function returns 0. 273 */ 274 if (last_bit & ADDR[start_byte + len_byte]) 275 return 0; 276 else if (len_byte == 0) 277 return 1; 278 } 279 280 /* Check whether all bytes are 0 */ 281 return ext2fs_mem_is_zero(ADDR + start_byte, len_byte); 282} 283 284 285static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap bitmap, 286 __u64 start, size_t num, void *in) 287{ 288 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 289 290 memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3); 291 292 return 0; 293} 294 295static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap bitmap, 296 __u64 start, size_t num, void *out) 297{ 298 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 299 300 memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3); 301 302 return 0; 303} 304 305static void ba_clear_bmap(ext2fs_generic_bitmap bitmap) 306{ 307 ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; 308 309 memset(bp->bitarray, 0, 310 (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); 311} 312 313static void ba_print_stats(ext2fs_generic_bitmap bitmap) 314{ 315 fprintf(stderr, "%16llu Bytes used by bitarray\n", 316 ((bitmap->real_end - bitmap->start) >> 3) + 1 + 317 sizeof(struct ext2fs_ba_private_struct)); 318} 319 320struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = { 321 .type = EXT2FS_BMAP64_BITARRAY, 322 .new_bmap = ba_new_bmap, 323 .free_bmap = ba_free_bmap, 324 .copy_bmap = ba_copy_bmap, 325 .resize_bmap = ba_resize_bmap, 326 .mark_bmap = ba_mark_bmap, 327 .unmark_bmap = ba_unmark_bmap, 328 .test_bmap = ba_test_bmap, 329 .test_clear_bmap_extent = ba_test_clear_bmap_extent, 330 .mark_bmap_extent = ba_mark_bmap_extent, 331 .unmark_bmap_extent = ba_unmark_bmap_extent, 332 .set_bmap_range = ba_set_bmap_range, 333 .get_bmap_range = ba_get_bmap_range, 334 .clear_bmap = ba_clear_bmap, 335 .print_stats = ba_print_stats, 336}; 337