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