xref: /haiku/src/add-ons/kernel/file_systems/ext2/BitmapBlock.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2  * Copyright 2001-2010, Haiku Inc. All rights reserved.
3  * This file may be used under the terms of the MIT License.
4  *
5  * Authors:
6  *		Janito V. Ferreira Filho
7  *		Jérôme Duval
8  */
9 
10 
11 #include "BitmapBlock.h"
12 
13 #include "CRCTable.h"
14 
15 
16 //#define TRACE_EXT2
17 #ifdef TRACE_EXT2
18 #	define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
19 #else
20 #	define TRACE(x...) ;
21 #endif
22 #define ERROR(x...) dprintf("\33[34mext2:\33[0m " x)
23 
24 
25 BitmapBlock::BitmapBlock(Volume* volume, uint32 numBits)
26 	:
27 	CachedBlock(volume),
28 	fVolume(volume),
29 	fData(NULL),
30 	fReadOnlyData(NULL),
31 	fNumBits(numBits),
32 	fMaxIndex(fNumBits >> 5)
33 {
34 	TRACE("BitmapBlock::BitmapBlock(): num bits: %" B_PRIu32 "\n", fNumBits);
35 }
36 
37 
38 BitmapBlock::~BitmapBlock()
39 {
40 }
41 
42 
43 bool
44 BitmapBlock::SetTo(off_t block)
45 {
46 	fData = NULL;
47 	fReadOnlyData = (uint32*)CachedBlock::SetTo(block);
48 
49 	return fReadOnlyData != NULL;
50 }
51 
52 
53 bool
54 BitmapBlock::SetToWritable(Transaction& transaction, off_t block, bool empty)
55 {
56 	fReadOnlyData = NULL;
57 	fData = (uint32*)CachedBlock::SetToWritable(transaction, block, empty);
58 
59 	return fData != NULL;
60 }
61 
62 
63 bool
64 BitmapBlock::_Check(uint32 start, uint32 length, bool marked)
65 {
66 	const uint32* data = fData == NULL ? fReadOnlyData : fData;
67 	if (data == NULL)
68 		return false;
69 
70 	if (start + length > fNumBits)
71 		return false;
72 	if (length == 0)
73 		return true;
74 
75 	uint32 startIndex = start >> 5;
76 	uint32 startBit = start & 0x1F;
77 	uint32 remainingBits = (length + startBit) & 0x1F;
78 
79 	uint32 iterations;
80 
81 	if (length < 32) {
82 		if (startBit + length < 32) {
83 			uint32 bits = B_LENDIAN_TO_HOST_INT32(data[startIndex]);
84 
85 			uint32 mask = (1 << (startBit + length)) - 1;
86 			mask &= ~((1 << startBit) - 1);
87 
88 			return (bits & mask) == (marked ? mask : 0);
89 		} else
90 			iterations = 0;
91 	} else
92 		iterations = (length - 32 + startBit) >> 5;
93 
94 	uint32 index = startIndex;
95 
96 	if (startBit != 0) {
97 		uint32 mask = ~((1 << startBit) - 1);
98 		uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
99 
100 		if ((bits & mask) != (marked ? mask : 0)) {
101 			TRACE("BitmapBlock::_Check(): start %" B_PRIx32 " mask %" B_PRIx32
102 				"\n", bits, mask);
103 			return false;
104 		}
105 
106 		index += 1;
107 	} else
108 		iterations++;
109 
110 	for (; iterations > 0; --iterations) {
111 		if (data[index++] != (marked ? 0xFFFFFFFF : 0)) {
112 			TRACE("BitmapBlock::_Check(): iterations %" B_PRIu32 " bits: %"
113 				B_PRIx32 "\n", iterations, data[index - 1]);
114 			return false;
115 		}
116 	}
117 
118 	if (remainingBits != 0) {
119 		uint32 mask = (1 << remainingBits) - 1;
120 
121 		uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
122 		if ((bits & mask) != (marked ? mask : 0)) {
123 			TRACE("BitmapBlock::_Check(): remainingBits %" B_PRIu32
124 				" remaining %" B_PRIx32 " mask %" B_PRIx32 "\n", remainingBits,
125 				bits, mask);
126 			return false;
127 		}
128 	}
129 
130 	return true;
131 }
132 
133 
134 bool
135 BitmapBlock::_Update(uint32 start, uint32 length, bool mark, bool force)
136 {
137 	TRACE("BitmapBlock::_Update(%" B_PRIu32 ", %" B_PRIu32 ", %c, %c)\n",
138 		start, length, mark ? 't' : 'f', force ? 't' : 'f');
139 
140 	if (fData == NULL || start + length > fNumBits)
141 		return false;
142 
143 	uint32 startIndex = start >> 5;
144 	uint32 startBit = start & 0x1F;
145 	uint32 remainingBits = (length + startBit) & 0x1F;
146 
147 	TRACE("BitmapBlock::_Update(): start index: %" B_PRIu32 ", start bit: %"
148 		B_PRIu32 ", remaining bits: %" B_PRIu32 ")\n", startIndex, startBit,
149 		remainingBits);
150 	uint32 iterations;
151 
152 	if (length < 32) {
153 		if (startBit + length < 32) {
154 			uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[startIndex]);
155 			TRACE("BitmapBlock::_Update(): bits: %" B_PRIx32 "\n", bits);
156 
157 			uint32 mask = (1 << (startBit + length)) - 1;
158 			mask &= ~((1 << startBit) - 1);
159 
160 			TRACE("BitmapBlock::_Update(): mask: %" B_PRIx32 "\n", mask);
161 
162 			if ((bits & mask) != (mark ? 0 : mask)) {
163 				ERROR("BitmapBlock::_Update() Marking failed bits %" B_PRIx32
164 					" startBit %" B_PRIu32 "\n", bits, startBit);
165 				return false;
166 			}
167 
168 			if (mark)
169 			    bits |= mask;
170 			else
171 			    bits &= ~mask;
172 
173 			TRACE("BitmapBlock::_Update(): updated bits: %" B_PRIx32 "\n",
174 				bits);
175 			fData[startIndex] = B_HOST_TO_LENDIAN_INT32(bits);
176 
177 			return true;
178 		} else
179 			iterations = 0;
180 	} else
181 		iterations = (length - 32 + startBit) >> 5;
182 
183 	TRACE("BitmapBlock::_Update(): iterations: %" B_PRIu32 "\n", iterations);
184 	uint32 index = startIndex;
185 
186 	if (startBit != 0) {
187 		uint32 mask = ~((1 << startBit) - 1);
188 		uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
189 
190 		TRACE("BitmapBlock::_Update(): mask: %" B_PRIx32 ", bits: %" B_PRIx32
191 			"\n", mask, bits);
192 
193 		if (!force && (bits & mask) != (mark ? 0 : mask))
194 			return false;
195 
196 		if (mark)
197 			bits |= mask;
198 		else
199 			bits &= ~mask;
200 		fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
201 
202 		TRACE("BitmapBlock::_Update(): updated bits: %" B_PRIx32 "\n", bits);
203 		index += 1;
204 	} else
205 		iterations++;
206 
207 	for (; iterations > 0; --iterations) {
208 		if (!force && fData[index] != (mark ? 0 : 0xFFFFFFFF)) {
209 			ERROR("BitmapBlock::_Update() Marking failed "
210 				"index %" B_PRIu32 ", iterations %" B_PRId32 "\n", index,
211 				iterations);
212 			return false;
213 		}
214 		fData[index++] = (mark ? 0xFFFFFFFF : 0);
215 	}
216 
217 	TRACE("BitmapBlock::_Update(): Finished iterations\n");
218 
219 	if (remainingBits != 0) {
220 		uint32 mask = (1 << remainingBits) - 1;
221 		uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
222 
223 		TRACE("BitmapBlock::_Update(): mask: %" B_PRIx32 ", bits: %" B_PRIx32
224 			"\n", mask, bits);
225 
226 		if (!force && (bits & mask) != (mark ? 0 : mask)) {
227 			ERROR("BitmapBlock::_Update() Marking failed remaining\n");
228 			return false;
229 		}
230 
231 		if (mark)
232 			bits |= mask;
233 		else
234 			bits &= ~mask;
235 		fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
236 
237 		TRACE("BitmapBlock::_Update(): updated bits: %" B_PRIx32 "\n", bits);
238 	}
239 
240 	return true;
241 }
242 
243 
244 void
245 BitmapBlock::_FindNext(uint32& pos, bool marked)
246 {
247 	TRACE("BitmapBlock::_FindNext(): pos: %" B_PRIu32 "\n", pos);
248 
249 	const uint32* data = fData == NULL ? fReadOnlyData : fData;
250 	if (data == NULL)
251 		return;
252 
253 	if (pos >= fNumBits) {
254 		pos = fNumBits;
255 		return;
256 	}
257 
258 	uint32 index = pos >> 5;
259 	uint32 bit = pos & 0x1F;
260 	uint32 maxBit = 32;
261 
262 	uint32 mask = ~((1 << bit) - 1);
263 	uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
264 
265 	TRACE("BitmapBlock::_FindNext(): index: %" B_PRIu32 ", bit: %" B_PRIu32
266 		", mask: %" B_PRIx32 ", bits: %" B_PRIx32 "\n", index, bit, mask,
267 		bits);
268 
269 	bits &= mask;
270 	if (bits == (marked ? 0 : mask) && index < fMaxIndex) {
271 		// Find a 32 bits block that has a marked bit
272 		do {
273 			index++;
274 		} while (index < fMaxIndex && data[index] == (marked ? 0 : 0xFFFFFFFF));
275 		bit = 0;
276 		mask = 0xffffffff;
277 	}
278 
279 	if (index >= fMaxIndex) {
280 		maxBit = fNumBits & 0x1F;
281 
282 		if (maxBit == 0) {
283 			// Not found
284 			TRACE("BitmapBlock::_FindNext(): reached end of block, "
285 				"num bits: %" B_PRIu32 "\n", fNumBits);
286 			pos = fNumBits;
287 			return;
288 		}
289 		bits = B_LENDIAN_TO_HOST_INT32(data[fMaxIndex]);
290 		mask &= (1 << maxBit) - 1;
291 		if ((bits & mask) == (marked ? 0 : mask)) {
292 			TRACE("BitmapBlock::_FindNext(): reached end of block, "
293 				"num bits: %" B_PRIu32 "\n", fNumBits);
294 			pos = fNumBits;
295 			return;
296 		}
297 		maxBit++;
298 	} else
299 		bits = B_LENDIAN_TO_HOST_INT32(data[index]);
300 
301 	for (; bit < maxBit; ++bit) {
302 		// Find the marked bit
303 		if ((bits >> bit & 1) != (marked ? 0U : 1U)) {
304 			pos = index << 5 | bit;
305 			TRACE("BitmapBlock::_FindNext(): found bit: %" B_PRIu32 "\n", pos);
306 			return;
307 		}
308 	}
309 
310 	panic("Couldn't find bit inside an uint32 (%" B_PRIx32 ")\n", bits);
311 }
312 
313 
314 void
315 BitmapBlock::FindPreviousMarked(uint32& pos)
316 {
317 	TRACE("BitmapBlock::FindPreviousMarked(%" B_PRIu32 ")\n", pos);
318 	const uint32* data = fData == NULL ? fReadOnlyData : fData;
319 	if (data == NULL)
320 		return;
321 
322 	if (pos >= fNumBits)
323 		pos = fNumBits;
324 
325 	if (pos == 0)
326 		return;
327 
328 	uint32 index = pos >> 5;
329 	int32 bit = pos & 0x1F;
330 
331 	uint32 mask = (1 << bit) - 1;
332 	uint32 bits = B_LENDIAN_TO_HOST_INT32(data[index]);
333 	bits = bits & mask;
334 
335 	TRACE("BitmapBlock::FindPreviousMarked(): index: %" B_PRIu32 " bit: %"
336 		B_PRIu32 " bits: %" B_PRIx32 "\n", index, bit, bits);
337 
338 	if (bits == 0) {
339 		// Find an block of 32 bits that has a marked bit
340 		do {
341 			index--;
342 		} while (data[index] == 0 && index > 0);
343 
344 		bits = B_LENDIAN_TO_HOST_INT32(data[index]);
345 		if (bits == 0) {
346 			// Not found
347 			pos = 0;
348 			return;
349 		}
350 
351 		bit = 31;
352 	}
353 
354 	TRACE("BitmapBlock::FindPreviousMarked(): index: %" B_PRIu32 " bit: %"
355 		B_PRIu32 " bits: %" B_PRIx32 "\n", index, bit, bits);
356 
357 	for (; bit >= 0; --bit) {
358 		// Find the marked bit
359 		if ((bits >> bit & 1) != 0) {
360 			pos = index << 5 | bit;
361 			return;
362 		}
363 	}
364 
365 	panic("Couldn't find marked bit inside an int32 with value different than "
366 		"zero!?\n");
367 }
368 
369 
370 void
371 BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
372 {
373 	const uint32* data = fData == NULL ? fReadOnlyData : fData;
374 	if (data == NULL)
375 		return;
376 
377 	uint32 wordSpan = length >> 5;
378 	uint32 startIndex = 0;
379 	uint32 index = 0;
380 	uint32 bits = B_LENDIAN_TO_HOST_INT32(data[0]);
381 
382 	TRACE("BitmapBlock::FindLargestUnmarkedRange(): word span: %" B_PRIu32
383 		", last index: %" B_PRIu32 ", start index: %" B_PRIu32 ", index: %"
384 		B_PRIu32 ", bits: %" B_PRIx32 ", start: %" B_PRIu32 ", length: %"
385 		B_PRIu32 "\n", wordSpan, fMaxIndex, startIndex, index, bits, start,
386 		length);
387 
388 	if (wordSpan == 0) {
389 		uint32 startPos = 0;
390 		uint32 endPos = 0;
391 
392 		while (endPos < fNumBits) {
393 			FindNextUnmarked(startPos);
394 			endPos = startPos;
395 
396 			if (startPos != fNumBits) {
397 				FindNextMarked(endPos);
398 
399 				uint32 newLength = endPos - startPos;
400 
401 				if (newLength > length) {
402 					start = startPos;
403 					length = newLength;
404 					TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
405 						"larger length %" B_PRIu32 " starting at %" B_PRIu32
406 						"\n", length, start);
407 				}
408 
409 				startPos = endPos;
410 
411 				if (newLength >= 32)
412 					break;
413 			}
414 		}
415 
416 		if (endPos >= fNumBits)
417 			return;
418 
419 		wordSpan = length >> 5;
420 		startIndex = startPos >> 5;
421 		index = (endPos >> 5) + 1;
422 		bits = B_LENDIAN_TO_HOST_INT32(data[index]);
423 	}
424 
425 	for (; index < fMaxIndex; ++index) {
426 		bits = B_LENDIAN_TO_HOST_INT32(data[index]);
427 
428 		if (bits != 0) {
429 			// Contains marked bits
430 			if (index - startIndex >= wordSpan) {
431 				uint32 newLength = (index - startIndex - 1) << 5;
432 				uint32 newStart = (startIndex + 1) << 5;
433 
434 				uint32 startBits =
435 					B_LENDIAN_TO_HOST_INT32(data[startIndex]);
436 
437 				for (int32 bit = 31; bit >= 0; --bit) {
438 					if ((startBits >> bit & 1) != 0)
439 						break;
440 
441 					++newLength;
442 					--newStart;
443 				}
444 
445 				for (int32 bit = 0; bit < 32; ++bit) {
446 					if ((bits >> bit & 1) != 0)
447 						break;
448 
449 					++newLength;
450 				}
451 
452 				if (newLength > length) {
453 					start = newStart;
454 					length = newLength;
455 					wordSpan = length >> 5;
456 
457 					TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
458 						"larger length %" B_PRIu32 " starting at %" B_PRIu32
459 						"; word span: %" B_PRIu32 "\n", length, start,
460 						wordSpan);
461 				}
462 			}
463 
464 			startIndex = index;
465 		}
466 	}
467 
468 	--index;
469 
470 	if (index - startIndex >= wordSpan) {
471 		uint32 newLength = (index - startIndex) << 5;
472 		uint32 newStart = (startIndex + 1) << 5;
473 
474 		TRACE("BitmapBlock::FindLargestUnmarkedRange(): Possibly found a "
475 			"larger range. index: %" B_PRIu32 ", start index: %" B_PRIu32
476 			", word span: %" B_PRIu32 ", new length: %" B_PRIu32
477 			", new start: %" B_PRIu32 "\n", index, startIndex, wordSpan,
478 			newLength, newStart);
479 
480 		if (newStart != 0) {
481 			uint32 startBits = B_LENDIAN_TO_HOST_INT32(data[startIndex]);
482 
483 			TRACE("BitmapBlock::FindLargestUnmarkedRange(): start bits: %"
484 				B_PRIu32 "\n", startBits);
485 
486 			for (int32 bit = 31; bit >= 0; --bit) {
487 				if ((startBits >> bit & 1) != 0)
488 					break;
489 
490 				++newLength;
491 				--newStart;
492 			}
493 
494 			TRACE("BitmapBlock::FindLargestUnmarkedRange(): updated new start "
495 				"to %" B_PRIu32 " and new length to %" B_PRIu32 "\n", newStart,
496 				newLength);
497 		}
498 
499 		for (int32 bit = 0; bit < 32; ++bit) {
500 			if ((bits >> bit & 1) == 0)
501 				break;
502 
503 			++newLength;
504 		}
505 
506 		TRACE("BitmapBlock::FindLargestUnmarkedRange(): updated new length to "
507 			"%" B_PRIu32 "\n", newLength);
508 
509 		if (newLength > length) {
510 			start = newStart;
511 			length = newLength;
512 			TRACE("BitmapBlock::FindLargestUnmarkedRange(): Found "
513 				"largest length %" B_PRIu32 " starting at %" B_PRIu32 "\n",
514 				length, start);
515 		}
516 	}
517 }
518 
519 
520 uint32
521 BitmapBlock::Checksum(uint32 unitsPerGroup) const
522 {
523 	const uint32* data = fData == NULL ? fReadOnlyData : fData;
524 	if (data == NULL)
525 		panic("BitmapBlock::Checksum() data is NULL\n");
526 	return calculate_crc32c(fVolume->ChecksumSeed(),
527 		(uint8*)data, unitsPerGroup / 8);
528 }
529