@@ -1571,6 +1571,83 @@ TEST_F(TestInternal, FlattenNoEmptyObjects)
15711571 rados_ioctx_destroy (d_ioctx);
15721572}
15731573
1574+ TEST_F (TestInternal, FlattenInconsistentObjectMap)
1575+ {
1576+ REQUIRE_FEATURE (RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
1577+ REQUIRE (!is_feature_enabled (RBD_FEATURE_STRIPINGV2));
1578+
1579+ librbd::ImageCtx* ictx;
1580+ ASSERT_EQ (0 , open_image (m_image_name, &ictx));
1581+
1582+ librbd::NoOpProgressContext no_op;
1583+ ASSERT_EQ (0 , ictx->operations ->resize ((1 << ictx->order ) * 5 , true , no_op));
1584+
1585+ bufferlist bl;
1586+ bl.append (std::string (256 , ' 1' ));
1587+ for (int i = 1 ; i < 5 ; i++) {
1588+ ASSERT_EQ (256 , api::Io<>::write (*ictx, (1 << ictx->order ) * i, 256 ,
1589+ bufferlist{bl}, 0 ));
1590+ }
1591+
1592+ ASSERT_EQ (0 , snap_create (*ictx, " snap" ));
1593+ ASSERT_EQ (0 , snap_protect (*ictx, " snap" ));
1594+
1595+ uint64_t features;
1596+ ASSERT_EQ (0 , librbd::get_features (ictx, &features));
1597+
1598+ std::string clone_name = get_temp_image_name ();
1599+ int order = ictx->order ;
1600+ ASSERT_EQ (0 , librbd::clone (m_ioctx, m_image_name.c_str (), " snap" , m_ioctx,
1601+ clone_name.c_str (), features, &order, 0 , 0 ));
1602+
1603+ close_image (ictx);
1604+ ASSERT_EQ (0 , open_image (clone_name, &ictx));
1605+
1606+ C_SaferCond lock_ctx;
1607+ {
1608+ std::shared_lock owner_locker{ictx->owner_lock };
1609+ ictx->exclusive_lock ->try_acquire_lock (&lock_ctx);
1610+ }
1611+ ASSERT_EQ (0 , lock_ctx.wait ());
1612+ ASSERT_TRUE (ictx->exclusive_lock ->is_lock_owner ());
1613+
1614+ ceph::BitVector<2 > inconsistent_object_map;
1615+ inconsistent_object_map.resize (5 );
1616+ inconsistent_object_map[0 ] = OBJECT_NONEXISTENT;
1617+ inconsistent_object_map[1 ] = OBJECT_NONEXISTENT;
1618+ inconsistent_object_map[2 ] = OBJECT_EXISTS;
1619+ inconsistent_object_map[3 ] = OBJECT_EXISTS_CLEAN;
1620+ // OBJECT_PENDING shouldn't happen within parent overlap, but test
1621+ // anyway
1622+ inconsistent_object_map[4 ] = OBJECT_PENDING;
1623+
1624+ auto object_map = new librbd::ObjectMap<>(*ictx, CEPH_NOSNAP);
1625+ C_SaferCond save_ctx;
1626+ {
1627+ std::shared_lock owner_locker{ictx->owner_lock };
1628+ std::unique_lock image_locker{ictx->image_lock };
1629+ object_map->set_object_map (inconsistent_object_map);
1630+ object_map->aio_save (&save_ctx);
1631+ }
1632+ ASSERT_EQ (0 , save_ctx.wait ());
1633+ object_map->put ();
1634+
1635+ close_image (ictx);
1636+ ASSERT_EQ (0 , open_image (clone_name, &ictx));
1637+ ASSERT_EQ (0 , ictx->operations ->flatten (no_op));
1638+
1639+ bufferptr read_ptr (256 );
1640+ bufferlist read_bl;
1641+ read_bl.push_back (read_ptr);
1642+
1643+ librbd::io::ReadResult read_result{&read_bl};
1644+ for (int i = 1 ; i < 5 ; i++) {
1645+ ASSERT_EQ (256 , api::Io<>::read (*ictx, (1 << ictx->order ) * i, 256 ,
1646+ librbd::io::ReadResult{read_result}, 0 ));
1647+ EXPECT_TRUE (bl.contents_equal (read_bl));
1648+ }
1649+ }
1650+
15741651TEST_F (TestInternal, PoolMetadataConfApply) {
15751652 REQUIRE_FORMAT_V2 ();
15761653
0 commit comments