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