Skip AllocateTest block-count checks on btrfs (#14553)

Summary:
btrfs accepts fallocate without error but uses copy-on-write, so preallocated extents are not reflected in st_blocks. This caused AllocateTest to fail spuriously on btrfs filesystems. Detect btrfs via statfs and skip only the block-count assertions, keeping the rest of the test (write, flush, close, size checks) intact.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/14553

Test Plan: env_test AllocateTest passes on btrfs (skips with message) and would still enforce preallocation checks on ext4.

Reviewed By: joshkang97

Differential Revision: D99307962

Pulled By: pdillinger

fbshipit-source-id: 8f40c0109aa397e9ca7d9ee4496fa0614e971970
This commit is contained in:
Peter Dillinger
2026-04-06 11:14:19 -07:00
committed by meta-codesync[bot]
parent 8ec2177bd1
commit 0186937710
+34 -12
View File
@@ -27,11 +27,16 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <cstdlib>
#endif
#if !defined(BTRFS_SUPER_MAGIC)
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
#ifdef ROCKSDB_FALLOCATE_PRESENT
#include <cerrno>
#endif
@@ -1247,24 +1252,41 @@ TEST_P(EnvPosixTestWithParam, AllocateTest) {
struct stat f_stat;
ASSERT_EQ(stat(fname.c_str(), &f_stat), 0);
ASSERT_EQ((unsigned int)kDataSize, f_stat.st_size);
// verify that blocks are preallocated
// Note here that we don't check the exact number of blocks preallocated --
// we only require that number of allocated blocks is at least what we
// expect.
// It looks like some FS give us more blocks that we asked for. That's fine.
// It might be worth investigating further.
ASSERT_LE((unsigned int)(kPreallocateSize / kBlockSize), f_stat.st_blocks);
// btrfs accepts fallocate but uses copy-on-write, so preallocated extents
// are not reflected in st_blocks. Skip block-count verification there.
bool skip_block_checks = false;
#ifdef OS_LINUX
struct statfs fs_stat;
if (statfs(fname.c_str(), &fs_stat) == 0 &&
fs_stat.f_type ==
static_cast<decltype(fs_stat.f_type)>(BTRFS_SUPER_MAGIC)) {
fprintf(stderr, "Skipping preallocation block count checks on btrfs\n");
skip_block_checks = true;
}
#endif
if (!skip_block_checks) {
// verify that blocks are preallocated
// Note here that we don't check the exact number of blocks preallocated
// -- we only require that number of allocated blocks is at least what we
// expect.
// It looks like some FS give us more blocks that we asked for. That's
// fine. It might be worth investigating further.
ASSERT_LE((unsigned int)(kPreallocateSize / kBlockSize),
f_stat.st_blocks);
}
// close the file, should deallocate the blocks
wfile.reset();
stat(fname.c_str(), &f_stat);
ASSERT_EQ((unsigned int)kDataSize, f_stat.st_size);
// verify that preallocated blocks were deallocated on file close
// Because the FS might give us more blocks, we add a full page to the size
// and expect the number of blocks to be less or equal to that.
ASSERT_GE((f_stat.st_size + kPageSize + kBlockSize - 1) / kBlockSize,
(unsigned int)f_stat.st_blocks);
if (!skip_block_checks) {
// verify that preallocated blocks were deallocated on file close
// Because the FS might give us more blocks, we add a full page to the
// size and expect the number of blocks to be less or equal to that.
ASSERT_GE((f_stat.st_size + kPageSize + kBlockSize - 1) / kBlockSize,
(unsigned int)f_stat.st_blocks);
}
}
}
#endif // ROCKSDB_FALLOCATE_PRESENT