]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: add encryption support for copyup 38114/head
authorOr Ozeri <oro@il.ibm.com>
Mon, 2 Nov 2020 13:20:18 +0000 (15:20 +0200)
committerOr Ozeri <oro@il.ibm.com>
Wed, 18 Nov 2020 19:08:30 +0000 (21:08 +0200)
This commit implements the prepare_copyup api by the crypto object dispatch layer.

Signed-off-by: Or Ozeri <oro@il.ibm.com>
20 files changed:
src/librbd/cache/ObjectCacherObjectDispatch.h
src/librbd/cache/ParentCacheObjectDispatch.h
src/librbd/cache/WriteAroundObjectDispatch.h
src/librbd/crypto/CryptoObjectDispatch.cc
src/librbd/crypto/CryptoObjectDispatch.h
src/librbd/deep_copy/ObjectCopyRequest.cc
src/librbd/io/CopyupRequest.cc
src/librbd/io/CopyupRequest.h
src/librbd/io/ObjectDispatch.h
src/librbd/io/ObjectDispatchInterface.h
src/librbd/io/ObjectDispatcher.cc
src/librbd/io/ObjectDispatcher.h
src/librbd/io/ObjectDispatcherInterface.h
src/librbd/io/SimpleSchedulerObjectDispatch.h
src/librbd/journal/ObjectDispatch.h
src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc
src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc
src/test/librbd/io/test_mock_CopyupRequest.cc
src/test/librbd/mock/io/MockObjectDispatch.h
src/test/librbd/mock/io/MockObjectDispatcher.h

index 5762c6914397b60f39f033ee752d363a364f18db..0cc87bd87ba80a4b98accf9a644392e2ee9155df 100644 (file)
@@ -101,9 +101,10 @@ public:
       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:
index 6d9c90828c0808b7b3d5e10f3b6a4453943203ad..1cf9c73b07cf7f2baed2c8f434eac22792356905 100644 (file)
@@ -118,9 +118,10 @@ public:
       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() {
index b91ab979e1ea05636201699ab9d948cd9f11cbe8..bc289f91cc84f65aaca7c7ba7a01e82da028b07a 100644 (file)
@@ -106,9 +106,10 @@ public:
       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:
index b09aad720a6b5d039804da34161f3c1a0e8c0772..4110c2e5a8ba9c244ac6c11060d0e14a8f27b8ea 100644 (file)
@@ -591,6 +591,66 @@ bool CryptoObjectDispatch<I>::discard(
   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
 
index a6cd87a9468fdccb8fbf368f9b03dac5942d6eb0..6df32ffee6d36c84d7e371a694e05c24194f85d0 100644 (file)
@@ -98,10 +98,9 @@ public:
           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:
 
index aa8dfdfe8c39d435bbcf6523178a7d2626181bb7..13cff743e63697d5dde26c9f717f7bc79398ac9a 100644 (file)
@@ -277,8 +277,14 @@ void ObjectCopyRequest<I>::process_copyup() {
 
   // 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();
 }
index 93effcb1cbb6858e5a01285786d00326404b3edd..4be133076c2b13f9c10d5a77eb89c20cd940ccad 100644 (file)
@@ -209,7 +209,16 @@ void CopyupRequest<I>::handle_read_from_parent(int r) {
   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();
@@ -678,7 +687,7 @@ void CopyupRequest<I>::convert_copyup_extent_map() {
 }
 
 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;
 
@@ -735,8 +744,11 @@ void CopyupRequest<I>::prepare_copyup_data() {
   }
 
   // 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();
@@ -749,6 +761,8 @@ void CopyupRequest<I>::prepare_copyup_data() {
       m_copyup_data.append(sbe.bl);
     }
   }
+
+  return 0;
 }
 
 } // namespace io
index 127fc4a00bf16253a4453f95aab31a099ec4118d..a6a20294c7f4bedbd5579c026b5e73f5557da5f8 100644 (file)
@@ -132,7 +132,7 @@ private:
 
   void compute_deep_copy_snap_ids();
   void convert_copyup_extent_map();
-  void prepare_copyup_data();
+  int prepare_copyup_data();
 };
 
 } // namespace io
index e66fba134fdc04c2ad2f22720bd57b6aee48d621..dd1f7261dddfc1ce424d4a321f3a3af2cf123188 100644 (file)
@@ -96,9 +96,10 @@ public:
       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:
index 1cd72dd1b9b149824d53572d2a1316da630ed41f..2e9dd1300cf5f7cab3753300b29a9b03dae91d6d 100644 (file)
@@ -90,7 +90,7 @@ struct ObjectDispatchInterface {
       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;
 
index 3bc55a57fd64213f9611e90f1a0756a1b04e053a..b66c6bb18c8e7ca5d01760f63f22dfa635ffe3bf 100644 (file)
@@ -173,7 +173,7 @@ void ObjectDispatcher<I>::extent_overwritten(
 }
 
 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;
@@ -183,8 +183,14 @@ void ObjectDispatcher<I>::prepare_copyup(
   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>
index 7b356afe6de144679bfa79f1bc6e29b5ff053af7..1e5e78d8b7f9c3ab2753aa0136b3d0e7493f709b 100644 (file)
@@ -34,7 +34,7 @@ public:
       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;
 
index b9f9197c02a4b4d736b80f387f242192e138fb7f..0f3d33330f57fc76f41314b81f4eda7343b8f0da 100644 (file)
@@ -23,7 +23,7 @@ public:
       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;
 
index ea125082d1d332fcb033adda901e8f35aef86a83..ca8a57f3a4e28c04ee853b3fc92ae3aa3a4798ed 100644 (file)
@@ -112,9 +112,10 @@ public:
       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:
index 18967a33aa4984959523395b31eb19570f1e2ca5..45e4773ccc40f0ee8e03bc50bfd47c0b62104611 100644 (file)
@@ -101,9 +101,10 @@ public:
       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:
index 805a83d75bda1ebd1494c44e8dace4014a871aea..2fb8f9f7024095da5dab8512795b1a1e1abdb394 100644 (file)
@@ -671,5 +671,62 @@ TEST_F(TestMockCryptoCryptoObjectDispatch, WriteSame) {
   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
index 3860a9aa1c93a009526cccad20b4d86dc873aea6..34ed54987859db233084e243266d77007bc99383 100644 (file)
@@ -298,8 +298,9 @@ public:
     }
   }
 
-  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,
@@ -826,6 +827,44 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
   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;
index ee7a911c43e2caf6ddf7e2b0e9b0fb6d6ae8d823..c8931d2c8aaa3913d18325d87e3e9fee4c1a2032 100644 (file)
@@ -338,8 +338,9 @@ struct TestMockIoCopyupRequest : public TestMockFixture {
         }));
   }
 
-  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,
@@ -354,6 +355,7 @@ struct TestMockIoCopyupRequest : public TestMockFixture {
           EXPECT_EQ(in_sparse_bl, sparse_bl);
 
           sparse_bl = out_sparse_bl;
+          return 0;
         })));
   }
 
@@ -977,6 +979,40 @@ TEST_F(TestMockIoCopyupRequest, ReadFromParentError) {
   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);
 
index 262e76bde337b18dde54e1db16147d90ff1e1eb8..baf86d9fb85e18c29e9bdadf46b685c91408d3a7 100644 (file)
@@ -128,7 +128,7 @@ public:
 
   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
index 0c3fc2c2c4ad84aa70baf7461b896ec15d6d8ad1..688744bcbe5404264c10c0e1cd5fd16781d5cee8 100644 (file)
@@ -32,7 +32,7 @@ public:
   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*));
 };