gen_bitmap64.c revision c1359d91958cadfbc0987921ee5b4db717852e90
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
81errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
82				    int type, __u64 start, __u64 end,
83				    __u64 real_end,
84				    const char *descr,
85				    ext2fs_generic_bitmap *ret)
86{
87	ext2fs_generic_bitmap	bitmap;
88	struct ext2_bitmap_ops	*ops;
89	errcode_t retval;
90
91	if (!type)
92		type = EXT2FS_BMAP64_BITARRAY;
93
94	switch (type) {
95	case EXT2FS_BMAP64_BITARRAY:
96		ops = &ext2fs_blkmap64_bitarray;
97		break;
98	case EXT2FS_BMAP64_RBTREE:
99		ops = &ext2fs_blkmap64_rbtree;
100		break;
101	default:
102		return EINVAL;
103	}
104
105	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
106				&bitmap);
107	if (retval)
108		return retval;
109
110	/* XXX factor out, repeated in copy_bmap */
111	bitmap->magic = magic;
112	bitmap->fs = fs;
113	bitmap->start = start;
114	bitmap->end = end;
115	bitmap->real_end = real_end;
116	bitmap->bitmap_ops = ops;
117	bitmap->cluster_bits = 0;
118	switch (magic) {
119	case EXT2_ET_MAGIC_INODE_BITMAP64:
120		bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
121		break;
122	case EXT2_ET_MAGIC_BLOCK_BITMAP64:
123		bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
124		bitmap->cluster_bits = fs->cluster_ratio_bits;
125		break;
126	default:
127		bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
128	}
129	if (descr) {
130		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
131		if (retval) {
132			ext2fs_free_mem(&bitmap);
133			return retval;
134		}
135		strcpy(bitmap->description, descr);
136	} else
137		bitmap->description = 0;
138
139	retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
140	if (retval) {
141		ext2fs_free_mem(&bitmap->description);
142		ext2fs_free_mem(&bitmap);
143		return retval;
144	}
145
146	*ret = bitmap;
147	return 0;
148}
149
150void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
151{
152	if (!bmap)
153		return;
154
155	if (EXT2FS_IS_32_BITMAP(bmap)) {
156		ext2fs_free_generic_bitmap(bmap);
157		return;
158	}
159
160	if (!EXT2FS_IS_64_BITMAP(bmap))
161		return;
162
163	bmap->bitmap_ops->free_bmap(bmap);
164
165	if (bmap->description) {
166		ext2fs_free_mem(&bmap->description);
167		bmap->description = 0;
168	}
169	bmap->magic = 0;
170	ext2fs_free_mem(&bmap);
171}
172
173errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
174				   ext2fs_generic_bitmap *dest)
175{
176	char *descr, *new_descr;
177	ext2fs_generic_bitmap	new_bmap;
178	errcode_t retval;
179
180	if (!src)
181		return EINVAL;
182
183	if (EXT2FS_IS_32_BITMAP(src))
184		return ext2fs_copy_generic_bitmap(src, dest);
185
186	if (!EXT2FS_IS_64_BITMAP(src))
187		return EINVAL;
188
189	/* Allocate a new bitmap struct */
190	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
191				&new_bmap);
192	if (retval)
193		return retval;
194
195	/* Copy all the high-level parts over */
196	new_bmap->magic = src->magic;
197	new_bmap->fs = src->fs;
198	new_bmap->start = src->start;
199	new_bmap->end = src->end;
200	new_bmap->real_end = src->real_end;
201	new_bmap->bitmap_ops = src->bitmap_ops;
202	new_bmap->base_error_code = src->base_error_code;
203	new_bmap->cluster_bits = src->cluster_bits;
204
205	descr = src->description;
206	if (descr) {
207		retval = ext2fs_get_mem(strlen(descr)+1, &new_descr);
208		if (retval) {
209			ext2fs_free_mem(&new_bmap);
210			return retval;
211		}
212		strcpy(new_descr, descr);
213		new_bmap->description = new_descr;
214	}
215
216	retval = src->bitmap_ops->copy_bmap(src, new_bmap);
217	if (retval) {
218		ext2fs_free_mem(&new_bmap->description);
219		ext2fs_free_mem(&new_bmap);
220		return retval;
221	}
222
223	*dest = new_bmap;
224
225	return 0;
226}
227
228errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
229				     __u64 new_end,
230				     __u64 new_real_end)
231{
232	if (!bmap)
233		return EINVAL;
234
235	if (EXT2FS_IS_32_BITMAP(bmap))
236		return ext2fs_resize_generic_bitmap(bmap->magic, new_end,
237						    new_real_end, bmap);
238
239	if (!EXT2FS_IS_64_BITMAP(bmap))
240		return EINVAL;
241
242	return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
243}
244
245errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap,
246					errcode_t neq,
247					__u64 end, __u64 *oend)
248{
249	if (!bitmap)
250		return EINVAL;
251
252	if (EXT2FS_IS_32_BITMAP(bitmap)) {
253		ext2_ino_t tmp_oend;
254		int retval;
255
256		retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic,
257							 neq, end, &tmp_oend);
258		if (oend)
259			*oend = tmp_oend;
260		return retval;
261	}
262
263	if (!EXT2FS_IS_64_BITMAP(bitmap))
264		return EINVAL;
265
266	if (end > bitmap->real_end)
267		return neq;
268	if (oend)
269		*oend = bitmap->end;
270	bitmap->end = end;
271	return 0;
272}
273
274__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap)
275{
276	if (!bitmap)
277		return EINVAL;
278
279	if (EXT2FS_IS_32_BITMAP(bitmap))
280		return ext2fs_get_generic_bitmap_start(bitmap);
281
282	if (!EXT2FS_IS_64_BITMAP(bitmap))
283		return EINVAL;
284
285	return bitmap->start;
286}
287
288__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap)
289{
290	if (!bitmap)
291		return EINVAL;
292
293	if (EXT2FS_IS_32_BITMAP(bitmap))
294		return ext2fs_get_generic_bitmap_end(bitmap);
295
296	if (!EXT2FS_IS_64_BITMAP(bitmap))
297		return EINVAL;
298
299	return bitmap->end;
300}
301
302void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap)
303{
304	if (EXT2FS_IS_32_BITMAP(bitmap))
305		ext2fs_clear_generic_bitmap(bitmap);
306	else
307		bitmap->bitmap_ops->clear_bmap (bitmap);
308}
309
310int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
311			     __u64 arg)
312{
313	if (!bitmap)
314		return 0;
315
316	if (EXT2FS_IS_32_BITMAP(bitmap)) {
317		if (arg & ~0xffffffffULL) {
318			ext2fs_warn_bitmap2(bitmap,
319					    EXT2FS_MARK_ERROR, 0xffffffff);
320			return 0;
321		}
322		return ext2fs_mark_generic_bitmap(bitmap, arg);
323	}
324
325	if (!EXT2FS_IS_64_BITMAP(bitmap))
326		return 0;
327
328	arg >>= bitmap->cluster_bits;
329
330	if ((arg < bitmap->start) || (arg > bitmap->end)) {
331		warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
332		return 0;
333	}
334
335	return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
336}
337
338int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap,
339			       __u64 arg)
340{
341	if (!bitmap)
342		return 0;
343
344	if (EXT2FS_IS_32_BITMAP(bitmap)) {
345		if (arg & ~0xffffffffULL) {
346			ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR,
347					    0xffffffff);
348			return 0;
349		}
350		return ext2fs_unmark_generic_bitmap(bitmap, arg);
351	}
352
353	if (!EXT2FS_IS_64_BITMAP(bitmap))
354		return 0;
355
356	arg >>= bitmap->cluster_bits;
357
358	if ((arg < bitmap->start) || (arg > bitmap->end)) {
359		warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
360		return 0;
361	}
362
363	return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
364}
365
366int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
367			     __u64 arg)
368{
369	if (!bitmap)
370		return 0;
371
372	if (EXT2FS_IS_32_BITMAP(bitmap)) {
373		if (arg & ~0xffffffffULL) {
374			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR,
375					    0xffffffff);
376			return 0;
377		}
378		return ext2fs_test_generic_bitmap(bitmap, arg);
379	}
380
381	if (!EXT2FS_IS_64_BITMAP(bitmap))
382		return 0;
383
384	arg >>= bitmap->cluster_bits;
385
386	if ((arg < bitmap->start) || (arg > bitmap->end)) {
387		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
388		return 0;
389	}
390
391	return bitmap->bitmap_ops->test_bmap(bitmap, arg);
392}
393
394errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
395					__u64 start, unsigned int num,
396					void *in)
397{
398	if (!bmap)
399		return EINVAL;
400
401	if (EXT2FS_IS_32_BITMAP(bmap)) {
402		if ((start+num-1) & ~0xffffffffULL) {
403			ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR,
404					    0xffffffff);
405			return EINVAL;
406		}
407		return ext2fs_set_generic_bitmap_range(bmap, bmap->magic,
408						       start, num, in);
409	}
410
411	if (!EXT2FS_IS_64_BITMAP(bmap))
412		return EINVAL;
413
414	return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
415}
416
417errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap,
418					__u64 start, unsigned int num,
419					void *out)
420{
421	if (!bmap)
422		return EINVAL;
423
424	if (EXT2FS_IS_32_BITMAP(bmap)) {
425		if ((start+num-1) & ~0xffffffffULL) {
426			ext2fs_warn_bitmap2(bmap,
427					    EXT2FS_UNMARK_ERROR, 0xffffffff);
428			return EINVAL;
429		}
430		return ext2fs_get_generic_bitmap_range(bmap, bmap->magic,
431						       start, num, out);
432	}
433
434	if (!EXT2FS_IS_64_BITMAP(bmap))
435		return EINVAL;
436
437	return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
438}
439
440errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
441				      ext2fs_generic_bitmap bm1,
442				      ext2fs_generic_bitmap bm2)
443{
444	blk64_t	i;
445
446	if (!bm1 || !bm2)
447		return EINVAL;
448	if (bm1->magic != bm2->magic)
449		return EINVAL;
450
451	/* Now we know both bitmaps have the same magic */
452	if (EXT2FS_IS_32_BITMAP(bm1))
453		return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2);
454
455	if (!EXT2FS_IS_64_BITMAP(bm1))
456		return EINVAL;
457
458	if ((bm1->start != bm2->start) ||
459	    (bm1->end != bm2->end))
460		return neq;
461
462	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
463		if (ext2fs_test_generic_bmap(bm1, i) !=
464		    ext2fs_test_generic_bmap(bm2, i))
465			return neq;
466
467	return 0;
468}
469
470void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
471{
472	__u64	start, num;
473
474	if (EXT2FS_IS_32_BITMAP(bmap)) {
475		ext2fs_set_generic_bitmap_padding(bmap);
476		return;
477	}
478
479	start = bmap->end + 1;
480	num = bmap->real_end - bmap->end;
481	bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
482	/* XXX ought to warn on error */
483}
484
485int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
486				    blk64_t block, unsigned int num)
487{
488	if (!bmap)
489		return EINVAL;
490
491	if (num == 1)
492		return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
493						 bmap, block);
494
495	if (EXT2FS_IS_32_BITMAP(bmap)) {
496		if ((block+num-1) & ~0xffffffffULL) {
497			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
498					    EXT2FS_UNMARK_ERROR, 0xffffffff);
499			return EINVAL;
500		}
501		return ext2fs_test_block_bitmap_range(
502			(ext2fs_generic_bitmap) bmap, block, num);
503	}
504
505	if (!EXT2FS_IS_64_BITMAP(bmap))
506		return EINVAL;
507
508	return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
509}
510
511void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
512				     blk64_t block, unsigned int num)
513{
514	if (!bmap)
515		return;
516
517	if (EXT2FS_IS_32_BITMAP(bmap)) {
518		if ((block+num-1) & ~0xffffffffULL) {
519			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
520					    EXT2FS_UNMARK_ERROR, 0xffffffff);
521			return;
522		}
523		ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
524					       block, num);
525	}
526
527	if (!EXT2FS_IS_64_BITMAP(bmap))
528		return;
529
530	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
531		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
532				   bmap->description);
533		return;
534	}
535
536	bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
537}
538
539void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
540				       blk64_t block, unsigned int num)
541{
542	if (!bmap)
543		return;
544
545	if (EXT2FS_IS_32_BITMAP(bmap)) {
546		if ((block+num-1) & ~0xffffffffULL) {
547			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
548					    EXT2FS_UNMARK_ERROR, 0xffffffff);
549			return;
550		}
551		ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
552						 block, num);
553	}
554
555	if (!EXT2FS_IS_64_BITMAP(bmap))
556		return;
557
558	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
559		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
560				   bmap->description);
561		return;
562	}
563
564	bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
565}
566
567void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func)
568{
569#ifndef OMIT_COM_ERR
570	if (bitmap && bitmap->description)
571		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
572			"called %s with 64-bit bitmap for %s", func,
573			bitmap->description);
574	else
575		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
576			"called %s with 64-bit bitmap", func);
577#endif
578}
579
580errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
581					   ext2fs_block_bitmap *bitmap)
582{
583	ext2fs_block_bitmap	cmap, bmap;
584	errcode_t		retval;
585	blk64_t			i, b_end, c_end;
586	int			n, ratio;
587
588	bmap = *bitmap;
589
590	if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap))
591		return 0;	/* Nothing to do */
592
593	retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
594					      &cmap);
595	if (retval)
596		return retval;
597
598	i = bmap->start;
599	b_end = bmap->end;
600	bmap->end = bmap->real_end;
601	c_end = cmap->end;
602	cmap->end = cmap->real_end;
603	n = 0;
604	ratio = 1 << fs->cluster_ratio_bits;
605	while (i < bmap->real_end) {
606		if (ext2fs_test_block_bitmap2(bmap, i)) {
607			ext2fs_mark_block_bitmap2(cmap, i);
608			i += ratio - n;
609			n = 0;
610			continue;
611		}
612		i++; n++;
613		if (n >= ratio)
614			n = 0;
615	}
616	bmap->end = b_end;
617	cmap->end = c_end;
618	ext2fs_free_block_bitmap(bmap);
619	*bitmap = cmap;
620	return 0;
621}
622