]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/gen_bitmap64.c
mke2fs: set overhead in super block
[thirdparty/e2fsprogs.git] / lib / ext2fs / gen_bitmap64.c
CommitLineData
69365c68
TT
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
d1154eb4 13#include "config.h"
69365c68
TT
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
b96365f8
MF
28#ifdef HAVE_SYS_TIME_H
29#include <sys/time.h>
30#endif
69365c68
TT
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
83d9ffcc 71static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap,
69365c68
TT
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
1625bf42 83#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
84#define INC_STAT(map, name) map->stats.name
85#else
86#define INC_STAT(map, name) ;;
87#endif
88
69365c68
TT
89
90errcode_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{
83d9ffcc 96 ext2fs_generic_bitmap_64 bitmap;
69365c68 97 struct ext2_bitmap_ops *ops;
d182831a 98 ext2_ino_t num_dirs;
69365c68
TT
99 errcode_t retval;
100
67861e5b
TT
101 if (!type)
102 type = EXT2FS_BMAP64_BITARRAY;
103
69365c68
TT
104 switch (type) {
105 case EXT2FS_BMAP64_BITARRAY:
106 ops = &ext2fs_blkmap64_bitarray;
107 break;
c1359d91
LC
108 case EXT2FS_BMAP64_RBTREE:
109 ops = &ext2fs_blkmap64_rbtree;
110 break;
d182831a
TT
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;
69365c68
TT
118 default:
119 return EINVAL;
120 }
121
83d9ffcc 122 retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
9288e3be 123 &bitmap);
69365c68
TT
124 if (retval)
125 return retval;
126
1625bf42 127#ifdef ENABLE_BMAP_STATS
9288e3be
LC
128 if (gettimeofday(&bitmap->stats.created,
129 (struct timezone *) NULL) == -1) {
130 perror("gettimeofday");
6a26b38a 131 ext2fs_free_mem(&bitmap);
9288e3be
LC
132 return 1;
133 }
134 bitmap->stats.type = type;
135#endif
136
69365c68
TT
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;
94968e74 144 bitmap->cluster_bits = 0;
69365c68
TT
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;
94968e74 151 bitmap->cluster_bits = fs->cluster_ratio_bits;
69365c68
TT
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) {
69365c68 168 ext2fs_free_mem(&bitmap->description);
ba7cb5d9 169 ext2fs_free_mem(&bitmap);
69365c68
TT
170 return retval;
171 }
172
83d9ffcc 173 *ret = (ext2fs_generic_bitmap) bitmap;
69365c68
TT
174 return 0;
175}
176
1625bf42 177#ifdef ENABLE_BMAP_STATS
83d9ffcc 178static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap)
9288e3be
LC
179{
180 struct ext2_bmap_statistics *stats = &bitmap->stats;
1625bf42 181#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
182 float mark_seq_perc = 0.0, test_seq_perc = 0.0;
183 float mark_back_perc = 0.0, test_back_perc = 0.0;
e64e6761 184#endif
9288e3be
LC
185 double inuse;
186 struct timeval now;
187
1625bf42 188#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
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");
1625bf42 217#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
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);
1625bf42 240#endif /* ENABLE_BMAP_STATS_OPS */
9288e3be
LC
241}
242#endif
243
83d9ffcc 244void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap)
69365c68 245{
83d9ffcc
TT
246 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
247
69365c68
TT
248 if (!bmap)
249 return;
250
251 if (EXT2FS_IS_32_BITMAP(bmap)) {
83d9ffcc 252 ext2fs_free_generic_bitmap(gen_bmap);
69365c68
TT
253 return;
254 }
255
256 if (!EXT2FS_IS_64_BITMAP(bmap))
257 return;
258
1625bf42 259#ifdef ENABLE_BMAP_STATS
9288e3be
LC
260 if (getenv("E2FSPROGS_BITMAP_STATS")) {
261 ext2fs_print_bmap_statistics(bmap);
262 bmap->bitmap_ops->print_stats(bmap);
263 }
264#endif
265
69365c68
TT
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;
5fff9754 273 ext2fs_free_mem(&bmap);
69365c68
TT
274}
275
83d9ffcc 276errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
69365c68
TT
277 ext2fs_generic_bitmap *dest)
278{
83d9ffcc 279 ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
69365c68 280 char *descr, *new_descr;
83d9ffcc 281 ext2fs_generic_bitmap_64 new_bmap;
69365c68
TT
282 errcode_t retval;
283
284 if (!src)
285 return EINVAL;
286
287 if (EXT2FS_IS_32_BITMAP(src))
83d9ffcc 288 return ext2fs_copy_generic_bitmap(gen_src, dest);
69365c68
TT
289
290 if (!EXT2FS_IS_64_BITMAP(src))
291 return EINVAL;
292
293 /* Allocate a new bitmap struct */
83d9ffcc 294 retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
9288e3be 295 &new_bmap);
69365c68
TT
296 if (retval)
297 return retval;
298
9288e3be 299
1625bf42 300#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
301 src->stats.copy_count++;
302#endif
1625bf42 303#ifdef ENABLE_BMAP_STATS
9288e3be
LC
304 if (gettimeofday(&new_bmap->stats.created,
305 (struct timezone *) NULL) == -1) {
306 perror("gettimeofday");
6a26b38a 307 ext2fs_free_mem(&new_bmap);
9288e3be
LC
308 return 1;
309 }
310 new_bmap->stats.type = src->stats.type;
311#endif
312
69365c68
TT
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;
9c79612f 321 new_bmap->cluster_bits = src->cluster_bits;
69365c68
TT
322
323 descr = src->description;
324 if (descr) {
4a61d17c 325 retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
69365c68
TT
326 if (retval) {
327 ext2fs_free_mem(&new_bmap);
328 return retval;
329 }
c4111cd7
TT
330 strcpy(new_descr, "copy of ");
331 strcat(new_descr, descr);
69365c68
TT
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
83d9ffcc 342 *dest = (ext2fs_generic_bitmap) new_bmap;
69365c68
TT
343
344 return 0;
345}
346
83d9ffcc 347errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
69365c68
TT
348 __u64 new_end,
349 __u64 new_real_end)
350{
83d9ffcc
TT
351 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
352
69365c68
TT
353 if (!bmap)
354 return EINVAL;
355
877d1dc0 356 if (EXT2FS_IS_32_BITMAP(bmap))
83d9ffcc
TT
357 return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
358 new_real_end, gen_bmap);
69365c68
TT
359
360 if (!EXT2FS_IS_64_BITMAP(bmap))
361 return EINVAL;
362
9288e3be
LC
363 INC_STAT(bmap, resize_count);
364
69365c68
TT
365 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
366}
367
83d9ffcc 368errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
69365c68
TT
369 errcode_t neq,
370 __u64 end, __u64 *oend)
371{
83d9ffcc
TT
372 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
373
69365c68
TT
374 if (!bitmap)
375 return EINVAL;
376
377 if (EXT2FS_IS_32_BITMAP(bitmap)) {
378 ext2_ino_t tmp_oend;
379 int retval;
380
83d9ffcc
TT
381 retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
382 bitmap->magic,
877d1dc0 383 neq, end, &tmp_oend);
69365c68
TT
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
83d9ffcc 400__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
69365c68 401{
83d9ffcc
TT
402 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
403
69365c68
TT
404 if (!bitmap)
405 return EINVAL;
406
877d1dc0 407 if (EXT2FS_IS_32_BITMAP(bitmap))
83d9ffcc 408 return ext2fs_get_generic_bitmap_start(gen_bitmap);
69365c68
TT
409
410 if (!EXT2FS_IS_64_BITMAP(bitmap))
411 return EINVAL;
412
413 return bitmap->start;
414}
415
83d9ffcc 416__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
69365c68 417{
83d9ffcc
TT
418 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
419
69365c68
TT
420 if (!bitmap)
421 return EINVAL;
422
877d1dc0 423 if (EXT2FS_IS_32_BITMAP(bitmap))
83d9ffcc 424 return ext2fs_get_generic_bitmap_end(gen_bitmap);
69365c68
TT
425
426 if (!EXT2FS_IS_64_BITMAP(bitmap))
427 return EINVAL;
428
429 return bitmap->end;
430}
431
83d9ffcc 432void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
69365c68 433{
83d9ffcc
TT
434 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
435
877d1dc0 436 if (EXT2FS_IS_32_BITMAP(bitmap))
83d9ffcc 437 ext2fs_clear_generic_bitmap(gen_bitmap);
ba37bb70 438 else
83d9ffcc 439 bitmap->bitmap_ops->clear_bmap(bitmap);
69365c68
TT
440}
441
83d9ffcc 442int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
69365c68
TT
443 __u64 arg)
444{
83d9ffcc
TT
445 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
446
69365c68
TT
447 if (!bitmap)
448 return 0;
449
450 if (EXT2FS_IS_32_BITMAP(bitmap)) {
451 if (arg & ~0xffffffffULL) {
83d9ffcc 452 ext2fs_warn_bitmap2(gen_bitmap,
69365c68
TT
453 EXT2FS_MARK_ERROR, 0xffffffff);
454 return 0;
455 }
83d9ffcc 456 return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
69365c68
TT
457 }
458
459 if (!EXT2FS_IS_64_BITMAP(bitmap))
460 return 0;
461
94968e74
TT
462 arg >>= bitmap->cluster_bits;
463
1625bf42 464#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
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
69365c68
TT
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
83d9ffcc 481int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
69365c68
TT
482 __u64 arg)
483{
83d9ffcc
TT
484 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
485
69365c68
TT
486 if (!bitmap)
487 return 0;
488
489 if (EXT2FS_IS_32_BITMAP(bitmap)) {
490 if (arg & ~0xffffffffULL) {
83d9ffcc 491 ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
877d1dc0 492 0xffffffff);
69365c68
TT
493 return 0;
494 }
83d9ffcc 495 return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
69365c68
TT
496 }
497
498 if (!EXT2FS_IS_64_BITMAP(bitmap))
499 return 0;
500
94968e74
TT
501 arg >>= bitmap->cluster_bits;
502
9288e3be
LC
503 INC_STAT(bitmap, unmark_count);
504
69365c68
TT
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
83d9ffcc 513int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
69365c68
TT
514 __u64 arg)
515{
83d9ffcc 516 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
69365c68
TT
517 if (!bitmap)
518 return 0;
519
520 if (EXT2FS_IS_32_BITMAP(bitmap)) {
521 if (arg & ~0xffffffffULL) {
83d9ffcc 522 ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
877d1dc0 523 0xffffffff);
69365c68
TT
524 return 0;
525 }
83d9ffcc 526 return ext2fs_test_generic_bitmap(gen_bitmap, arg);
69365c68
TT
527 }
528
529 if (!EXT2FS_IS_64_BITMAP(bitmap))
530 return 0;
531
94968e74
TT
532 arg >>= bitmap->cluster_bits;
533
1625bf42 534#ifdef ENABLE_BMAP_STATS_OPS
9288e3be
LC
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
69365c68
TT
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
83d9ffcc 551errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
69365c68
TT
552 __u64 start, unsigned int num,
553 void *in)
554{
83d9ffcc
TT
555 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
556
69365c68
TT
557 if (!bmap)
558 return EINVAL;
559
560 if (EXT2FS_IS_32_BITMAP(bmap)) {
15749d7d 561 if ((start+num-1) & ~0xffffffffULL) {
83d9ffcc 562 ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
877d1dc0 563 0xffffffff);
69365c68
TT
564 return EINVAL;
565 }
83d9ffcc 566 return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
877d1dc0 567 start, num, in);
69365c68
TT
568 }
569
570 if (!EXT2FS_IS_64_BITMAP(bmap))
571 return EINVAL;
572
9288e3be
LC
573 INC_STAT(bmap, set_range_count);
574
69365c68
TT
575 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
576}
577
83d9ffcc 578errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
69365c68
TT
579 __u64 start, unsigned int num,
580 void *out)
581{
83d9ffcc
TT
582 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
583
69365c68
TT
584 if (!bmap)
585 return EINVAL;
586
587 if (EXT2FS_IS_32_BITMAP(bmap)) {
15749d7d 588 if ((start+num-1) & ~0xffffffffULL) {
83d9ffcc 589 ext2fs_warn_bitmap2(gen_bmap,
69365c68
TT
590 EXT2FS_UNMARK_ERROR, 0xffffffff);
591 return EINVAL;
592 }
83d9ffcc 593 return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
877d1dc0 594 start, num, out);
69365c68
TT
595 }
596
597 if (!EXT2FS_IS_64_BITMAP(bmap))
598 return EINVAL;
599
9288e3be
LC
600 INC_STAT(bmap, get_range_count);
601
69365c68
TT
602 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
603}
604
605errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
83d9ffcc
TT
606 ext2fs_generic_bitmap gen_bm1,
607 ext2fs_generic_bitmap gen_bm2)
69365c68 608{
83d9ffcc
TT
609 ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
610 ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
69365c68
TT
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))
83d9ffcc
TT
620 return ext2fs_compare_generic_bitmap(bm1->magic, neq,
621 gen_bm1, gen_bm2);
69365c68
TT
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++)
83d9ffcc
TT
631 if (ext2fs_test_generic_bmap(gen_bm1, i) !=
632 ext2fs_test_generic_bmap(gen_bm2, i))
69365c68
TT
633 return neq;
634
635 return 0;
636}
637
83d9ffcc 638void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
69365c68 639{
83d9ffcc 640 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
69365c68
TT
641 __u64 start, num;
642
643 if (EXT2FS_IS_32_BITMAP(bmap)) {
83d9ffcc 644 ext2fs_set_generic_bitmap_padding(gen_bmap);
69365c68
TT
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
83d9ffcc 654int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
69365c68
TT
655 blk64_t block, unsigned int num)
656{
83d9ffcc 657 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
3e1816b8
TT
658 __u64 end = block + num;
659
69365c68
TT
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)) {
92c55949
TT
668 if ((block & ~0xffffffffULL) ||
669 ((block+num-1) & ~0xffffffffULL)) {
69365c68
TT
670 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
671 EXT2FS_UNMARK_ERROR, 0xffffffff);
672 return EINVAL;
673 }
674 return ext2fs_test_block_bitmap_range(
675 (ext2fs_generic_bitmap) bmap, block, num);
676 }
677
678 if (!EXT2FS_IS_64_BITMAP(bmap))
679 return EINVAL;
680
9288e3be
LC
681 INC_STAT(bmap, test_ext_count);
682
3e1816b8
TT
683 /* convert to clusters if necessary */
684 block >>= bmap->cluster_bits;
685 end += (1 << bmap->cluster_bits) - 1;
686 end >>= bmap->cluster_bits;
687 num = end - block;
688
92c55949
TT
689 if ((block < bmap->start) || (block > bmap->end) ||
690 (block+num-1 > bmap->end)) {
3e1816b8
TT
691 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
692 bmap->description);
0d89e5ac 693 return EINVAL;
3e1816b8
TT
694 }
695
69365c68
TT
696 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
697}
698
83d9ffcc 699void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
69365c68
TT
700 blk64_t block, unsigned int num)
701{
83d9ffcc 702 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
3e1816b8
TT
703 __u64 end = block + num;
704
69365c68
TT
705 if (!bmap)
706 return;
707
708 if (EXT2FS_IS_32_BITMAP(bmap)) {
92c55949
TT
709 if ((block & ~0xffffffffULL) ||
710 ((block+num-1) & ~0xffffffffULL)) {
69365c68
TT
711 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
712 EXT2FS_UNMARK_ERROR, 0xffffffff);
713 return;
714 }
715 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
716 block, num);
717 }
718
719 if (!EXT2FS_IS_64_BITMAP(bmap))
720 return;
721
9288e3be
LC
722 INC_STAT(bmap, mark_ext_count);
723
3e1816b8
TT
724 /* convert to clusters if necessary */
725 block >>= bmap->cluster_bits;
726 end += (1 << bmap->cluster_bits) - 1;
727 end >>= bmap->cluster_bits;
728 num = end - block;
729
92c55949
TT
730 if ((block < bmap->start) || (block > bmap->end) ||
731 (block+num-1 > bmap->end)) {
69365c68
TT
732 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
733 bmap->description);
734 return;
735 }
736
737 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
738}
739
83d9ffcc 740void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
69365c68
TT
741 blk64_t block, unsigned int num)
742{
83d9ffcc 743 ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
3e1816b8
TT
744 __u64 end = block + num;
745
69365c68
TT
746 if (!bmap)
747 return;
748
749 if (EXT2FS_IS_32_BITMAP(bmap)) {
92c55949
TT
750 if ((block & ~0xffffffffULL) ||
751 ((block+num-1) & ~0xffffffffULL)) {
69365c68
TT
752 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
753 EXT2FS_UNMARK_ERROR, 0xffffffff);
754 return;
755 }
756 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
757 block, num);
758 }
759
760 if (!EXT2FS_IS_64_BITMAP(bmap))
761 return;
762
9288e3be
LC
763 INC_STAT(bmap, unmark_ext_count);
764
3e1816b8
TT
765 /* convert to clusters if necessary */
766 block >>= bmap->cluster_bits;
767 end += (1 << bmap->cluster_bits) - 1;
768 end >>= bmap->cluster_bits;
769 num = end - block;
770
92c55949
TT
771 if ((block < bmap->start) || (block > bmap->end) ||
772 (block+num-1 > bmap->end)) {
69365c68
TT
773 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
774 bmap->description);
775 return;
776 }
777
778 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
779}
c21cde99 780
83d9ffcc 781void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
c21cde99 782{
83d9ffcc
TT
783 ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
784
c21cde99
TT
785#ifndef OMIT_COM_ERR
786 if (bitmap && bitmap->description)
787 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
788 "called %s with 64-bit bitmap for %s", func,
789 bitmap->description);
790 else
791 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
792 "called %s with 64-bit bitmap", func);
793#endif
794}
94968e74
TT
795
796errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
797 ext2fs_block_bitmap *bitmap)
798{
83d9ffcc
TT
799 ext2fs_generic_bitmap_64 bmap, cmap;
800 ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap;
94968e74 801 errcode_t retval;
bd828b0d 802 blk64_t i, next, b_end, c_end;
94968e74 803
83d9ffcc
TT
804 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
805 if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap))
94968e74
TT
806 return 0; /* Nothing to do */
807
808 retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
83d9ffcc 809 &gen_cmap);
94968e74
TT
810 if (retval)
811 return retval;
812
83d9ffcc 813 cmap = (ext2fs_generic_bitmap_64) gen_cmap;
94968e74
TT
814 i = bmap->start;
815 b_end = bmap->end;
816 bmap->end = bmap->real_end;
817 c_end = cmap->end;
818 cmap->end = cmap->real_end;
94968e74 819 while (i < bmap->real_end) {
bd828b0d
LD
820 retval = ext2fs_find_first_set_block_bitmap2(gen_bmap,
821 i, bmap->real_end, &next);
822 if (retval)
823 break;
824 ext2fs_mark_block_bitmap2(gen_cmap, next);
825 i = EXT2FS_C2B(fs, EXT2FS_B2C(fs, next) + 1);
94968e74
TT
826 }
827 bmap->end = b_end;
828 cmap->end = c_end;
83d9ffcc
TT
829 ext2fs_free_block_bitmap(gen_bmap);
830 *bitmap = (ext2fs_block_bitmap) cmap;
94968e74
TT
831 return 0;
832}
c1a1e7fc
SL
833
834errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
835 __u64 start, __u64 end, __u64 *out)
836{
83d9ffcc 837 ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
36021974
TT
838 __u64 cstart, cend, cout;
839 errcode_t retval;
c1a1e7fc 840
664c3326
TT
841 if (!bitmap)
842 return EINVAL;
c1a1e7fc 843
664c3326
TT
844 if (EXT2FS_IS_32_BITMAP(bitmap)) {
845 blk_t blk = 0;
664c3326
TT
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))
c1a1e7fc
SL
861 return EINVAL;
862
83d9ffcc
TT
863 cstart = start >> bmap64->cluster_bits;
864 cend = end >> bmap64->cluster_bits;
664c3326 865
83d9ffcc
TT
866 if (cstart < bmap64->start || cend > bmap64->end || start > end) {
867 warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
c1a1e7fc
SL
868 return EINVAL;
869 }
870
83d9ffcc
TT
871 if (bmap64->bitmap_ops->find_first_zero) {
872 retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
36021974
TT
873 cend, &cout);
874 if (retval)
875 return retval;
876 found:
83d9ffcc 877 cout <<= bmap64->cluster_bits;
36021974
TT
878 *out = (cout >= start) ? cout : start;
879 return 0;
c1a1e7fc
SL
880 }
881
36021974 882 for (cout = cstart; cout <= cend; cout++)
83d9ffcc 883 if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
36021974
TT
884 goto found;
885
c1a1e7fc
SL
886 return ENOENT;
887}
dff0b6a3
TT
888
889errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
890 __u64 start, __u64 end, __u64 *out)
891{
83d9ffcc 892 ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
36021974
TT
893 __u64 cstart, cend, cout;
894 errcode_t retval;
dff0b6a3
TT
895
896 if (!bitmap)
897 return EINVAL;
898
dff0b6a3
TT
899 if (EXT2FS_IS_32_BITMAP(bitmap)) {
900 blk_t blk = 0;
dff0b6a3
TT
901
902 if (((start) & ~0xffffffffULL) ||
903 ((end) & ~0xffffffffULL)) {
904 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
905 return EINVAL;
c1a1e7fc 906 }
dff0b6a3
TT
907
908 retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
909 end, &blk);
910 if (retval == 0)
911 *out = blk;
912 return retval;
c1a1e7fc
SL
913 }
914
dff0b6a3
TT
915 if (!EXT2FS_IS_64_BITMAP(bitmap))
916 return EINVAL;
917
83d9ffcc
TT
918 cstart = start >> bmap64->cluster_bits;
919 cend = end >> bmap64->cluster_bits;
dff0b6a3 920
83d9ffcc
TT
921 if (cstart < bmap64->start || cend > bmap64->end || start > end) {
922 warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
dff0b6a3
TT
923 return EINVAL;
924 }
925
83d9ffcc
TT
926 if (bmap64->bitmap_ops->find_first_set) {
927 retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
36021974
TT
928 cend, &cout);
929 if (retval)
930 return retval;
931 found:
83d9ffcc 932 cout <<= bmap64->cluster_bits;
36021974
TT
933 *out = (cout >= start) ? cout : start;
934 return 0;
dff0b6a3
TT
935 }
936
36021974 937 for (cout = cstart; cout <= cend; cout++)
83d9ffcc 938 if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
36021974
TT
939 goto found;
940
c1a1e7fc
SL
941 return ENOENT;
942}
59037c53
LD
943
944errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start,
945 blk64_t end, blk64_t *out)
946{
947 blk64_t next;
948 blk64_t tot_set = 0;
949 errcode_t retval;
950
951 while (start < end) {
952 retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
953 start, end, &next);
954 if (retval) {
955 if (retval == ENOENT)
956 retval = 0;
957 break;
958 }
959 start = next;
960
961 retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
962 start, end, &next);
963 if (retval == 0) {
964 tot_set += next - start;
965 start = next + 1;
966 } else if (retval == ENOENT) {
967 retval = 0;
968 tot_set += end - start + 1;
969 break;
970 } else
971 break;
972 }
973
974 if (!retval)
975 *out = EXT2FS_NUM_B2C(fs, tot_set);
976 return retval;
977}