]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: clip extents to their area instead of DATA area
authorIlya Dryomov <idryomov@gmail.com>
Wed, 28 Sep 2022 08:31:45 +0000 (10:31 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 4 Dec 2022 17:19:19 +0000 (18:19 +0100)
This fixes cases where CRYPTO HEADER area is larger than DATA area.
In particular, it was effectively impossible to flatten unformatted
clones of such images.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
src/librbd/api/DiffIterate.cc
src/librbd/api/Io.cc
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/io/ImageDispatcher.cc
src/librbd/io/Utils.cc
src/librbd/io/Utils.h
src/test/librbd/test_librbd.cc

index 489763cf6def2b207fefec2dac2b4f83d015b826..1cc08968a2904516f496687a929ee1818e843be9 100644 (file)
@@ -198,7 +198,7 @@ int DiffIterate<I>::diff_iterate(I *ictx,
   }
 
   ictx->image_lock.lock_shared();
-  r = clip_io(ictx, off, &len);
+  r = clip_io(ictx, off, &len, io::ImageArea::DATA);
   ictx->image_lock.unlock_shared();
   if (r < 0) {
     return r;
index fb8501bde91c55c6881d5b45006ff1691c264dc9..af9d3ebe5cfcc767fe4ed418eb10d152666c09bb 100644 (file)
@@ -63,7 +63,8 @@ ssize_t Io<I>::write(
                  << "len = " << len << dendl;
 
   image_ctx.image_lock.lock_shared();
-  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len);
+  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len,
+                  io::ImageArea::DATA);
   image_ctx.image_lock.unlock_shared();
   if (r < 0) {
     lderr(cct) << "invalid IO request: " << cpp_strerror(r) << dendl;
@@ -90,7 +91,8 @@ ssize_t Io<I>::discard(
                  << "len = " << len << dendl;
 
   image_ctx.image_lock.lock_shared();
-  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len);
+  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len,
+                  io::ImageArea::DATA);
   image_ctx.image_lock.unlock_shared();
   if (r < 0) {
     lderr(cct) << "invalid IO request: " << cpp_strerror(r) << dendl;
@@ -116,7 +118,8 @@ ssize_t Io<I>::write_same(
                  << "len = " << len << ", data_len " << bl.length() << dendl;
 
   image_ctx.image_lock.lock_shared();
-  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len);
+  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len,
+                  io::ImageArea::DATA);
   image_ctx.image_lock.unlock_shared();
   if (r < 0) {
     lderr(cct) << "invalid IO request: " << cpp_strerror(r) << dendl;
@@ -142,7 +145,8 @@ ssize_t Io<I>::write_zeroes(I& image_ctx, uint64_t off, uint64_t len,
                  << "len = " << len << dendl;
 
   image_ctx.image_lock.lock_shared();
-  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len);
+  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len,
+                  io::ImageArea::DATA);
   image_ctx.image_lock.unlock_shared();
   if (r < 0) {
     lderr(cct) << "invalid IO request: " << cpp_strerror(r) << dendl;
@@ -169,7 +173,8 @@ ssize_t Io<I>::compare_and_write(
                  << off << ", " << "len = " << len << dendl;
 
   image_ctx.image_lock.lock_shared();
-  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len);
+  int r = clip_io(util::get_image_ctx(&image_ctx), off, &len,
+                  io::ImageArea::DATA);
   image_ctx.image_lock.unlock_shared();
   if (r < 0) {
     lderr(cct) << "invalid IO request: " << cpp_strerror(r) << dendl;
index 0cefd4b3603d2784b317b21f8fdfd1887555c609..297172e2c583cf52211d884ca19b92290bd16748 100644 (file)
@@ -1542,7 +1542,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
 
     uint64_t mylen = len;
     ictx->image_lock.lock_shared();
-    r = clip_io(ictx, off, &mylen);
+    r = clip_io(ictx, off, &mylen, io::ImageArea::DATA);
     ictx->image_lock.unlock_shared();
     if (r < 0)
       return r;
@@ -1595,9 +1595,8 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
     return total_read;
   }
 
-  // validate extent against image size; clip to image size if necessary
-  int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len)
-  {
+  // validate extent against area size; clip to area size if necessary
+  int clip_io(ImageCtx* ictx, uint64_t off, uint64_t* len, io::ImageArea area) {
     ceph_assert(ceph_mutex_is_locked(ictx->image_lock));
 
     if (ictx->snap_id != CEPH_NOSNAP &&
@@ -1609,8 +1608,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
     if (*len == 0)
       return 0;
 
-    // TODO: pass area
-    uint64_t area_size = ictx->get_area_size(io::ImageArea::DATA);
+    uint64_t area_size = ictx->get_area_size(area);
 
     // can't start past end
     if (off >= area_size)
index 2b2400b8c8cfe5c26059d78105063f823f97afab..50314a6e1780d2f0fa3a69df8fb59662ff2cc650 100644 (file)
 namespace librbd {
 
   struct ImageCtx;
-  namespace io { struct AioCompletion; }
+  namespace io {
+  struct AioCompletion;
+  enum class ImageArea;
+  }
 
   class NoOpProgressContext : public ProgressContext
   {
@@ -122,7 +125,7 @@ namespace librbd {
   void image_info(const ImageCtx *ictx, image_info_t& info, size_t info_size);
   uint64_t oid_to_object_no(const std::string& oid,
                            const std::string& object_prefix);
-  int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len);
+  int clip_io(ImageCtx* ictx, uint64_t off, uint64_t* len, io::ImageArea area);
   void init_rbd_header(struct rbd_obj_header_ondisk& ondisk,
                       uint64_t size, int order, uint64_t bid);
 
index 2dfdc58d4990e6c29089fe591fad5211052827cd..e7e5dda959639591dcb882cc1cdd34d042d18dd4 100644 (file)
@@ -135,8 +135,11 @@ struct ImageDispatcher<I>::PreprocessVisitor
   }
 
   bool clip_request() const {
+    auto area = (image_dispatch_spec->image_dispatch_flags &
+        IMAGE_DISPATCH_FLAG_CRYPTO_HEADER ? ImageArea::CRYPTO_HEADER :
+                                            ImageArea::DATA);
     int r = util::clip_request(image_dispatcher->m_image_ctx,
-                               &image_dispatch_spec->image_extents);
+                               &image_dispatch_spec->image_extents, area);
     if (r < 0) {
       image_dispatch_spec->fail(r);
       return true;
index 6b9fa5dca170643b8db1ec07311f7ad829750995..a8cef0e41bb93111dc08393cb32ebb00332b2035 100644 (file)
@@ -140,12 +140,12 @@ void read_parent(I *image_ctx, uint64_t object_no, ReadExtents* read_extents,
 }
 
 template <typename I>
-int clip_request(I *image_ctx, Extents *image_extents) {
+int clip_request(I* image_ctx, Extents* image_extents, ImageArea area) {
   std::shared_lock image_locker{image_ctx->image_lock};
   for (auto &image_extent : *image_extents) {
     auto clip_len = image_extent.second;
     int r = clip_io(librbd::util::get_image_ctx(image_ctx),
-                    image_extent.first, &clip_len);
+                    image_extent.first, &clip_len, area);
     if (r < 0) {
       return r;
     }
@@ -231,7 +231,7 @@ template void librbd::io::util::read_parent(
     librbd::ImageCtx *image_ctx, uint64_t object_no, ReadExtents* extents,
     librados::snap_t snap_id, const ZTracer::Trace &trace, Context* on_finish);
 template int librbd::io::util::clip_request(
-    librbd::ImageCtx *image_ctx, Extents *image_extents);
+    librbd::ImageCtx* image_ctx, Extents* image_extents, ImageArea area);
 template bool librbd::io::util::trigger_copyup(
         librbd::ImageCtx *image_ctx, uint64_t object_no, IOContext io_context,
         Context* on_finish);
index 04e8ba0e04a0ed2e2452a77fffbf054169b3c842..efb79b6a64da86d089f2b30cf5b959a9b6e8f2c6 100644 (file)
@@ -36,7 +36,7 @@ void read_parent(ImageCtxT *image_ctx, uint64_t object_no,
                  const ZTracer::Trace &trace, Context* on_finish);
 
 template <typename ImageCtxT = librbd::ImageCtx>
-int clip_request(ImageCtxT *image_ctx, Extents *image_extents);
+int clip_request(ImageCtxT* image_ctx, Extents* image_extents, ImageArea area);
 
 inline uint64_t get_extents_length(const Extents &extents) {
   uint64_t total_bytes = 0;
index 543a580568da6cb7eb4d396612b04811844906ad..ec31b861b7aed4a20fe97c097a7d641e694d1903 100644 (file)
@@ -2804,6 +2804,97 @@ TEST_F(TestLibRBD, EncryptedResize)
   }
 }
 
+TEST_F(TestLibRBD, EncryptedFlattenSmallData)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+  REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
+  REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
+
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+  librbd::RBD rbd;
+  std::string parent_name = get_temp_image_name();
+  std::string clone_name = get_temp_image_name();
+  uint64_t data_size = 5000;
+  uint64_t luks2_meta_size = 16 << 20;
+  std::string passphrase = "some passphrase";
+
+  {
+    int order = 22;
+    ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(),
+                                 luks2_meta_size + data_size, &order));
+    librbd::Image parent;
+    ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), nullptr));
+
+    librbd::encryption_luks2_format_options_t opts = {
+        RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
+    ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &opts,
+                                          sizeof(opts)));
+
+    ceph::bufferlist bl;
+    bl.append(std::string(data_size, 'a'));
+    ASSERT_EQ(data_size, parent.write(0, data_size, bl));
+
+    ASSERT_EQ(0, parent.snap_create("snap"));
+    ASSERT_EQ(0, parent.snap_protect("snap"));
+    uint64_t features;
+    ASSERT_EQ(0, parent.features(&features));
+    ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap", ioctx,
+                           clone_name.c_str(), features, &order));
+  }
+
+  {
+    librbd::Image clone;
+    ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
+
+    librbd::encryption_luks_format_options_t opts = {passphrase};
+    ASSERT_EQ(0, clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
+                                       sizeof(opts)));
+    uint64_t size;
+    ASSERT_EQ(0, clone.size(&size));
+    ASSERT_EQ(data_size, size);
+    uint64_t overlap;
+    ASSERT_EQ(0, clone.overlap(&overlap));
+    ASSERT_EQ(data_size, overlap);
+
+    ceph::bufferlist expected_bl;
+    expected_bl.append(std::string(data_size, 'a'));
+
+    ceph::bufferlist read_bl1;
+    ASSERT_EQ(data_size, clone.read(0, data_size, read_bl1));
+    ASSERT_TRUE(expected_bl.contents_equal(read_bl1));
+
+    ASSERT_EQ(0, clone.flatten());
+
+    ceph::bufferlist read_bl2;
+    ASSERT_EQ(data_size, clone.read(0, data_size, read_bl2));
+    ASSERT_TRUE(expected_bl.contents_equal(read_bl2));
+  }
+
+  {
+    librbd::Image clone;
+    ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
+
+    librbd::encryption_luks_format_options_t opts = {passphrase};
+    ASSERT_EQ(0, clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
+                                       sizeof(opts)));
+    uint64_t size;
+    ASSERT_EQ(0, clone.size(&size));
+    ASSERT_EQ(data_size, size);
+    uint64_t overlap;
+    ASSERT_EQ(0, clone.overlap(&overlap));
+    ASSERT_EQ(0, overlap);
+
+    ceph::bufferlist expected_bl;
+    expected_bl.append(std::string(data_size, 'a'));
+
+    ceph::bufferlist read_bl;
+    ASSERT_EQ(data_size, clone.read(0, data_size, read_bl));
+    ASSERT_TRUE(expected_bl.contents_equal(read_bl));
+  }
+}
+
 #endif
 
 TEST_F(TestLibRBD, TestIOWithIOHint)