Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and
      3  * block bitmaps.
      4  *
      5  * Copyright (C) 2007, 2008 Theodore Ts'o.
      6  *
      7  * %Begin-Header%
      8  * This file may be redistributed under the terms of the GNU Public
      9  * License.
     10  * %End-Header%
     11  */
     12 
     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 #include <errno.h>
     21 #if HAVE_SYS_STAT_H
     22 #include <sys/stat.h>
     23 #endif
     24 #if HAVE_SYS_TYPES_H
     25 #include <sys/types.h>
     26 #endif
     27 #ifdef HAVE_SYS_TIME_H
     28 #include <sys/time.h>
     29 #endif
     30 
     31 #include "ext2_fs.h"
     32 #include "ext2fsP.h"
     33 #include "bmap64.h"
     34 
     35 /*
     36  * Design of 64-bit bitmaps
     37  *
     38  * In order maintain ABI compatibility with programs that don't
     39  * understand about 64-bit blocks/inodes,
     40  * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap()
     41  * will create old-style bitmaps unless the application passes the
     42  * flag EXT2_FLAG_64BITS to ext2fs_open().  If this flag is
     43  * passed, then we know the application has been recompiled, so we can
     44  * use the new-style bitmaps.  If it is not passed, we have to return
     45  * an error if trying to open a filesystem which needs 64-bit bitmaps.
     46  *
     47  * The new bitmaps use a new set of structure magic numbers, so that
     48  * both the old-style and new-style interfaces can identify which
     49  * version of the data structure was used.  Both the old-style and
     50  * new-style interfaces will support either type of bitmap, although
     51  * of course 64-bit operation will only be possible when both the
     52  * new-style interface and the new-style bitmap are used.
     53  *
     54  * For example, the new bitmap interfaces will check the structure
     55  * magic numbers and so will be able to detect old-stype bitmap.  If
     56  * they see an old-style bitmap, they will pass it to the gen_bitmap.c
     57  * functions for handling.  The same will be true for the old
     58  * interfaces as well.
     59  *
     60  * The new-style interfaces will have several different back-end
     61  * implementations, so we can support different encodings that are
     62  * appropriate for different applications.  In general the default
     63  * should be whatever makes sense, and what the application/library
     64  * will use.  However, e2fsck may need specialized implementations for
     65  * its own uses.  For example, when doing parent directory pointer
     66  * loop detections in pass 3, the bitmap will *always* be sparse, so
     67  * e2fsck can request an encoding which is optimized for that.
     68  */
     69 
     70 static void warn_bitmap(ext2fs_generic_bitmap bitmap,
     71 			int code, __u64 arg)
     72 {
     73 #ifndef OMIT_COM_ERR
     74 	if (bitmap->description)
     75 		com_err(0, bitmap->base_error_code+code,
     76 			"#%llu for %s", arg, bitmap->description);
     77 	else
     78 		com_err(0, bitmap->base_error_code + code, "#%llu", arg);
     79 #endif
     80 }
     81 
     82 #ifdef BMAP_STATS_OPS
     83 #define INC_STAT(map, name) map->stats.name
     84 #else
     85 #define INC_STAT(map, name) ;;
     86 #endif
     87 
     88 
     89 errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
     90 				    int type, __u64 start, __u64 end,
     91 				    __u64 real_end,
     92 				    const char *descr,
     93 				    ext2fs_generic_bitmap *ret)
     94 {
     95 	ext2fs_generic_bitmap	bitmap;
     96 	struct ext2_bitmap_ops	*ops;
     97 	ext2_ino_t num_dirs;
     98 	errcode_t retval;
     99 
    100 	if (!type)
    101 		type = EXT2FS_BMAP64_BITARRAY;
    102 
    103 	switch (type) {
    104 	case EXT2FS_BMAP64_BITARRAY:
    105 		ops = &ext2fs_blkmap64_bitarray;
    106 		break;
    107 	case EXT2FS_BMAP64_RBTREE:
    108 		ops = &ext2fs_blkmap64_rbtree;
    109 		break;
    110 	case EXT2FS_BMAP64_AUTODIR:
    111 		retval = ext2fs_get_num_dirs(fs, &num_dirs);
    112 		if (retval || num_dirs > (fs->super->s_inodes_count / 320))
    113 			ops = &ext2fs_blkmap64_bitarray;
    114 		else
    115 			ops = &ext2fs_blkmap64_rbtree;
    116 		break;
    117 	default:
    118 		return EINVAL;
    119 	}
    120 
    121 	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
    122 				    &bitmap);
    123 	if (retval)
    124 		return retval;
    125 
    126 #ifdef BMAP_STATS
    127 	if (gettimeofday(&bitmap->stats.created,
    128 			 (struct timezone *) NULL) == -1) {
    129 		perror("gettimeofday");
    130 		ext2fs_free_mem(&bitmap);
    131 		return 1;
    132 	}
    133 	bitmap->stats.type = type;
    134 #endif
    135 
    136 	/* XXX factor out, repeated in copy_bmap */
    137 	bitmap->magic = magic;
    138 	bitmap->fs = fs;
    139 	bitmap->start = start;
    140 	bitmap->end = end;
    141 	bitmap->real_end = real_end;
    142 	bitmap->bitmap_ops = ops;
    143 	bitmap->cluster_bits = 0;
    144 	switch (magic) {
    145 	case EXT2_ET_MAGIC_INODE_BITMAP64:
    146 		bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
    147 		break;
    148 	case EXT2_ET_MAGIC_BLOCK_BITMAP64:
    149 		bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
    150 		bitmap->cluster_bits = fs->cluster_ratio_bits;
    151 		break;
    152 	default:
    153 		bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
    154 	}
    155 	if (descr) {
    156 		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
    157 		if (retval) {
    158 			ext2fs_free_mem(&bitmap);
    159 			return retval;
    160 		}
    161 		strcpy(bitmap->description, descr);
    162 	} else
    163 		bitmap->description = 0;
    164 
    165 	retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
    166 	if (retval) {
    167 		ext2fs_free_mem(&bitmap->description);
    168 		ext2fs_free_mem(&bitmap);
    169 		return retval;
    170 	}
    171 
    172 	*ret = bitmap;
    173 	return 0;
    174 }
    175 
    176 #ifdef BMAP_STATS
    177 static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
    178 {
    179 	struct ext2_bmap_statistics *stats = &bitmap->stats;
    180 #ifdef BMAP_STATS_OPS
    181 	float mark_seq_perc = 0.0, test_seq_perc = 0.0;
    182 	float mark_back_perc = 0.0, test_back_perc = 0.0;
    183 #endif
    184 	double inuse;
    185 	struct timeval now;
    186 
    187 #ifdef BMAP_STATS_OPS
    188 	if (stats->test_count) {
    189 		test_seq_perc = ((float)stats->test_seq /
    190 				 stats->test_count) * 100;
    191 		test_back_perc = ((float)stats->test_back /
    192 				  stats->test_count) * 100;
    193 	}
    194 
    195 	if (stats->mark_count) {
    196 		mark_seq_perc = ((float)stats->mark_seq /
    197 				 stats->mark_count) * 100;
    198 		mark_back_perc = ((float)stats->mark_back /
    199 				  stats->mark_count) * 100;
    200 	}
    201 #endif
    202 
    203 	if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
    204 		perror("gettimeofday");
    205 		return;
    206 	}
    207 
    208 	inuse = (double) now.tv_sec + \
    209 		(((double) now.tv_usec) * 0.000001);
    210 	inuse -= (double) stats->created.tv_sec + \
    211 		(((double) stats->created.tv_usec) * 0.000001);
    212 
    213 	fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
    214 		stats->type);
    215 	fprintf(stderr, "=================================================\n");
    216 #ifdef BMAP_STATS_OPS
    217 	fprintf(stderr, "%16llu bits long\n",
    218 		bitmap->real_end - bitmap->start);
    219 	fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
    220 		stats->copy_count, stats->resize_count);
    221 	fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n",
    222 		stats->mark_count, stats->unmark_count);
    223 	fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n",
    224 		stats->test_count, stats->mark_ext_count);
    225 	fprintf(stderr, "%16lu unmark_bmap_extent\n"
    226 		"%16lu test_clear_bmap_extent\n",
    227 		stats->unmark_ext_count, stats->test_ext_count);
    228 	fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n",
    229 		stats->set_range_count, stats->get_range_count);
    230 	fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n",
    231 		stats->clear_count, stats->test_seq, test_seq_perc);
    232 	fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n"
    233 		"%16llu bits tested backwards (%.2f%%)\n",
    234 		stats->mark_seq, mark_seq_perc,
    235 		stats->test_back, test_back_perc);
    236 	fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
    237 		"%16.2f seconds in use\n",
    238 		stats->mark_back, mark_back_perc, inuse);
    239 #endif /* BMAP_STATS_OPS */
    240 }
    241 #endif
    242 
    243 void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
    244 {
    245 	if (!bmap)
    246 		return;
    247 
    248 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    249 		ext2fs_free_generic_bitmap(bmap);
    250 		return;
    251 	}
    252 
    253 	if (!EXT2FS_IS_64_BITMAP(bmap))
    254 		return;
    255 
    256 #ifdef BMAP_STATS
    257 	if (getenv("E2FSPROGS_BITMAP_STATS")) {
    258 		ext2fs_print_bmap_statistics(bmap);
    259 		bmap->bitmap_ops->print_stats(bmap);
    260 	}
    261 #endif
    262 
    263 	bmap->bitmap_ops->free_bmap(bmap);
    264 
    265 	if (bmap->description) {
    266 		ext2fs_free_mem(&bmap->description);
    267 		bmap->description = 0;
    268 	}
    269 	bmap->magic = 0;
    270 	ext2fs_free_mem(&bmap);
    271 }
    272 
    273 errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
    274 				   ext2fs_generic_bitmap *dest)
    275 {
    276 	char *descr, *new_descr;
    277 	ext2fs_generic_bitmap	new_bmap;
    278 	errcode_t retval;
    279 
    280 	if (!src)
    281 		return EINVAL;
    282 
    283 	if (EXT2FS_IS_32_BITMAP(src))
    284 		return ext2fs_copy_generic_bitmap(src, dest);
    285 
    286 	if (!EXT2FS_IS_64_BITMAP(src))
    287 		return EINVAL;
    288 
    289 	/* Allocate a new bitmap struct */
    290 	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
    291 				    &new_bmap);
    292 	if (retval)
    293 		return retval;
    294 
    295 
    296 #ifdef BMAP_STATS_OPS
    297 	src->stats.copy_count++;
    298 #endif
    299 #ifdef BMAP_STATS
    300 	if (gettimeofday(&new_bmap->stats.created,
    301 			 (struct timezone *) NULL) == -1) {
    302 		perror("gettimeofday");
    303 		ext2fs_free_mem(&new_bmap);
    304 		return 1;
    305 	}
    306 	new_bmap->stats.type = src->stats.type;
    307 #endif
    308 
    309 	/* Copy all the high-level parts over */
    310 	new_bmap->magic = src->magic;
    311 	new_bmap->fs = src->fs;
    312 	new_bmap->start = src->start;
    313 	new_bmap->end = src->end;
    314 	new_bmap->real_end = src->real_end;
    315 	new_bmap->bitmap_ops = src->bitmap_ops;
    316 	new_bmap->base_error_code = src->base_error_code;
    317 	new_bmap->cluster_bits = src->cluster_bits;
    318 
    319 	descr = src->description;
    320 	if (descr) {
    321 		retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
    322 		if (retval) {
    323 			ext2fs_free_mem(&new_bmap);
    324 			return retval;
    325 		}
    326 		sprintf(new_descr, "copy of %s", descr);
    327 		new_bmap->description = new_descr;
    328 	}
    329 
    330 	retval = src->bitmap_ops->copy_bmap(src, new_bmap);
    331 	if (retval) {
    332 		ext2fs_free_mem(&new_bmap->description);
    333 		ext2fs_free_mem(&new_bmap);
    334 		return retval;
    335 	}
    336 
    337 	*dest = new_bmap;
    338 
    339 	return 0;
    340 }
    341 
    342 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
    343 				     __u64 new_end,
    344 				     __u64 new_real_end)
    345 {
    346 	if (!bmap)
    347 		return EINVAL;
    348 
    349 	if (EXT2FS_IS_32_BITMAP(bmap))
    350 		return ext2fs_resize_generic_bitmap(bmap->magic, new_end,
    351 						    new_real_end, bmap);
    352 
    353 	if (!EXT2FS_IS_64_BITMAP(bmap))
    354 		return EINVAL;
    355 
    356 	INC_STAT(bmap, resize_count);
    357 
    358 	return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
    359 }
    360 
    361 errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap,
    362 					errcode_t neq,
    363 					__u64 end, __u64 *oend)
    364 {
    365 	if (!bitmap)
    366 		return EINVAL;
    367 
    368 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    369 		ext2_ino_t tmp_oend;
    370 		int retval;
    371 
    372 		retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic,
    373 							 neq, end, &tmp_oend);
    374 		if (oend)
    375 			*oend = tmp_oend;
    376 		return retval;
    377 	}
    378 
    379 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    380 		return EINVAL;
    381 
    382 	if (end > bitmap->real_end)
    383 		return neq;
    384 	if (oend)
    385 		*oend = bitmap->end;
    386 	bitmap->end = end;
    387 	return 0;
    388 }
    389 
    390 __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap)
    391 {
    392 	if (!bitmap)
    393 		return EINVAL;
    394 
    395 	if (EXT2FS_IS_32_BITMAP(bitmap))
    396 		return ext2fs_get_generic_bitmap_start(bitmap);
    397 
    398 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    399 		return EINVAL;
    400 
    401 	return bitmap->start;
    402 }
    403 
    404 __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap)
    405 {
    406 	if (!bitmap)
    407 		return EINVAL;
    408 
    409 	if (EXT2FS_IS_32_BITMAP(bitmap))
    410 		return ext2fs_get_generic_bitmap_end(bitmap);
    411 
    412 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    413 		return EINVAL;
    414 
    415 	return bitmap->end;
    416 }
    417 
    418 void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap)
    419 {
    420 	if (EXT2FS_IS_32_BITMAP(bitmap))
    421 		ext2fs_clear_generic_bitmap(bitmap);
    422 	else
    423 		bitmap->bitmap_ops->clear_bmap (bitmap);
    424 }
    425 
    426 int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
    427 			     __u64 arg)
    428 {
    429 	if (!bitmap)
    430 		return 0;
    431 
    432 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    433 		if (arg & ~0xffffffffULL) {
    434 			ext2fs_warn_bitmap2(bitmap,
    435 					    EXT2FS_MARK_ERROR, 0xffffffff);
    436 			return 0;
    437 		}
    438 		return ext2fs_mark_generic_bitmap(bitmap, arg);
    439 	}
    440 
    441 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    442 		return 0;
    443 
    444 	arg >>= bitmap->cluster_bits;
    445 
    446 #ifdef BMAP_STATS_OPS
    447 	if (arg == bitmap->stats.last_marked + 1)
    448 		bitmap->stats.mark_seq++;
    449 	if (arg < bitmap->stats.last_marked)
    450 		bitmap->stats.mark_back++;
    451 	bitmap->stats.last_marked = arg;
    452 	bitmap->stats.mark_count++;
    453 #endif
    454 
    455 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    456 		warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
    457 		return 0;
    458 	}
    459 
    460 	return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
    461 }
    462 
    463 int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap,
    464 			       __u64 arg)
    465 {
    466 	if (!bitmap)
    467 		return 0;
    468 
    469 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    470 		if (arg & ~0xffffffffULL) {
    471 			ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR,
    472 					    0xffffffff);
    473 			return 0;
    474 		}
    475 		return ext2fs_unmark_generic_bitmap(bitmap, arg);
    476 	}
    477 
    478 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    479 		return 0;
    480 
    481 	arg >>= bitmap->cluster_bits;
    482 
    483 	INC_STAT(bitmap, unmark_count);
    484 
    485 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    486 		warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
    487 		return 0;
    488 	}
    489 
    490 	return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
    491 }
    492 
    493 int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
    494 			     __u64 arg)
    495 {
    496 	if (!bitmap)
    497 		return 0;
    498 
    499 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    500 		if (arg & ~0xffffffffULL) {
    501 			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR,
    502 					    0xffffffff);
    503 			return 0;
    504 		}
    505 		return ext2fs_test_generic_bitmap(bitmap, arg);
    506 	}
    507 
    508 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    509 		return 0;
    510 
    511 	arg >>= bitmap->cluster_bits;
    512 
    513 #ifdef BMAP_STATS_OPS
    514 	bitmap->stats.test_count++;
    515 	if (arg == bitmap->stats.last_tested + 1)
    516 		bitmap->stats.test_seq++;
    517 	if (arg < bitmap->stats.last_tested)
    518 		bitmap->stats.test_back++;
    519 	bitmap->stats.last_tested = arg;
    520 #endif
    521 
    522 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    523 		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
    524 		return 0;
    525 	}
    526 
    527 	return bitmap->bitmap_ops->test_bmap(bitmap, arg);
    528 }
    529 
    530 errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
    531 					__u64 start, unsigned int num,
    532 					void *in)
    533 {
    534 	if (!bmap)
    535 		return EINVAL;
    536 
    537 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    538 		if ((start+num-1) & ~0xffffffffULL) {
    539 			ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR,
    540 					    0xffffffff);
    541 			return EINVAL;
    542 		}
    543 		return ext2fs_set_generic_bitmap_range(bmap, bmap->magic,
    544 						       start, num, in);
    545 	}
    546 
    547 	if (!EXT2FS_IS_64_BITMAP(bmap))
    548 		return EINVAL;
    549 
    550 	INC_STAT(bmap, set_range_count);
    551 
    552 	return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
    553 }
    554 
    555 errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap,
    556 					__u64 start, unsigned int num,
    557 					void *out)
    558 {
    559 	if (!bmap)
    560 		return EINVAL;
    561 
    562 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    563 		if ((start+num-1) & ~0xffffffffULL) {
    564 			ext2fs_warn_bitmap2(bmap,
    565 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    566 			return EINVAL;
    567 		}
    568 		return ext2fs_get_generic_bitmap_range(bmap, bmap->magic,
    569 						       start, num, out);
    570 	}
    571 
    572 	if (!EXT2FS_IS_64_BITMAP(bmap))
    573 		return EINVAL;
    574 
    575 	INC_STAT(bmap, get_range_count);
    576 
    577 	return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
    578 }
    579 
    580 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
    581 				      ext2fs_generic_bitmap bm1,
    582 				      ext2fs_generic_bitmap bm2)
    583 {
    584 	blk64_t	i;
    585 
    586 	if (!bm1 || !bm2)
    587 		return EINVAL;
    588 	if (bm1->magic != bm2->magic)
    589 		return EINVAL;
    590 
    591 	/* Now we know both bitmaps have the same magic */
    592 	if (EXT2FS_IS_32_BITMAP(bm1))
    593 		return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2);
    594 
    595 	if (!EXT2FS_IS_64_BITMAP(bm1))
    596 		return EINVAL;
    597 
    598 	if ((bm1->start != bm2->start) ||
    599 	    (bm1->end != bm2->end))
    600 		return neq;
    601 
    602 	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
    603 		if (ext2fs_test_generic_bmap(bm1, i) !=
    604 		    ext2fs_test_generic_bmap(bm2, i))
    605 			return neq;
    606 
    607 	return 0;
    608 }
    609 
    610 void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
    611 {
    612 	__u64	start, num;
    613 
    614 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    615 		ext2fs_set_generic_bitmap_padding(bmap);
    616 		return;
    617 	}
    618 
    619 	start = bmap->end + 1;
    620 	num = bmap->real_end - bmap->end;
    621 	bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
    622 	/* XXX ought to warn on error */
    623 }
    624 
    625 int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
    626 				    blk64_t block, unsigned int num)
    627 {
    628 	__u64	end = block + num;
    629 
    630 	if (!bmap)
    631 		return EINVAL;
    632 
    633 	if (num == 1)
    634 		return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
    635 						 bmap, block);
    636 
    637 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    638 		if ((block+num-1) & ~0xffffffffULL) {
    639 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    640 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    641 			return EINVAL;
    642 		}
    643 		return ext2fs_test_block_bitmap_range(
    644 			(ext2fs_generic_bitmap) bmap, block, num);
    645 	}
    646 
    647 	if (!EXT2FS_IS_64_BITMAP(bmap))
    648 		return EINVAL;
    649 
    650 	INC_STAT(bmap, test_ext_count);
    651 
    652 	/* convert to clusters if necessary */
    653 	block >>= bmap->cluster_bits;
    654 	end += (1 << bmap->cluster_bits) - 1;
    655 	end >>= bmap->cluster_bits;
    656 	num = end - block;
    657 
    658 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    659 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
    660 				   bmap->description);
    661 		return EINVAL;
    662 	}
    663 
    664 	return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
    665 }
    666 
    667 void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
    668 				     blk64_t block, unsigned int num)
    669 {
    670 	__u64	end = block + num;
    671 
    672 	if (!bmap)
    673 		return;
    674 
    675 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    676 		if ((block+num-1) & ~0xffffffffULL) {
    677 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    678 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    679 			return;
    680 		}
    681 		ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
    682 					       block, num);
    683 	}
    684 
    685 	if (!EXT2FS_IS_64_BITMAP(bmap))
    686 		return;
    687 
    688 	INC_STAT(bmap, mark_ext_count);
    689 
    690 	/* convert to clusters if necessary */
    691 	block >>= bmap->cluster_bits;
    692 	end += (1 << bmap->cluster_bits) - 1;
    693 	end >>= bmap->cluster_bits;
    694 	num = end - block;
    695 
    696 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    697 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
    698 				   bmap->description);
    699 		return;
    700 	}
    701 
    702 	bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
    703 }
    704 
    705 void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
    706 				       blk64_t block, unsigned int num)
    707 {
    708 	__u64	end = block + num;
    709 
    710 	if (!bmap)
    711 		return;
    712 
    713 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    714 		if ((block+num-1) & ~0xffffffffULL) {
    715 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    716 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    717 			return;
    718 		}
    719 		ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
    720 						 block, num);
    721 	}
    722 
    723 	if (!EXT2FS_IS_64_BITMAP(bmap))
    724 		return;
    725 
    726 	INC_STAT(bmap, unmark_ext_count);
    727 
    728 	/* convert to clusters if necessary */
    729 	block >>= bmap->cluster_bits;
    730 	end += (1 << bmap->cluster_bits) - 1;
    731 	end >>= bmap->cluster_bits;
    732 	num = end - block;
    733 
    734 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    735 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
    736 				   bmap->description);
    737 		return;
    738 	}
    739 
    740 	bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
    741 }
    742 
    743 void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func)
    744 {
    745 #ifndef OMIT_COM_ERR
    746 	if (bitmap && bitmap->description)
    747 		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
    748 			"called %s with 64-bit bitmap for %s", func,
    749 			bitmap->description);
    750 	else
    751 		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
    752 			"called %s with 64-bit bitmap", func);
    753 #endif
    754 }
    755 
    756 errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
    757 					   ext2fs_block_bitmap *bitmap)
    758 {
    759 	ext2fs_block_bitmap	cmap, bmap;
    760 	errcode_t		retval;
    761 	blk64_t			i, b_end, c_end;
    762 	int			n, ratio;
    763 
    764 	bmap = *bitmap;
    765 
    766 	if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap))
    767 		return 0;	/* Nothing to do */
    768 
    769 	retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
    770 					      &cmap);
    771 	if (retval)
    772 		return retval;
    773 
    774 	i = bmap->start;
    775 	b_end = bmap->end;
    776 	bmap->end = bmap->real_end;
    777 	c_end = cmap->end;
    778 	cmap->end = cmap->real_end;
    779 	n = 0;
    780 	ratio = 1 << fs->cluster_ratio_bits;
    781 	while (i < bmap->real_end) {
    782 		if (ext2fs_test_block_bitmap2(bmap, i)) {
    783 			ext2fs_mark_block_bitmap2(cmap, i);
    784 			i += ratio - n;
    785 			n = 0;
    786 			continue;
    787 		}
    788 		i++; n++;
    789 		if (n >= ratio)
    790 			n = 0;
    791 	}
    792 	bmap->end = b_end;
    793 	cmap->end = c_end;
    794 	ext2fs_free_block_bitmap(bmap);
    795 	*bitmap = cmap;
    796 	return 0;
    797 }
    798 
    799 errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
    800 					      __u64 start, __u64 end, __u64 *out)
    801 {
    802 	int b;
    803 
    804 	if (!bitmap)
    805 		return EINVAL;
    806 
    807 	if (EXT2FS_IS_64_BITMAP(bitmap) && bitmap->bitmap_ops->find_first_zero)
    808 		return bitmap->bitmap_ops->find_first_zero(bitmap, start,
    809 							   end, out);
    810 
    811 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    812 		blk_t blk = 0;
    813 		errcode_t retval;
    814 
    815 		if (((start) & ~0xffffffffULL) ||
    816 		    ((end) & ~0xffffffffULL)) {
    817 			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
    818 			return EINVAL;
    819 		}
    820 
    821 		retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
    822 							       end, &blk);
    823 		if (retval == 0)
    824 			*out = blk;
    825 		return retval;
    826 	}
    827 
    828 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    829 		return EINVAL;
    830 
    831 	start >>= bitmap->cluster_bits;
    832 	end >>= bitmap->cluster_bits;
    833 
    834 	if (start < bitmap->start || end > bitmap->end || start > end) {
    835 		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start);
    836 		return EINVAL;
    837 	}
    838 
    839 	while (start <= end) {
    840 		b = bitmap->bitmap_ops->test_bmap(bitmap, start);
    841 		if (!b) {
    842 			*out = start << bitmap->cluster_bits;
    843 			return 0;
    844 		}
    845 		start++;
    846 	}
    847 
    848 	return ENOENT;
    849 }
    850