Skip to content

Commit d7f0b6a

Browse files
committed
test/store_test: Expose race in BlueFS truncate / remove
Created test that exposes race between BlueFS::truncate and BlueFS::unlink. Test requires injection of 1ms sleep to BlueFS::truncate. Therefore, in this form, it is unsuitable for merge. Signed-off-by: Adam Kupczyk <[email protected]>
1 parent 72f4cc5 commit d7f0b6a

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

src/os/bluestore/BlueFS.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3861,7 +3861,7 @@ int BlueFS::truncate(FileWriter *h, uint64_t offset)/*_WF_L*/
38613861
if (offset > fnode.size) {
38623862
ceph_abort_msg("truncate up not supported");
38633863
}
3864-
3864+
unittest_inject_delay();
38653865
_flush_bdev(h);
38663866
{
38673867
std::lock_guard ll(log.lock);

src/os/bluestore/BlueFS.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ class debug_point_t {
237237
: m_func(func) {}
238238
template<typename... Arg>
239239
void operator()(Arg... arg) { if (m_func) m_func(std::forward<Arg...>(arg...)); }
240+
void operator()() { if (m_func) m_func(); }
240241
void operator=(T&& func) { m_func = std::move(func);}
241242
void operator=(T& func) { m_func = func;}
242243
private:
@@ -813,6 +814,7 @@ class BlueFS {
813814
bool debug_get_is_dev_dirty(FileWriter *h, uint8_t dev);
814815
debug_point_t<std::function<void(uint32_t)>> tracepoint_async_compact;
815816
void trim_free_space(const std::string& type, std::ostream& outss);
817+
debug_point_t<std::function<void()>> unittest_inject_delay;
816818

817819
private:
818820
// Wrappers for BlockDevice::read(...) and BlockDevice::read_random(...)

src/test/objectstore/store_test.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11996,6 +11996,53 @@ TEST_P(StoreTestSpecificAUSize, BlueFSReservedTest) {
1199611996
g_conf()->bluefs_alloc_size + wal_extra);
1199711997
}
1199811998

11999+
12000+
TEST_P(StoreTest, BlueFS_truncate_remove_race) {
12001+
if (string(GetParam()) != "bluestore")
12002+
GTEST_SKIP();
12003+
12004+
BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
12005+
ceph_assert(bstore);
12006+
BlueFS& fs = *bstore->get_bluefs();
12007+
fs.unittest_inject_delay = []() { usleep(1000); };
12008+
static constexpr uint32_t batch_size = 20;
12009+
std::binary_semaphore go_remove(0);
12010+
std::binary_semaphore done_remove(0);
12011+
12012+
auto files_remover = [&]() {
12013+
for (uint32_t cnt = 0; cnt < batch_size; cnt++) {
12014+
go_remove.acquire();
12015+
std::string name = "test-file-" + std::to_string(cnt);
12016+
fs.unlink("dir", name);
12017+
fs.sync_metadata(false);
12018+
done_remove.release();
12019+
}
12020+
};
12021+
12022+
ASSERT_EQ(0, fs.mkdir("dir"));
12023+
std::thread remover_thread(files_remover);
12024+
12025+
for (uint32_t cnt = 0; cnt < batch_size; cnt++) {
12026+
std::string name = "test-file-" + std::to_string(cnt);
12027+
BlueFS::FileWriter *f = nullptr;
12028+
ASSERT_EQ(0, fs.open_for_write("dir", name, &f, false));
12029+
fs.preallocate(f->file, 0, 100000);
12030+
for (uint32_t i = 0; i < 10; i++) {
12031+
fs.append_try_flush(f, "x", 1);
12032+
fs.fsync(f);
12033+
}
12034+
go_remove.release();
12035+
fs.truncate(f, 10);
12036+
fs.close_writer(f);
12037+
done_remove.acquire();
12038+
}
12039+
12040+
remover_thread.join();
12041+
fs.unittest_inject_delay = nullptr;
12042+
EXPECT_EQ(store->umount(), 0);
12043+
EXPECT_EQ(store->mount(), 0);
12044+
}
12045+
1199912046
#endif // WITH_BLUESTORE
1200012047

1200112048
int main(int argc, char **argv) {

0 commit comments

Comments
 (0)