mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:38:11 +00:00
Kernel/Ext2: Write superblock backups
We don't ever read them out, but this should make fsck a lot less mad.
This commit is contained in:
parent
cc1cb72fb5
commit
a0705202ea
4 changed files with 54 additions and 2 deletions
|
@ -54,4 +54,18 @@ constexpr I pow(I base, I exponent)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<auto base, Unsigned U = decltype(base)>
|
||||||
|
constexpr bool is_power_of(U x)
|
||||||
|
{
|
||||||
|
if constexpr (base == 2)
|
||||||
|
return is_power_of_two(x);
|
||||||
|
|
||||||
|
// FIXME: I am naive! A log2-based approach (pow<U>(base, (log2(x) / log2(base))) == x) does not work due to rounding errors.
|
||||||
|
for (U exponent = 0; exponent <= log2(x) / log2(base) + 1; ++exponent) {
|
||||||
|
if (pow<U>(base, exponent) == x)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/IntegralMath.h>
|
||||||
#include <Kernel/Debug.h>
|
#include <Kernel/Debug.h>
|
||||||
#include <Kernel/FileSystem/Ext2FS/FileSystem.h>
|
#include <Kernel/FileSystem/Ext2FS/FileSystem.h>
|
||||||
#include <Kernel/FileSystem/Ext2FS/Inode.h>
|
#include <Kernel/FileSystem/Ext2FS/Inode.h>
|
||||||
|
@ -30,7 +31,23 @@ ErrorOr<void> Ext2FS::flush_super_block()
|
||||||
MutexLocker locker(m_lock);
|
MutexLocker locker(m_lock);
|
||||||
VERIFY((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
VERIFY((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
||||||
auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
|
auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
|
||||||
return raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer);
|
auto const superblock_physical_block_count = (sizeof(ext2_super_block) / logical_block_size());
|
||||||
|
|
||||||
|
// First superblock is always at offset 1024 (physical block index 2).
|
||||||
|
TRY(raw_write_blocks(2, superblock_physical_block_count, super_block_buffer));
|
||||||
|
|
||||||
|
auto is_sparse = has_flag(get_features_readonly(), FeaturesReadOnly::SparseSuperblock);
|
||||||
|
|
||||||
|
for (auto group = 1u; group < m_block_group_count; ++group) {
|
||||||
|
auto first_block_in_group = first_block_of_group(group);
|
||||||
|
// Superblock copies with sparse layout are in group number 2 and powers of 3, 5, and 7.
|
||||||
|
if (!is_sparse || group == 2 || AK::is_power_of<3>(group - 1) || AK::is_power_of<5>(group - 1) || AK::is_power_of<7>(group - 1)) {
|
||||||
|
dbgln_if(EXT2_DEBUG, "Writing superblock backup to block group {} (block {})", group, first_block_in_group);
|
||||||
|
TRY(write_blocks(first_block_in_group, 1, super_block_buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ext2_group_desc const& Ext2FS::group_descriptor(GroupIndex group_index) const
|
ext2_group_desc const& Ext2FS::group_descriptor(GroupIndex group_index) const
|
||||||
|
|
|
@ -22,10 +22,13 @@ class Ext2FS final : public BlockBasedFileSystem {
|
||||||
friend class Ext2FSInode;
|
friend class Ext2FSInode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// s_feature_ro_compat
|
||||||
enum class FeaturesReadOnly : u32 {
|
enum class FeaturesReadOnly : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
FileSize64bits = 1 << 1,
|
SparseSuperblock = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
|
||||||
|
FileSize64bits = EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
|
||||||
};
|
};
|
||||||
|
AK_ENUM_BITWISE_FRIEND_OPERATORS(FeaturesReadOnly);
|
||||||
|
|
||||||
static ErrorOr<NonnullRefPtr<FileSystem>> try_create(OpenFileDescription&, ReadonlyBytes);
|
static ErrorOr<NonnullRefPtr<FileSystem>> try_create(OpenFileDescription&, ReadonlyBytes);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <LibTest/TestCase.h>
|
#include <LibTest/TestCase.h>
|
||||||
|
|
||||||
#include <AK/IntegralMath.h>
|
#include <AK/IntegralMath.h>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
TEST_CASE(pow)
|
TEST_CASE(pow)
|
||||||
{
|
{
|
||||||
|
@ -18,3 +19,20 @@ TEST_CASE(pow)
|
||||||
EXPECT_EQ(AK::pow<u64>(10, 5), 100'000ull);
|
EXPECT_EQ(AK::pow<u64>(10, 5), 100'000ull);
|
||||||
EXPECT_EQ(AK::pow<u64>(10, 6), 1'000'000ull);
|
EXPECT_EQ(AK::pow<u64>(10, 6), 1'000'000ull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(is_power_of)
|
||||||
|
{
|
||||||
|
constexpr auto check_prime = []<u64 prime>(u64 limit) {
|
||||||
|
for (u64 power = 0; power < limit; ++power)
|
||||||
|
EXPECT(AK::is_power_of<prime>(AK::pow(prime, power)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Limits calculated as floor( log_{prime}(2^64) ) to prevent overflows.
|
||||||
|
check_prime.operator()<2>(64);
|
||||||
|
check_prime.operator()<3>(40);
|
||||||
|
check_prime.operator()<5>(27);
|
||||||
|
check_prime.operator()<7>(20);
|
||||||
|
check_prime.operator()<11>(18);
|
||||||
|
check_prime.operator()<97>(9);
|
||||||
|
check_prime.operator()<257>(7);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue