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_64 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_64 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_64),
    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 = (ext2fs_generic_bitmap) bitmap;
    174 	return 0;
    175 }
    176 
    177 #ifdef ENABLE_BMAP_STATS
    178 static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 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 gen_bmap)
    245 {
    246 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    247 
    248 	if (!bmap)
    249 		return;
    250 
    251 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    252 		ext2fs_free_generic_bitmap(gen_bmap);
    253 		return;
    254 	}
    255 
    256 	if (!EXT2FS_IS_64_BITMAP(bmap))
    257 		return;
    258 
    259 #ifdef ENABLE_BMAP_STATS
    260 	if (getenv("E2FSPROGS_BITMAP_STATS")) {
    261 		ext2fs_print_bmap_statistics(bmap);
    262 		bmap->bitmap_ops->print_stats(bmap);
    263 	}
    264 #endif
    265 
    266 	bmap->bitmap_ops->free_bmap(bmap);
    267 
    268 	if (bmap->description) {
    269 		ext2fs_free_mem(&bmap->description);
    270 		bmap->description = 0;
    271 	}
    272 	bmap->magic = 0;
    273 	ext2fs_free_mem(&bmap);
    274 }
    275 
    276 errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
    277 				   ext2fs_generic_bitmap *dest)
    278 {
    279 	ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
    280 	char *descr, *new_descr;
    281 	ext2fs_generic_bitmap_64 new_bmap;
    282 	errcode_t retval;
    283 
    284 	if (!src)
    285 		return EINVAL;
    286 
    287 	if (EXT2FS_IS_32_BITMAP(src))
    288 		return ext2fs_copy_generic_bitmap(gen_src, dest);
    289 
    290 	if (!EXT2FS_IS_64_BITMAP(src))
    291 		return EINVAL;
    292 
    293 	/* Allocate a new bitmap struct */
    294 	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
    295 				    &new_bmap);
    296 	if (retval)
    297 		return retval;
    298 
    299 
    300 #ifdef ENABLE_BMAP_STATS_OPS
    301 	src->stats.copy_count++;
    302 #endif
    303 #ifdef ENABLE_BMAP_STATS
    304 	if (gettimeofday(&new_bmap->stats.created,
    305 			 (struct timezone *) NULL) == -1) {
    306 		perror("gettimeofday");
    307 		ext2fs_free_mem(&new_bmap);
    308 		return 1;
    309 	}
    310 	new_bmap->stats.type = src->stats.type;
    311 #endif
    312 
    313 	/* Copy all the high-level parts over */
    314 	new_bmap->magic = src->magic;
    315 	new_bmap->fs = src->fs;
    316 	new_bmap->start = src->start;
    317 	new_bmap->end = src->end;
    318 	new_bmap->real_end = src->real_end;
    319 	new_bmap->bitmap_ops = src->bitmap_ops;
    320 	new_bmap->base_error_code = src->base_error_code;
    321 	new_bmap->cluster_bits = src->cluster_bits;
    322 
    323 	descr = src->description;
    324 	if (descr) {
    325 		retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
    326 		if (retval) {
    327 			ext2fs_free_mem(&new_bmap);
    328 			return retval;
    329 		}
    330 		strcpy(new_descr, "copy of ");
    331 		strcat(new_descr, descr);
    332 		new_bmap->description = new_descr;
    333 	}
    334 
    335 	retval = src->bitmap_ops->copy_bmap(src, new_bmap);
    336 	if (retval) {
    337 		ext2fs_free_mem(&new_bmap->description);
    338 		ext2fs_free_mem(&new_bmap);
    339 		return retval;
    340 	}
    341 
    342 	*dest = (ext2fs_generic_bitmap) new_bmap;
    343 
    344 	return 0;
    345 }
    346 
    347 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
    348 				     __u64 new_end,
    349 				     __u64 new_real_end)
    350 {
    351 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    352 
    353 	if (!bmap)
    354 		return EINVAL;
    355 
    356 	if (EXT2FS_IS_32_BITMAP(bmap))
    357 		return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
    358 						    new_real_end, gen_bmap);
    359 
    360 	if (!EXT2FS_IS_64_BITMAP(bmap))
    361 		return EINVAL;
    362 
    363 	INC_STAT(bmap, resize_count);
    364 
    365 	return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
    366 }
    367 
    368 errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
    369 					errcode_t neq,
    370 					__u64 end, __u64 *oend)
    371 {
    372 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    373 
    374 	if (!bitmap)
    375 		return EINVAL;
    376 
    377 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    378 		ext2_ino_t tmp_oend;
    379 		int retval;
    380 
    381 		retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
    382 							 bitmap->magic,
    383 							 neq, end, &tmp_oend);
    384 		if (oend)
    385 			*oend = tmp_oend;
    386 		return retval;
    387 	}
    388 
    389 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    390 		return EINVAL;
    391 
    392 	if (end > bitmap->real_end)
    393 		return neq;
    394 	if (oend)
    395 		*oend = bitmap->end;
    396 	bitmap->end = end;
    397 	return 0;
    398 }
    399 
    400 __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
    401 {
    402 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    403 
    404 	if (!bitmap)
    405 		return EINVAL;
    406 
    407 	if (EXT2FS_IS_32_BITMAP(bitmap))
    408 		return ext2fs_get_generic_bitmap_start(gen_bitmap);
    409 
    410 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    411 		return EINVAL;
    412 
    413 	return bitmap->start;
    414 }
    415 
    416 __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
    417 {
    418 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    419 
    420 	if (!bitmap)
    421 		return EINVAL;
    422 
    423 	if (EXT2FS_IS_32_BITMAP(bitmap))
    424 		return ext2fs_get_generic_bitmap_end(gen_bitmap);
    425 
    426 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    427 		return EINVAL;
    428 
    429 	return bitmap->end;
    430 }
    431 
    432 void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
    433 {
    434 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    435 
    436 	if (EXT2FS_IS_32_BITMAP(bitmap))
    437 		ext2fs_clear_generic_bitmap(gen_bitmap);
    438 	else
    439 		bitmap->bitmap_ops->clear_bmap(bitmap);
    440 }
    441 
    442 int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
    443 			     __u64 arg)
    444 {
    445 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    446 
    447 	if (!bitmap)
    448 		return 0;
    449 
    450 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    451 		if (arg & ~0xffffffffULL) {
    452 			ext2fs_warn_bitmap2(gen_bitmap,
    453 					    EXT2FS_MARK_ERROR, 0xffffffff);
    454 			return 0;
    455 		}
    456 		return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
    457 	}
    458 
    459 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    460 		return 0;
    461 
    462 	arg >>= bitmap->cluster_bits;
    463 
    464 #ifdef ENABLE_BMAP_STATS_OPS
    465 	if (arg == bitmap->stats.last_marked + 1)
    466 		bitmap->stats.mark_seq++;
    467 	if (arg < bitmap->stats.last_marked)
    468 		bitmap->stats.mark_back++;
    469 	bitmap->stats.last_marked = arg;
    470 	bitmap->stats.mark_count++;
    471 #endif
    472 
    473 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    474 		warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
    475 		return 0;
    476 	}
    477 
    478 	return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
    479 }
    480 
    481 int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
    482 			       __u64 arg)
    483 {
    484 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    485 
    486 	if (!bitmap)
    487 		return 0;
    488 
    489 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    490 		if (arg & ~0xffffffffULL) {
    491 			ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
    492 					    0xffffffff);
    493 			return 0;
    494 		}
    495 		return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
    496 	}
    497 
    498 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    499 		return 0;
    500 
    501 	arg >>= bitmap->cluster_bits;
    502 
    503 	INC_STAT(bitmap, unmark_count);
    504 
    505 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    506 		warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
    507 		return 0;
    508 	}
    509 
    510 	return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
    511 }
    512 
    513 int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
    514 			     __u64 arg)
    515 {
    516 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    517 	if (!bitmap)
    518 		return 0;
    519 
    520 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    521 		if (arg & ~0xffffffffULL) {
    522 			ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
    523 					    0xffffffff);
    524 			return 0;
    525 		}
    526 		return ext2fs_test_generic_bitmap(gen_bitmap, arg);
    527 	}
    528 
    529 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    530 		return 0;
    531 
    532 	arg >>= bitmap->cluster_bits;
    533 
    534 #ifdef ENABLE_BMAP_STATS_OPS
    535 	bitmap->stats.test_count++;
    536 	if (arg == bitmap->stats.last_tested + 1)
    537 		bitmap->stats.test_seq++;
    538 	if (arg < bitmap->stats.last_tested)
    539 		bitmap->stats.test_back++;
    540 	bitmap->stats.last_tested = arg;
    541 #endif
    542 
    543 	if ((arg < bitmap->start) || (arg > bitmap->end)) {
    544 		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
    545 		return 0;
    546 	}
    547 
    548 	return bitmap->bitmap_ops->test_bmap(bitmap, arg);
    549 }
    550 
    551 errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
    552 					__u64 start, unsigned int num,
    553 					void *in)
    554 {
    555 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    556 
    557 	if (!bmap)
    558 		return EINVAL;
    559 
    560 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    561 		if ((start+num-1) & ~0xffffffffULL) {
    562 			ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
    563 					    0xffffffff);
    564 			return EINVAL;
    565 		}
    566 		return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
    567 						       start, num, in);
    568 	}
    569 
    570 	if (!EXT2FS_IS_64_BITMAP(bmap))
    571 		return EINVAL;
    572 
    573 	INC_STAT(bmap, set_range_count);
    574 
    575 	return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
    576 }
    577 
    578 errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
    579 					__u64 start, unsigned int num,
    580 					void *out)
    581 {
    582 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    583 
    584 	if (!bmap)
    585 		return EINVAL;
    586 
    587 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    588 		if ((start+num-1) & ~0xffffffffULL) {
    589 			ext2fs_warn_bitmap2(gen_bmap,
    590 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    591 			return EINVAL;
    592 		}
    593 		return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
    594 						       start, num, out);
    595 	}
    596 
    597 	if (!EXT2FS_IS_64_BITMAP(bmap))
    598 		return EINVAL;
    599 
    600 	INC_STAT(bmap, get_range_count);
    601 
    602 	return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
    603 }
    604 
    605 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
    606 				      ext2fs_generic_bitmap gen_bm1,
    607 				      ext2fs_generic_bitmap gen_bm2)
    608 {
    609 	ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
    610 	ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
    611 	blk64_t	i;
    612 
    613 	if (!bm1 || !bm2)
    614 		return EINVAL;
    615 	if (bm1->magic != bm2->magic)
    616 		return EINVAL;
    617 
    618 	/* Now we know both bitmaps have the same magic */
    619 	if (EXT2FS_IS_32_BITMAP(bm1))
    620 		return ext2fs_compare_generic_bitmap(bm1->magic, neq,
    621 						     gen_bm1, gen_bm2);
    622 
    623 	if (!EXT2FS_IS_64_BITMAP(bm1))
    624 		return EINVAL;
    625 
    626 	if ((bm1->start != bm2->start) ||
    627 	    (bm1->end != bm2->end))
    628 		return neq;
    629 
    630 	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
    631 		if (ext2fs_test_generic_bmap(gen_bm1, i) !=
    632 		    ext2fs_test_generic_bmap(gen_bm2, i))
    633 			return neq;
    634 
    635 	return 0;
    636 }
    637 
    638 void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
    639 {
    640 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    641 	__u64	start, num;
    642 
    643 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    644 		ext2fs_set_generic_bitmap_padding(gen_bmap);
    645 		return;
    646 	}
    647 
    648 	start = bmap->end + 1;
    649 	num = bmap->real_end - bmap->end;
    650 	bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
    651 	/* XXX ought to warn on error */
    652 }
    653 
    654 int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
    655 				    blk64_t block, unsigned int num)
    656 {
    657 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    658 	__u64	end = block + num;
    659 
    660 	if (!bmap)
    661 		return EINVAL;
    662 
    663 	if (num == 1)
    664 		return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
    665 						 bmap, block);
    666 
    667 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    668 		if ((block+num-1) & ~0xffffffffULL) {
    669 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    670 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    671 			return EINVAL;
    672 		}
    673 		return ext2fs_test_block_bitmap_range(
    674 			(ext2fs_generic_bitmap) bmap, block, num);
    675 	}
    676 
    677 	if (!EXT2FS_IS_64_BITMAP(bmap))
    678 		return EINVAL;
    679 
    680 	INC_STAT(bmap, test_ext_count);
    681 
    682 	/* convert to clusters if necessary */
    683 	block >>= bmap->cluster_bits;
    684 	end += (1 << bmap->cluster_bits) - 1;
    685 	end >>= bmap->cluster_bits;
    686 	num = end - block;
    687 
    688 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    689 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
    690 				   bmap->description);
    691 		return EINVAL;
    692 	}
    693 
    694 	return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
    695 }
    696 
    697 void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
    698 				     blk64_t block, unsigned int num)
    699 {
    700 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    701 	__u64	end = block + num;
    702 
    703 	if (!bmap)
    704 		return;
    705 
    706 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    707 		if ((block+num-1) & ~0xffffffffULL) {
    708 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    709 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    710 			return;
    711 		}
    712 		ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
    713 					       block, num);
    714 	}
    715 
    716 	if (!EXT2FS_IS_64_BITMAP(bmap))
    717 		return;
    718 
    719 	INC_STAT(bmap, mark_ext_count);
    720 
    721 	/* convert to clusters if necessary */
    722 	block >>= bmap->cluster_bits;
    723 	end += (1 << bmap->cluster_bits) - 1;
    724 	end >>= bmap->cluster_bits;
    725 	num = end - block;
    726 
    727 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    728 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
    729 				   bmap->description);
    730 		return;
    731 	}
    732 
    733 	bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
    734 }
    735 
    736 void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
    737 				       blk64_t block, unsigned int num)
    738 {
    739 	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    740 	__u64	end = block + num;
    741 
    742 	if (!bmap)
    743 		return;
    744 
    745 	if (EXT2FS_IS_32_BITMAP(bmap)) {
    746 		if ((block+num-1) & ~0xffffffffULL) {
    747 			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
    748 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
    749 			return;
    750 		}
    751 		ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
    752 						 block, num);
    753 	}
    754 
    755 	if (!EXT2FS_IS_64_BITMAP(bmap))
    756 		return;
    757 
    758 	INC_STAT(bmap, unmark_ext_count);
    759 
    760 	/* convert to clusters if necessary */
    761 	block >>= bmap->cluster_bits;
    762 	end += (1 << bmap->cluster_bits) - 1;
    763 	end >>= bmap->cluster_bits;
    764 	num = end - block;
    765 
    766 	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
    767 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
    768 				   bmap->description);
    769 		return;
    770 	}
    771 
    772 	bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
    773 }
    774 
    775 void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
    776 {
    777 	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
    778 
    779 #ifndef OMIT_COM_ERR
    780 	if (bitmap && bitmap->description)
    781 		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
    782 			"called %s with 64-bit bitmap for %s", func,
    783 			bitmap->description);
    784 	else
    785 		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
    786 			"called %s with 64-bit bitmap", func);
    787 #endif
    788 }
    789 
    790 errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
    791 					   ext2fs_block_bitmap *bitmap)
    792 {
    793 	ext2fs_generic_bitmap_64 bmap, cmap;
    794 	ext2fs_block_bitmap	gen_bmap = *bitmap, gen_cmap;
    795 	errcode_t		retval;
    796 	blk64_t			i, b_end, c_end;
    797 	int			n, ratio;
    798 
    799 	bmap = (ext2fs_generic_bitmap_64) gen_bmap;
    800 	if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap))
    801 		return 0;	/* Nothing to do */
    802 
    803 	retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
    804 					      &gen_cmap);
    805 	if (retval)
    806 		return retval;
    807 
    808 	cmap = (ext2fs_generic_bitmap_64) gen_cmap;
    809 	i = bmap->start;
    810 	b_end = bmap->end;
    811 	bmap->end = bmap->real_end;
    812 	c_end = cmap->end;
    813 	cmap->end = cmap->real_end;
    814 	n = 0;
    815 	ratio = 1 << fs->cluster_ratio_bits;
    816 	while (i < bmap->real_end) {
    817 		if (ext2fs_test_block_bitmap2(gen_bmap, i)) {
    818 			ext2fs_mark_block_bitmap2(gen_cmap, i);
    819 			i += ratio - n;
    820 			n = 0;
    821 			continue;
    822 		}
    823 		i++; n++;
    824 		if (n >= ratio)
    825 			n = 0;
    826 	}
    827 	bmap->end = b_end;
    828 	cmap->end = c_end;
    829 	ext2fs_free_block_bitmap(gen_bmap);
    830 	*bitmap = (ext2fs_block_bitmap) cmap;
    831 	return 0;
    832 }
    833 
    834 errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
    835 					      __u64 start, __u64 end, __u64 *out)
    836 {
    837 	ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
    838 	__u64 cstart, cend, cout;
    839 	errcode_t retval;
    840 
    841 	if (!bitmap)
    842 		return EINVAL;
    843 
    844 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    845 		blk_t blk = 0;
    846 
    847 		if (((start) & ~0xffffffffULL) ||
    848 		    ((end) & ~0xffffffffULL)) {
    849 			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
    850 			return EINVAL;
    851 		}
    852 
    853 		retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
    854 							       end, &blk);
    855 		if (retval == 0)
    856 			*out = blk;
    857 		return retval;
    858 	}
    859 
    860 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    861 		return EINVAL;
    862 
    863 	cstart = start >> bmap64->cluster_bits;
    864 	cend = end >> bmap64->cluster_bits;
    865 
    866 	if (cstart < bmap64->start || cend > bmap64->end || start > end) {
    867 		warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
    868 		return EINVAL;
    869 	}
    870 
    871 	if (bmap64->bitmap_ops->find_first_zero) {
    872 		retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
    873 							     cend, &cout);
    874 		if (retval)
    875 			return retval;
    876 	found:
    877 		cout <<= bmap64->cluster_bits;
    878 		*out = (cout >= start) ? cout : start;
    879 		return 0;
    880 	}
    881 
    882 	for (cout = cstart; cout <= cend; cout++)
    883 		if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
    884 			goto found;
    885 
    886 	return ENOENT;
    887 }
    888 
    889 errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
    890 					     __u64 start, __u64 end, __u64 *out)
    891 {
    892 	ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
    893 	__u64 cstart, cend, cout;
    894 	errcode_t retval;
    895 
    896 	if (!bitmap)
    897 		return EINVAL;
    898 
    899 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
    900 		blk_t blk = 0;
    901 
    902 		if (((start) & ~0xffffffffULL) ||
    903 		    ((end) & ~0xffffffffULL)) {
    904 			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
    905 			return EINVAL;
    906 		}
    907 
    908 		retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
    909 							      end, &blk);
    910 		if (retval == 0)
    911 			*out = blk;
    912 		return retval;
    913 	}
    914 
    915 	if (!EXT2FS_IS_64_BITMAP(bitmap))
    916 		return EINVAL;
    917 
    918 	cstart = start >> bmap64->cluster_bits;
    919 	cend = end >> bmap64->cluster_bits;
    920 
    921 	if (cstart < bmap64->start || cend > bmap64->end || start > end) {
    922 		warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
    923 		return EINVAL;
    924 	}
    925 
    926 	if (bmap64->bitmap_ops->find_first_set) {
    927 		retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
    928 							    cend, &cout);
    929 		if (retval)
    930 			return retval;
    931 	found:
    932 		cout <<= bmap64->cluster_bits;
    933 		*out = (cout >= start) ? cout : start;
    934 		return 0;
    935 	}
    936 
    937 	for (cout = cstart; cout <= cend; cout++)
    938 		if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
    939 			goto found;
    940 
    941 	return ENOENT;
    942 }
    943