]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: introduce reduce_parent_overlap() and switch overlap API
authorIlya Dryomov <idryomov@gmail.com>
Fri, 14 Oct 2022 14:20:24 +0000 (16:20 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 4 Dec 2022 17:19:19 +0000 (18:19 +0100)
When encryption is loaded, rbd_get_overlap() and Image::overlap() now
return "effective" overlap, similar to rbd_get_size() and Image::size().
Previously, returned overlap could have been bigger than "effective"
size.

Note that get_effective_image_size() successor doesn't take snap_id
because passing anything but ictx->snap_id was broken.  Since the size
of the crypto header is stored in the crypto header itself, image areas
are defined only for the "opened at" snap_id.  Getting "effective" size
for an arbitrary snapshot requires actually opening it and loading
encryption on it.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
src/librbd/ImageCtx.cc
src/librbd/ImageCtx.h
src/librbd/internal.cc
src/librbd/io/ImageRequest.cc
src/test/librbd/mock/MockImageCtx.h

index 1ca88b4168ce2c08ecfad7eda279b6955b92c64f..8f6413d0e405bf3a7edfc2d2f46e6c8200c5002d 100644 (file)
@@ -537,13 +537,26 @@ librados::IoCtx duplicate_io_ctx(librados::IoCtx& io_ctx) {
     return 0;
   }
 
-  uint64_t ImageCtx::get_effective_image_size(snap_t in_snap_id) const {
-    auto raw_size = get_image_size(in_snap_id);
+  uint64_t ImageCtx::get_area_size(io::ImageArea area) const {
+    // image areas are defined only for the "opened at" snap_id
+    // (i.e. where encryption may be loaded)
+    uint64_t raw_size = get_image_size(snap_id);
     if (raw_size == 0) {
       return 0;
     }
 
-    return io::util::raw_to_area_offset(*this, raw_size).first;
+    auto [data_size, data_area] = io::util::raw_to_area_offset(*this, raw_size);
+    ceph_assert(data_size <= raw_size && data_area == io::ImageArea::DATA);
+
+    switch (area) {
+    case io::ImageArea::DATA:
+      return data_size;
+    case io::ImageArea::CRYPTO_HEADER:
+      // CRYPTO_HEADER area ends where DATA area begins
+      return raw_size - data_size;
+    default:
+      ceph_abort();
+    }
   }
 
   uint64_t ImageCtx::get_object_count(snap_t in_snap_id) const {
@@ -682,6 +695,29 @@ librados::IoCtx duplicate_io_ctx(librados::IoCtx& io_ctx) {
     return -ENOENT;
   }
 
+  std::pair<uint64_t, io::ImageArea> ImageCtx::reduce_parent_overlap(
+      uint64_t raw_overlap, bool migration_write) const {
+    ceph_assert(ceph_mutex_is_locked(image_lock));
+    if (migration_write) {
+      // don't reduce migration write overlap -- it may be larger as
+      // it's the largest overlap across snapshots by construction
+      return io::util::remap_offset(*this, raw_overlap);
+    }
+    if (raw_overlap == 0 || parent == nullptr) {
+      // image opened with OPEN_FLAG_SKIP_OPEN_PARENT -> no overlap
+      return io::util::remap_offset(*this, 0);
+    }
+    // DATA area in the parent may be smaller than the part of DATA
+    // area in the clone that is still within the overlap (e.g. for
+    // LUKS2-encrypted parent + LUKS1-encrypted clone, due to LUKS2
+    // header usually being bigger than LUKS1 header)
+    auto overlap = io::util::remap_offset(*this, raw_overlap);
+    std::shared_lock parent_image_locker(parent->image_lock);
+    overlap.first = std::min(overlap.first,
+                             parent->get_area_size(overlap.second));
+    return overlap;
+  }
+
   void ImageCtx::register_watch(Context *on_finish) {
     ceph_assert(image_watcher != NULL);
     image_watcher->register_watch(on_finish);
index f9ce6dd16da0bcdaa7090c6ea5bedbad9c7302ff..8c69615a7178fe3a0142ebd8b89c1cf26cf81390 100644 (file)
@@ -61,6 +61,7 @@ namespace librbd {
   class AioCompletion;
   class AsyncOperation;
   template <typename> class CopyupRequest;
+  enum class ImageArea;
   struct ImageDispatcherInterface;
   struct ObjectDispatcherInterface;
   }
@@ -301,7 +302,7 @@ namespace librbd {
                 std::string in_snap_name,
                 librados::snap_t id);
     uint64_t get_image_size(librados::snap_t in_snap_id) const;
-    uint64_t get_effective_image_size(librados::snap_t in_snap_id) const;
+    uint64_t get_area_size(io::ImageArea area) const;
     uint64_t get_object_count(librados::snap_t in_snap_id) const;
     bool test_features(uint64_t test_features) const;
     bool test_features(uint64_t test_features,
@@ -323,6 +324,8 @@ namespace librbd {
     uint64_t get_parent_snap_id(librados::snap_t in_snap_id) const;
     int get_parent_overlap(librados::snap_t in_snap_id,
                            uint64_t* raw_overlap) const;
+    std::pair<uint64_t, io::ImageArea> reduce_parent_overlap(
+        uint64_t raw_overlap, bool migration_write) const;
     void register_watch(Context *on_finish);
     uint64_t prune_parent_extents(std::vector<std::pair<uint64_t,uint64_t> >& objectx,
                                  uint64_t overlap);
index 02d95d17d2ae1fbd4351676da50c87982da560f4..0cefd4b3603d2784b317b21f8fdfd1887555c609 100644 (file)
@@ -182,7 +182,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
     int obj_order = ictx->order;
     {
       std::shared_lock locker{ictx->image_lock};
-      info.size = ictx->get_effective_image_size(ictx->snap_id);
+      info.size = ictx->get_area_size(io::ImageArea::DATA);
     }
     info.obj_size = 1ULL << obj_order;
     info.num_objs = Striper::get_num_objects(ictx->layout, info.size);
@@ -859,7 +859,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
     if (r < 0)
       return r;
     std::shared_lock l2{ictx->image_lock};
-    *size = ictx->get_effective_image_size(ictx->snap_id);
+    *size = ictx->get_area_size(io::ImageArea::DATA);
     return 0;
   }
 
@@ -878,8 +878,16 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
     int r = ictx->state->refresh_if_required();
     if (r < 0)
       return r;
+
     std::shared_lock image_locker{ictx->image_lock};
-    return ictx->get_parent_overlap(ictx->snap_id, overlap);
+    uint64_t raw_overlap;
+    r = ictx->get_parent_overlap(ictx->snap_id, &raw_overlap);
+    if (r < 0) {
+      return r;
+    }
+    auto _overlap = ictx->reduce_parent_overlap(raw_overlap, false);
+    *overlap = (_overlap.second == io::ImageArea::DATA ? _overlap.first : 0);
+    return 0;
   }
 
   int get_flags(ImageCtx *ictx, uint64_t *flags)
@@ -1596,19 +1604,21 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
         ictx->get_snap_info(ictx->snap_id) == nullptr) {
       return -ENOENT;
     }
-    uint64_t image_size = ictx->get_effective_image_size(ictx->snap_id);
 
     // special-case "len == 0" requests: always valid
     if (*len == 0)
       return 0;
 
+    // TODO: pass area
+    uint64_t area_size = ictx->get_area_size(io::ImageArea::DATA);
+
     // can't start past end
-    if (off >= image_size)
+    if (off >= area_size)
       return -EINVAL;
 
     // clip requests that extend past end to just end
-    if ((off + *len) > image_size)
-      *len = (size_t)(image_size - off);
+    if ((off + *len) > area_size)
+      *len = (size_t)(area_size - off);
 
     return 0;
   }
index c7f09ef87ac146f0dd66c5098ac9e38dc1436ae6..0a032d25e9d83ab252feb07edc7397e7c1749558 100644 (file)
@@ -145,10 +145,10 @@ void readahead(I *ictx, const Extents& image_extents, IOContext io_context) {
     return;
   }
 
-  uint64_t image_size = ictx->get_effective_image_size(ictx->snap_id);
+  uint64_t data_size = ictx->get_area_size(ImageArea::DATA);
   ictx->image_lock.unlock_shared();
 
-  auto readahead_extent = ictx->readahead.update(image_extents, image_size);
+  auto readahead_extent = ictx->readahead.update(image_extents, data_size);
   uint64_t readahead_offset = readahead_extent.first;
   uint64_t readahead_length = readahead_extent.second;
 
index 6d84521616b6c886f950e9333f6ddce3df0f2243..a4c3fc0326ed884ee5e3eb60dc766d4fdf69cf7b 100644 (file)
@@ -69,7 +69,7 @@ struct MockImageCtx {
   MOCK_CONST_METHOD0(get_object_size, uint64_t());
   MOCK_CONST_METHOD0(get_current_size, uint64_t());
   MOCK_CONST_METHOD1(get_image_size, uint64_t(librados::snap_t));
-  MOCK_CONST_METHOD1(get_effective_image_size, uint64_t(librados::snap_t));
+  MOCK_CONST_METHOD1(get_area_size, uint64_t(io::ImageArea));
   MOCK_CONST_METHOD1(get_object_count, uint64_t(librados::snap_t));
   MOCK_CONST_METHOD1(get_read_flags, int(librados::snap_t));
   MOCK_CONST_METHOD2(get_flags, int(librados::snap_t in_snap_id,
@@ -86,6 +86,8 @@ struct MockImageCtx {
   MOCK_CONST_METHOD1(get_parent_info, const ParentImageInfo*(librados::snap_t));
   MOCK_CONST_METHOD2(get_parent_overlap, int(librados::snap_t in_snap_id,
                                              uint64_t *raw_overlap));
+  MOCK_CONST_METHOD2(reduce_parent_overlap,
+                     std::pair<uint64_t, io::ImageArea>(uint64_t, bool));
   MOCK_CONST_METHOD2(prune_parent_extents, uint64_t(std::vector<std::pair<uint64_t,uint64_t> >& ,
                                                     uint64_t));