From 42d3d3ac2d33360aae071330cfa34b87c87eadc5 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Wed, 4 May 2016 17:00:59 -0400 Subject: [PATCH] librbd: guard object map against incompatible image sizes Signed-off-by: Jason Dillaman --- src/librbd/ObjectMap.cc | 9 ++++++++- src/librbd/ObjectMap.h | 3 +++ src/librbd/Operations.cc | 15 +++++++++++++-- src/librbd/internal.cc | 13 +++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/librbd/ObjectMap.cc b/src/librbd/ObjectMap.cc index 59d3a363585f..9f7d1d4a45cf 100644 --- a/src/librbd/ObjectMap.cc +++ b/src/librbd/ObjectMap.cc @@ -17,8 +17,10 @@ #include "common/dout.h" #include "common/errno.h" #include "common/WorkQueue.h" -#include "include/stringify.h" #include "cls/lock/cls_lock_client.h" +#include "cls/rbd/cls_rbd_types.h" +#include "include/stringify.h" +#include "osdc/Striper.h" #include #define dout_subsys ceph_subsys_rbd @@ -48,6 +50,11 @@ std::string ObjectMap::object_map_name(const std::string &image_id, return oid; } +bool ObjectMap::is_compatible(const file_layout_t& layout, uint64_t size) { + uint64_t object_count = Striper::get_num_objects(layout, size); + return (object_count <= cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT); +} + ceph::BitVector<2u>::Reference ObjectMap::operator[](uint64_t object_no) { assert(m_image_ctx.object_map_lock.is_wlocked()); diff --git a/src/librbd/ObjectMap.h b/src/librbd/ObjectMap.h index a2868aa6ef64..f2852961aa38 100644 --- a/src/librbd/ObjectMap.h +++ b/src/librbd/ObjectMap.h @@ -4,6 +4,7 @@ #define CEPH_LIBRBD_OBJECT_MAP_H #include "include/int_types.h" +#include "include/fs_types.h" #include "include/rados/librados.hpp" #include "include/rbd/object_map_types.h" #include "common/bit_vector.hpp" @@ -24,6 +25,8 @@ public: static std::string object_map_name(const std::string &image_id, uint64_t snap_id); + static bool is_compatible(const file_layout_t& layout, uint64_t size); + ceph::BitVector<2u>::Reference operator[](uint64_t object_no); uint8_t operator[](uint64_t object_no) const; inline uint64_t size() const { diff --git a/src/librbd/Operations.cc b/src/librbd/Operations.cc index 5c8b3d222ba4..620b0bf6cee1 100644 --- a/src/librbd/Operations.cc +++ b/src/librbd/Operations.cc @@ -9,6 +9,7 @@ #include "librbd/ImageCtx.h" #include "librbd/ImageState.h" #include "librbd/ImageWatcher.h" +#include "librbd/ObjectMap.h" #include "librbd/Utils.h" #include "librbd/operation/FlattenRequest.h" #include "librbd/operation/RebuildObjectMapRequest.h" @@ -499,6 +500,12 @@ int Operations::resize(uint64_t size, ProgressContext& prog_ctx) { return r; } + if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) && + !ObjectMap::is_compatible(m_image_ctx.layout, size)) { + lderr(cct) << "New size not compatible with object map" << dendl; + return -EINVAL; + } + uint64_t request_id = ++m_async_request_seq; r = invoke_async_request("resize", false, boost::bind(&Operations::execute_resize, this, @@ -525,13 +532,17 @@ void Operations::execute_resize(uint64_t size, ProgressContext &prog_ctx, ldout(cct, 5) << this << " " << __func__ << ": " << "size=" << m_image_ctx.size << ", " << "new_size=" << size << dendl; - m_image_ctx.snap_lock.put_read(); - m_image_ctx.snap_lock.get_read(); if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) { m_image_ctx.snap_lock.put_read(); on_finish->complete(-EROFS); return; + } else if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP, + m_image_ctx.snap_lock) && + !ObjectMap::is_compatible(m_image_ctx.layout, size)) { + m_image_ctx.snap_lock.put_read(); + on_finish->complete(-EINVAL); + return; } m_image_ctx.snap_lock.put_read(); diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 455d3b35eb4c..911af32f63fb 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -95,18 +95,26 @@ int remove_object_map(ImageCtx *ictx) { } return 0; } + int create_object_map(ImageCtx *ictx) { assert(ictx->snap_lock.is_locked()); CephContext *cct = ictx->cct; int r; + uint64_t max_size = ictx->size; std::vector snap_ids; snap_ids.push_back(CEPH_NOSNAP); for (std::map::iterator it = ictx->snap_info.begin(); it != ictx->snap_info.end(); ++it) { + max_size = MAX(max_size, it->second.size); snap_ids.push_back(it->first); } + if (!ObjectMap::is_compatible(ictx->layout, max_size)) { + lderr(cct) << "image size not compatible with object map" << dendl; + return -EINVAL; + } + for (std::vector::iterator it = snap_ids.begin(); it != snap_ids.end(); ++it) { librados::ObjectWriteOperation op; @@ -1098,6 +1106,11 @@ remove_mirroring_image: layout.stripe_count = stripe_count; } + if (!ObjectMap::is_compatible(layout, size)) { + lderr(cct) << "image size not compatible with object map" << dendl; + goto err_remove_header; + } + librados::ObjectWriteOperation op; cls_client::object_map_resize(&op, Striper::get_num_objects(layout, size), OBJECT_NONEXISTENT); -- 2.47.3