From 58a77fd3c964a1e89e1ce1bd1b4e94f501dcfff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 16 Oct 2008 10:00:34 +0000 Subject: [PATCH] * Fixed the incorrect ASSERT that possibly dropped you into KDL while deleting something (as reported by Marcus and Bruno on the mailing list). * AllocationGroup::Allocate() would always invalidate the largest block if it did not cover the largest part of the group; now it only invalidates it if it has been cut before. * Added small test app for the invalidation part. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28162 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../file_systems/bfs/BlockAllocator.cpp | 22 ++- .../add-ons/kernel/file_systems/bfs/Jamfile | 4 + .../bfs/bfs_allocator_invalidate_largest.cpp | 154 ++++++++++++++++++ 3 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 src/tests/add-ons/kernel/file_systems/bfs/bfs_allocator_invalidate_largest.cpp diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index af47dc39a6..7f83a7931a 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -366,8 +366,7 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks) status_t AllocationGroup::Allocate(Transaction& transaction, uint16 start, int32 length) { - if (start > fNumBits) - return B_ERROR; + ASSERT(start + length <= fNumBits); // Update the allocation group info // TODO: this info will be incorrect if something goes wrong later @@ -377,16 +376,22 @@ AllocationGroup::Allocate(Transaction& transaction, uint16 start, int32 length) fFreeBits -= length; if (fLargestValid) { + bool cut = false; if (fLargestStart == start) { + // cut from start fLargestStart += length; fLargestLength -= length; + cut = true; } else if (start > fLargestStart && start < fLargestStart + fLargestLength) { + // cut from end fLargestLength = start - fLargestStart; + cut = true; } - if (fLargestLength < fLargestStart - || fLargestLength - < (int32)fNumBits - (fLargestStart + fLargestLength)) { + if (cut && (fLargestLength < fLargestStart + || fLargestLength + < (int32)fNumBits - (fLargestStart + fLargestLength))) { + // might not be the largest block anymore fLargestValid = false; } } @@ -430,8 +435,7 @@ AllocationGroup::Allocate(Transaction& transaction, uint16 start, int32 length) status_t AllocationGroup::Free(Transaction& transaction, uint16 start, int32 length) { - if (start > fNumBits) - return B_ERROR; + ASSERT(start + length <= fNumBits); // Update the allocation group info // TODO: this info will be incorrect if something goes wrong later @@ -440,8 +444,8 @@ AllocationGroup::Free(Transaction& transaction, uint16 start, int32 length) fFreeBits += length; // The range to be freed cannot be part of the valid largest range - ASSERT(!fLargestValid || start < fLargestStart - || start > fLargestStart + fLargestLength); + ASSERT(!fLargestValid || start + length <= fLargestStart + || start > fLargestStart); if (fLargestValid && (start + length == fLargestStart diff --git a/src/tests/add-ons/kernel/file_systems/bfs/Jamfile b/src/tests/add-ons/kernel/file_systems/bfs/Jamfile index 537bb4bce6..8c00e1d6b9 100644 --- a/src/tests/add-ons/kernel/file_systems/bfs/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/bfs/Jamfile @@ -1,5 +1,9 @@ SubDir HAIKU_TOP src tests add-ons kernel file_systems bfs ; +SimpleTest bfs_allocator_invalidate_largest : + bfs_allocator_invalidate_largest.cpp +; + SimpleTest bfs_attribute_iterator_test : bfs_attribute_iterator_test.cpp : be ; diff --git a/src/tests/add-ons/kernel/file_systems/bfs/bfs_allocator_invalidate_largest.cpp b/src/tests/add-ons/kernel/file_systems/bfs/bfs_allocator_invalidate_largest.cpp new file mode 100644 index 0000000000..bb5d9bd8f7 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/bfs/bfs_allocator_invalidate_largest.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. + * This file may be used under the terms of the MIT License. + */ + + +#include +#include +#include + + +int32_t fLargestStart = -1; +int32_t fLargestLength = -1; +bool fLargestValid = false; +int32_t fNumBits = 100; + + +void +allocate(uint16_t start, int32_t length) +{ + if (start + length > fNumBits) + return; + + if (fLargestValid) { + bool cut = false; + if (fLargestStart == start) { + // cut from start + fLargestStart += length; + fLargestLength -= length; + cut = true; + } else if (start > fLargestStart + && start < fLargestStart + fLargestLength) { + // cut from end + fLargestLength = start - fLargestStart; + cut = true; + } + if (cut && (fLargestLength < fLargestStart + || fLargestLength + < (int32_t)fNumBits - (fLargestStart + fLargestLength))) { + // might not be the largest block anymore + fLargestValid = false; + } + } +} + + +void +free(uint16_t start, int32_t length) +{ + if (start + length > fNumBits) + return; + + // The range to be freed cannot be part of the valid largest range + if (!(!fLargestValid || start + length <= fLargestStart + || start > fLargestStart)) + printf("ASSERT failed!\n"); + + if (fLargestValid + && (start + length == fLargestStart + || fLargestStart + fLargestLength == start + || (start < fLargestStart && fLargestStart > fLargestLength) + || (start > fLargestStart + && (int32_t)fNumBits - (fLargestStart + fLargestLength) + > fLargestLength))) { + fLargestValid = false; + } +} + + +void +test(int32_t num, int32_t nextLargestStart, int32_t nextLargestLength, + bool nextLargestValid) +{ + const char* error = NULL; + if (nextLargestValid != fLargestValid) + error = "valid differs"; + else if (!nextLargestValid) + return; + + if (nextLargestStart != fLargestStart) + error = "start differ"; + else if (nextLargestLength != fLargestLength) + error = "length differs"; + + if (error == NULL) + return; + + printf("%d: %s: is %d.%d%s, should be %d.%d%s\n", num, error, fLargestStart, + fLargestLength, fLargestValid ? "" : " (INVALID)", nextLargestStart, + nextLargestLength, nextLargestValid ? "" : " (INVALID)"); + exit(1); +} + + +void +test_allocate(int32_t num, int32_t largestStart, int32_t largestLength, + int32_t start, int32_t length, int32_t nextLargestStart, + int32_t nextLargestLength, bool nextLargestValid) +{ + fLargestStart = largestStart; + fLargestLength = largestLength; + fLargestValid = true; + + printf("Test %d: %d.%d - allocate %d.%d\n", num, fLargestStart, + fLargestLength, start, length); + + allocate(start, length); + test(num, nextLargestStart, nextLargestLength, nextLargestValid); +} + + +void +test_free(int32_t num, int32_t largestStart, int32_t largestLength, int32_t start, + int32_t length, int32_t nextLargestStart, int32_t nextLargestLength, + bool nextLargestValid) +{ + fLargestStart = largestStart; + fLargestLength = largestLength; + fLargestValid = true; + + printf("Test %d: %d.%d - free %d.%d\n", num, fLargestStart, fLargestLength, + start, length); + + free(start, length); + test(num, nextLargestStart, nextLargestLength, nextLargestValid); +} + + +int +main(int argc, char** argv) +{ + puts("------------- Allocate Tests -------------\n"); + test_allocate(1, 40, 50, 20, 20, 40, 50, true); // touch start + test_allocate(2, 40, 50, 20, 19, 40, 50, true); // don't touch start + test_allocate(3, 40, 10, 40, 1, 41, 9, false); // cut start + test_allocate(4, 40, 50, 40, 1, 41, 49, true); // cut start + test_allocate(5, 40, 50, 90, 1, 40, 50, true); // touch end + test_allocate(6, 40, 50, 89, 1, 40, 49, true); // cut end + test_allocate(7, 40, 20, 59, 1, 40, 19, false); // cut end + test_allocate(8, 0, 51, 0, 1, 1, 50, true); // cut start + test_allocate(9, 0, 51, 0, 2, 2, 49, true); // cut start + test_allocate(10, 0, 51, 0, 3, 3, 48, false); // cut start + + puts("------------- Free Tests -------------\n"); + test_free(1, 40, 50, 20, 20, 40, 50, false); // touch start + test_free(2, 40, 50, 20, 19, 40, 50, true); // before start + test_free(3, 50, 40, 20, 19, 40, 50, false); // before start + test_free(4, 40, 40, 80, 20, 40, 80, false); // touch end + test_free(5, 40, 40, 81, 20, 40, 40, true); // after end + test_free(6, 40, 20, 60, 20, 40, 80, false); // touch end + test_free(7, 40, 20, 61, 20, 40, 80, false); // after end + test_free(8, 40, 20, 41, 20, 40, 80, false); // after end + return 0; +}