<< m_object_map.size() << " < " << num_objs << dendl;
finish(-EINVAL);
return;
- } else {
- m_object_map.resize(num_objs);
}
uint64_t start_object_no, end_object_no;
uint64_t prev_object_diff_state_size = m_object_diff_state->size();
if (is_diff_iterate()) {
- start_object_no = std::min(m_start_object_no, m_object_map.size());
- end_object_no = std::min(m_end_object_no, m_object_map.size());
+ start_object_no = std::min(m_start_object_no, num_objs);
+ end_object_no = std::min(m_end_object_no, num_objs);
uint64_t num_objs_in_range = end_object_no - start_object_no;
if (m_object_diff_state->size() != num_objs_in_range) {
m_object_diff_state->resize(num_objs_in_range);
} else {
// for deep-copy, the object diff state should be the largest of
// all versions in the set, so it's only ever grown
- if (m_object_diff_state->size() < m_object_map.size()) {
- m_object_diff_state->resize(m_object_map.size());
- } else if (m_object_diff_state->size() > m_object_map.size()) {
- // the image was shrunk so expanding the object map will flag end objects
- // as non-existent and they will be compared against the previous object
- // diff state
- m_object_map.resize(m_object_diff_state->size());
+ // shrink is handled by flagging trimmed objects as non-existent
+ // and comparing against the previous object diff state as usual
+ if (m_object_diff_state->size() < num_objs) {
+ m_object_diff_state->resize(num_objs);
}
start_object_no = 0;
end_object_no = m_object_diff_state->size();
auto it = m_object_map.begin() + start_object_no;
auto diff_it = m_object_diff_state->begin();
uint64_t ono = start_object_no;
- for (; ono < start_object_no + overlap; ++it, ++diff_it, ++ono) {
- uint8_t object_map_state = *it;
+ for (; ono < start_object_no + overlap; ++diff_it, ++ono) {
+ uint8_t object_map_state = (ono < num_objs ? *it++ : OBJECT_NONEXISTENT);
uint8_t prev_object_diff_state = *diff_it;
switch (prev_object_diff_state) {
case DIFF_STATE_HOLE:
ldout(cct, 20) << "computed overlap diffs" << dendl;
ceph_assert(diff_it == m_object_diff_state->end() ||
- end_object_no <= m_object_map.size());
+ end_object_no <= num_objs);
for (; ono < end_object_no; ++it, ++diff_it, ++ono) {
uint8_t object_map_state = *it;
if (object_map_state == OBJECT_NONEXISTENT) {
}
}
+TEST_P(TestMockObjectMapDiffRequest, ObjectMapTooLarge) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count + 12);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count + 34);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(MockObjectMapDiffRequestTests,
TestMockObjectMapDiffRequest, ::testing::Bool());