This commit implements the prepare_copyup api by the crypto object dispatch layer.
Signed-off-by: Or Ozeri <oro@il.ibm.com>
uint64_t journal_tid, uint64_t new_journal_tid) {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
private:
uint64_t journal_tid, uint64_t new_journal_tid) {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
ImageCtxT* get_image_ctx() {
uint64_t journal_tid, uint64_t new_journal_tid) override {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
private:
return true;
}
+template <typename I>
+int CryptoObjectDispatch<I>::prepare_copyup(
+ uint64_t object_no,
+ io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) {
+ ceph::bufferlist current_bl;
+ current_bl.append_zero(m_image_ctx->get_object_size());
+
+ for (auto& [key, extent_map]: *snapshot_sparse_bufferlist) {
+ // update current_bl with data from extent_map
+ for (auto& extent : extent_map) {
+ auto &sbe = extent.get_val();
+ if (sbe.state == io::SPARSE_EXTENT_STATE_DATA) {
+ current_bl.begin(extent.get_off()).copy_in(extent.get_len(), sbe.bl);
+ } else if (sbe.state == io::SPARSE_EXTENT_STATE_ZEROED) {
+ ceph::bufferlist zeros;
+ zeros.append_zero(extent.get_len());
+ current_bl.begin(extent.get_off()).copy_in(extent.get_len(), zeros);
+ }
+ }
+
+ // encrypt
+ io::SparseBufferlist encrypted_sparse_bufferlist;
+ for (auto& extent : extent_map) {
+ auto [aligned_off, aligned_len] = m_crypto->align(
+ extent.get_off(), extent.get_len());
+
+ io::Extents image_extents;
+ Striper::extent_to_file(
+ m_image_ctx->cct, &m_image_ctx->layout, object_no, aligned_off,
+ aligned_len, image_extents);
+
+ ceph::bufferlist encrypted_bl;
+ uint64_t position = 0;
+ for (auto [image_offset, image_length]: image_extents) {
+ ceph::bufferlist aligned_bl;
+ aligned_bl.substr_of(current_bl, aligned_off + position, image_length);
+ aligned_bl.rebuild(); // to deep copy aligned_bl from current_bl
+ position += image_length;
+
+ auto r = m_crypto->encrypt(&aligned_bl, image_offset);
+ if (r != 0) {
+ return r;
+ }
+
+ encrypted_bl.append(aligned_bl);
+ }
+
+ encrypted_sparse_bufferlist.insert(
+ aligned_off, aligned_len, {io::SPARSE_EXTENT_STATE_DATA, aligned_len,
+ std::move(encrypted_bl)});
+ }
+
+ // replace original plaintext sparse bufferlist with encrypted one
+ extent_map.clear();
+ extent_map.insert(std::move(encrypted_sparse_bufferlist));
+ }
+
+ return 0;
+}
+
} // namespace crypto
} // namespace librbd
uint64_t journal_tid, uint64_t new_journal_tid) override {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
- io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
- }
+ io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override;
private:
// let dispatch layers have a chance to process the data but
// assume that the dispatch layer will only touch the sparse bufferlist
- m_dst_image_ctx->io_object_dispatcher->prepare_copyup(
+ auto r = m_dst_image_ctx->io_object_dispatcher->prepare_copyup(
m_dst_object_number, &m_snapshot_sparse_bufferlist);
+ if (r < 0) {
+ lderr(m_cct) << "failed to prepare copyup data: " << cpp_strerror(r)
+ << dendl;
+ finish(r);
+ return;
+ }
send_write_object();
}
m_lock.lock();
disable_append_requests();
- prepare_copyup_data();
+ r = prepare_copyup_data();
+ if (r < 0) {
+ m_lock.unlock();
+ m_image_ctx->image_lock.unlock_shared();
+
+ lderr(m_image_ctx->cct) << "failed to prepare copyup data: "
+ << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
m_copyup_is_zero = m_copyup_data.is_zero();
m_copyup_required = is_copyup_required();
}
template <typename I>
-void CopyupRequest<I>::prepare_copyup_data() {
+int CopyupRequest<I>::prepare_copyup_data() {
ceph_assert(ceph_mutex_is_locked(m_image_ctx->image_lock));
auto cct = m_image_ctx->cct;
}
// Let dispatch layers have a chance to process the data
- m_image_ctx->io_object_dispatcher->prepare_copyup(
+ auto r = m_image_ctx->io_object_dispatcher->prepare_copyup(
m_object_no, &snapshot_sparse_bufferlist);
+ if (r < 0) {
+ return r;
+ }
// Convert sparse extents back to extent map
m_copyup_data.clear();
m_copyup_data.append(sbe.bl);
}
}
+
+ return 0;
}
} // namespace io
void compute_deep_copy_snap_ids();
void convert_copyup_extent_map();
- void prepare_copyup_data();
+ int prepare_copyup_data();
};
} // namespace io
uint64_t journal_tid, uint64_t new_journal_tid) override {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
private:
uint64_t object_no, uint64_t object_off, uint64_t object_len,
uint64_t journal_tid, uint64_t new_journal_tid) = 0;
- virtual void prepare_copyup(
+ virtual int prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) = 0;
}
template <typename I>
-void ObjectDispatcher<I>::prepare_copyup(
+int ObjectDispatcher<I>::prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) {
auto cct = this->m_image_ctx->cct;
for (auto it : this->m_dispatches) {
auto& object_dispatch_meta = it.second;
auto object_dispatch = object_dispatch_meta.dispatch;
- object_dispatch->prepare_copyup(object_no, snapshot_sparse_bufferlist);
+ auto r = object_dispatch->prepare_copyup(
+ object_no, snapshot_sparse_bufferlist);
+ if (r < 0) {
+ return r;
+ }
}
+
+ return 0;
}
template <typename I>
uint64_t object_no, uint64_t object_off, uint64_t object_len,
uint64_t journal_tid, uint64_t new_journal_tid) override;
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override;
uint64_t object_no, uint64_t object_off, uint64_t object_len,
uint64_t journal_tid, uint64_t new_journal_tid) = 0;
- virtual void prepare_copyup(
+ virtual int prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) = 0;
uint64_t journal_tid, uint64_t new_journal_tid) override {
}
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
private:
uint64_t object_no, uint64_t object_off, uint64_t object_len,
uint64_t journal_tid, uint64_t new_journal_tid) override;
- void prepare_copyup(
+ int prepare_copyup(
uint64_t object_no,
io::SnapshotSparseBufferlist* snapshot_sparse_bufferlist) override {
+ return 0;
}
private:
ASSERT_EQ(0, dispatched_cond.wait());
}
+TEST_F(TestMockCryptoCryptoObjectDispatch, PrepareCopyup) {
+ char* data = (char*)"0123456789";
+ io::SnapshotSparseBufferlist snapshot_sparse_bufferlist;
+ auto& snap1 = snapshot_sparse_bufferlist[0];
+ auto& snap2 = snapshot_sparse_bufferlist[1];
+
+ snap1.insert(0, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
+ ceph::bufferlist::static_from_mem(data + 1, 1)});
+ snap1.insert(8191, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
+ ceph::bufferlist::static_from_mem(data + 2, 1)});
+ snap1.insert(8193, 3, {io::SPARSE_EXTENT_STATE_DATA, 3,
+ ceph::bufferlist::static_from_mem(data + 3, 3)});
+
+ snap2.insert(0, 2, {io::SPARSE_EXTENT_STATE_ZEROED, 2});
+ snap2.insert(8191, 3, {io::SPARSE_EXTENT_STATE_DATA, 3,
+ ceph::bufferlist::static_from_mem(data + 6, 3)});
+ snap2.insert(16384, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
+ ceph::bufferlist::static_from_mem(data + 9, 1)});
+
+ expect_get_object_size();
+ expect_encrypt(6);
+ ASSERT_EQ(0, mock_crypto_object_dispatch->prepare_copyup(
+ 0, &snapshot_sparse_bufferlist));
+
+ ASSERT_EQ(2, snapshot_sparse_bufferlist.size());
+
+ auto& snap1_result = snapshot_sparse_bufferlist[0];
+ auto& snap2_result = snapshot_sparse_bufferlist[1];
+
+ auto it = snap1_result.begin();
+ ASSERT_NE(it, snap1_result.end());
+ ASSERT_EQ(0, it.get_off());
+ ASSERT_EQ(4096 * 3, it.get_len());
+
+ ASSERT_TRUE(it.get_val().bl.to_str() ==
+ std::string("1") + std::string(4095, '\0') +
+ std::string(4095, '\0') + std::string("2") +
+ std::string(1, '\0') + std::string("345") + std::string(4092, '\0'));
+ ASSERT_EQ(++it, snap1_result.end());
+
+ it = snap2_result.begin();
+ ASSERT_NE(it, snap2_result.end());
+ ASSERT_EQ(0, it.get_off());
+ ASSERT_EQ(4096 * 3, it.get_len());
+ ASSERT_TRUE(it.get_val().bl.to_str() ==
+ std::string(4096, '\0') +
+ std::string(4095, '\0') + std::string("6") +
+ std::string("7845") + std::string(4092, '\0'));
+
+ ASSERT_NE(++it, snap2_result.end());
+ ASSERT_EQ(16384, it.get_off());
+ ASSERT_EQ(4096, it.get_len());
+ ASSERT_TRUE(it.get_val().bl.to_str() ==
+ std::string("9") + std::string(4095, '\0'));
+ ASSERT_EQ(++it, snap2_result.end());
+}
+
} // namespace io
} // namespace librbd
}
}
- void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, prepare_copyup(_, _));
+ void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx, int r = 0) {
+ EXPECT_CALL(*mock_image_ctx.io_object_dispatcher,
+ prepare_copyup(_, _)).WillOnce(Return(r));
}
int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
ASSERT_EQ(-EBLOCKLISTED, ctx.wait());
}
+TEST_F(TestMockDeepCopyObjectCopyRequest, PrepareCopyupError) {
+ // scribble some data
+ interval_set<uint64_t> one;
+ scribble(m_src_image_ctx, 10, 102400, &one);
+
+ ASSERT_EQ(0, create_snap("copy"));
+ librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+ librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+ librbd::MockObjectMap mock_object_map;
+ mock_dst_image_ctx.object_map = &mock_object_map;
+
+ expect_op_work_queue(mock_src_image_ctx);
+ expect_test_features(mock_dst_image_ctx);
+ expect_get_object_count(mock_dst_image_ctx);
+
+ C_SaferCond ctx;
+ MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
+
+ InSequence seq;
+ expect_list_snaps(mock_src_image_ctx, 0);
+ expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0);
+
+ expect_start_op(mock_exclusive_lock);
+ expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+ m_dst_snap_ids[0], OBJECT_EXISTS, 0);
+
+ expect_prepare_copyup(mock_dst_image_ctx, -EIO);
+
+ request->send();
+ ASSERT_EQ(-EIO, ctx.wait());
+}
+
TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
// scribble some data
interval_set<uint64_t> one;
}));
}
- void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, prepare_copyup(_, _));
+ void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx, int r = 0) {
+ EXPECT_CALL(*mock_image_ctx.io_object_dispatcher,
+ prepare_copyup(_, _)).WillOnce(Return(r));
}
void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx,
EXPECT_EQ(in_sparse_bl, sparse_bl);
sparse_bl = out_sparse_bl;
+ return 0;
})));
}
ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
}
+TEST_F(TestMockIoCopyupRequest, PrepareCopyupError) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
+ MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
+
+ MockExclusiveLock mock_exclusive_lock;
+ MockJournal mock_journal;
+ MockObjectMap mock_object_map;
+ initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+ mock_object_map);
+
+ expect_op_work_queue(mock_image_ctx);
+ expect_is_lock_owner(mock_image_ctx);
+
+ InSequence seq;
+
+ std::string data(4096, '1');
+ expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
+ expect_prepare_copyup(mock_image_ctx, -EIO);
+
+ auto req = new MockCopyupRequest(&mock_image_ctx, 0,
+ {{0, 4096}}, {});
+ mock_image_ctx.copyup_list[0] = req;
+ MockAbstractObjectWriteRequest mock_write_request;
+ req->append_request(&mock_write_request, {});
+ req->send();
+
+ ASSERT_EQ(-EIO, mock_write_request.ctx.wait());
+}
+
TEST_F(TestMockIoCopyupRequest, DeepCopyError) {
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
MOCK_METHOD5(extent_overwritten, void(uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t));
- MOCK_METHOD2(prepare_copyup, void(uint64_t, SnapshotSparseBufferlist*));
+ MOCK_METHOD2(prepare_copyup, int(uint64_t, SnapshotSparseBufferlist*));
};
} // namespace io
MOCK_METHOD5(extent_overwritten, void(uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t));
- MOCK_METHOD2(prepare_copyup, void(uint64_t, SnapshotSparseBufferlist*));
+ MOCK_METHOD2(prepare_copyup, int(uint64_t, SnapshotSparseBufferlist*));
MOCK_METHOD1(send, void(ObjectDispatchSpec*));
};