From: Adam Kupczyk Date: Fri, 6 Mar 2026 15:42:47 +0000 (+0000) Subject: store_test: Test for fsck fixing stray onode shards X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c7ea65c3ba752d0ec81bb2517d8e9fdf0eb86bef;p=ceph.git store_test: Test for fsck fixing stray onode shards Fsck cannot fix: 1) missing head for sharded objects 2) missing non-head shard from object 3) extra shard Adds tests for 1) and 3). Option 2) will not be currently tested - fsck fails on it with missing shard assert. Signed-off-by: Adam Kupczyk --- diff --git a/src/test/objectstore/store_test.cc b/src/test/objectstore/store_test.cc index 176eecbad3ed..1ab4191dda15 100644 --- a/src/test/objectstore/store_test.cc +++ b/src/test/objectstore/store_test.cc @@ -11495,6 +11495,108 @@ TEST_P(CorruptedOnodesTest, Recover_TolerateMissingHeadShard) cleanup_store(); } +TEST_P(CorruptedOnodesTest, Fsck_FixMissingHeadShard) +{ + SetVal(g_conf(), "bluestore_debug_inject_allocation_from_file_failure", "0"); + prepare_store(); + + mount(); + BlueStore* bs = dynamic_cast(store.get()); + ceph_assert(bs); + KeyValueDB* pdb = bs->get_kv(); + KeyValueDB::Iterator it = pdb->get_iterator("O"); + it->seek_to_first(); + while (it->valid()) { + if (it->key().contains("my_special_object") && + it->key().ends_with("o")) { + //delete main key for the object + auto trans = pdb->get_transaction(); + trans->rm_single_key("O", it->key()); + pdb->submit_transaction_sync(trans); + break; + } + it->next(); + } + it.reset(); + umount(); + + ASSERT_GT(store->fsck(false), 8); // I observe 11, so 8 seems safe + ASSERT_EQ(store->repair(false), 0); + ASSERT_EQ(store->fsck(false), 0); + + cleanup_store(); +} + +TEST_P(CorruptedOnodesTest, Fsck_FixExtraShard) +{ + SetVal(g_conf(), "bluestore_debug_inject_allocation_from_file_failure", "0"); + prepare_store(); + mount(); + BlueStore* bs = dynamic_cast(store.get()); + ceph_assert(bs); + KeyValueDB* pdb = bs->get_kv(); + KeyValueDB::Iterator it = pdb->get_iterator("O"); + it->seek_to_first(); + while (it->valid()) { + if (it->key().contains("my_special_object") && + it->key().ends_with("x")) { + //duplicate shard into offset +1 + auto trans = pdb->get_transaction(); + std::string new_key = it->key(); + new_key[new_key.size() - 2] = '\001'; + trans->set("O", new_key, it->value()); + pdb->submit_transaction_sync(trans); + break; + } + it->next(); + } + it.reset(); + umount(); + + ASSERT_EQ(store->fsck(false), 1); + ASSERT_EQ(store->repair(false), 0); + ASSERT_EQ(store->fsck(false), 0); + + cleanup_store(); +} + +TEST_P(CorruptedOnodesTest, Fsck_Fix3ExtraShards) { + SetVal(g_conf(), "bluestore_debug_inject_allocation_from_file_failure", "0"); + prepare_store(); + + mount(); + BlueStore* bs = dynamic_cast(store.get()); + ceph_assert(bs); + KeyValueDB* pdb = bs->get_kv(); + KeyValueDB::Iterator it = pdb->get_iterator("O"); + it->seek_to_first(); + while (it->valid()) { + if (it->key().contains("my_special_object") && + it->key().ends_with("x")) { + //duplicate shard into offset +1 + auto trans = pdb->get_transaction(); + std::string new_key = it->key(); + new_key[new_key.size() - 2] = '\001'; + trans->set("O", new_key, it->value()); + new_key[new_key.size() - 2] = '\002'; + trans->set("O", new_key, it->value()); + new_key[new_key.size() - 2] = '\003'; + trans->set("O", new_key, it->value()); + pdb->submit_transaction_sync(trans); + break; + } + it->next(); + } + it.reset(); + umount(); + + ASSERT_EQ(store->fsck(false), 3); + ASSERT_EQ(store->repair(false), 0); + ASSERT_EQ(store->fsck(false), 0); + + cleanup_store(); +} + #endif // WITH_BLUESTORE TEST_P(StoreTestSpecificAUSize, BluestoreEnforceHWSettingsHdd) {