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 {
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);
class AioCompletion;
class AsyncOperation;
template <typename> class CopyupRequest;
+ enum class ImageArea;
struct ImageDispatcherInterface;
struct ObjectDispatcherInterface;
}
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,
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);
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);
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;
}
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)
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;
}
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;
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,
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));