BlobRef& b) {
OldExtent* oe = new OldExtent(lo, o, l, b);
b->put_ref(c.get(), o, l, &(oe->r));
- oe->blob_empty = b->get_referenced_bytes() == 0;
+ oe->blob_empty = !b->is_referenced();
return oe;
}
}
} // for (auto& i : ref_map)
+ {
+ auto &sbm = o->extent_map.spanning_blob_map;
+ size_t broken = 0;
+ BlobRef first_broken;
+ for (auto it = sbm.begin(); it != sbm.end();) {
+ auto it1 = it++;
+ if (ref_map.count(it1->second) == 0) {
+ if (!broken) {
+ first_broken = it1->second;
+ ++errors;
+ }
+ broken++;
+ if (repairer) {
+ sbm.erase(it1);
+ }
+ }
+ }
+ if (broken) {
+ derr << "fsck error: " << oid << " - " << broken
+ << " zombie spanning blob(s) found, the first one: "
+ << *first_broken << dendl;
+ if(repairer) {
+ auto txn = repairer->fix_spanning_blobs(db);
+ _record_onode(o, txn);
+ }
+ }
+ }
+
if (o->onode.has_omap()) {
_fsck_check_object_omap(depth, o, ctx);
}
db->submit_transaction_sync(txn);
}
+void BlueStore::inject_zombie_spanning_blob(coll_t cid, ghobject_t oid,
+ int16_t blob_id)
+{
+ OnodeRef o;
+ CollectionRef c = _get_collection(cid);
+ ceph_assert(c);
+ {
+ std::unique_lock l{ c->lock }; // just to avoid internal asserts
+ o = c->get_onode(oid, false);
+ ceph_assert(o);
+ o->extent_map.fault_range(db, 0, OBJECT_MAX_SIZE);
+ }
+
+ BlobRef b = c->new_blob();
+ b->id = blob_id;
+ o->extent_map.spanning_blob_map[blob_id] = b;
+
+ KeyValueDB::Transaction txn;
+ txn = db->get_transaction();
+
+ _record_onode(o, txn);
+ db->submit_transaction_sync(txn);
+}
+
void BlueStore::collect_metadata(map<string,string> *pm)
{
dout(10) << __func__ << dendl;
return true;
}
+KeyValueDB::Transaction BlueStoreRepairer::fix_spanning_blobs(KeyValueDB* db)
+{
+ if (!fix_onode_txn) {
+ fix_onode_txn = db->get_transaction();
+ }
+ ++to_repair_cnt;
+ return fix_onode_txn;
+}
+
bool BlueStoreRepairer::preprocess_misreference(KeyValueDB *db)
{
if (misreferenced_extents.size()) {
db->submit_transaction_sync(fix_misreferences_txn);
fix_misreferences_txn = nullptr;
}
+ if (fix_onode_txn) {
+ db->submit_transaction_sync(fix_onode_txn);
+ fix_onode_txn = nullptr;
+ }
if (fix_shared_blob_txn) {
db->submit_transaction_sync(fix_shared_blob_txn);
fix_shared_blob_txn = nullptr;
void inject_misreference(coll_t cid1, ghobject_t oid1,
coll_t cid2, ghobject_t oid2,
uint64_t offset);
+ void inject_zombie_spanning_blob(coll_t cid, ghobject_t oid, int16_t blob_id);
// resets global per_pool_omap in DB
void inject_legacy_omap();
// resets per_pool_omap | pgmeta_omap for onode
FreelistManager* fm,
uint64_t offset, uint64_t len);
bool fix_bluefs_extents(std::atomic<uint64_t>& out_of_sync_flag);
+ KeyValueDB::Transaction fix_spanning_blobs(KeyValueDB* db);
void init(uint64_t total_space, uint64_t lres_tracking_unit_size);
KeyValueDB::Transaction fix_shared_blob_txn;
KeyValueDB::Transaction fix_misreferences_txn;
+ KeyValueDB::Transaction fix_onode_txn;
StoreSpaceTracker space_usage_tracker;
ASSERT_EQ(bstore->fsck(false), 0);
}
+ cerr << "Zombie spanning blob" << std::endl;
+ {
+ bstore->mount();
+ ghobject_t hoid4 = make_object("Object 4", pool);
+ auto ch = store->open_collection(cid);
+ {
+ bufferlist bl;
+ string s(0x1000, 'a');
+ bl.append(s);
+ ObjectStore::Transaction t;
+ for(size_t i = 0; i < 0x10; i++) {
+ t.write(cid, hoid4, i * bl.length(), bl.length(), bl);
+ }
+ r = queue_transaction(store, ch, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ sleep(5);
+ {
+ bstore->inject_zombie_spanning_blob(cid, hoid4, 12345);
+ bstore->inject_zombie_spanning_blob(cid, hoid4, 23456);
+ bstore->inject_zombie_spanning_blob(cid, hoid4, 23457);
+ }
+
+ bstore->umount();
+ ASSERT_EQ(bstore->fsck(false), 1);
+ ASSERT_LE(bstore->repair(false), 0);
+ ASSERT_EQ(bstore->fsck(false), 0);
+ }
+
cerr << "Completing" << std::endl;
bstore->mount();
}
-TEST_P(StoreTest, BluestoreRepairGlobalStats)
-{
+TEST_P(StoreTest, BluestoreRepairGlobalStats) {
if (string(GetParam()) != "bluestore")
return;
const size_t offs_base = 65536 / 2;
bstore->mount();
}
-TEST_P(StoreTest, BluestoreRepairGlobalStatsFixOnMount)
-{
+TEST_P(StoreTest, BluestoreRepairGlobalStatsFixOnMount) {
if (string(GetParam()) != "bluestore")
return;
const size_t offs_base = 65536 / 2;