From: Jason Dillaman Date: Wed, 4 May 2016 19:01:58 +0000 (-0400) Subject: librbd: add client-side memory constraint when loading object map X-Git-Tag: v10.2.1~17^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=764b3bd413b81d2c98f8c325100661ee41a571bc;p=ceph.git librbd: add client-side memory constraint when loading object map Signed-off-by: Jason Dillaman (cherry picked from commit 2dd34b2c7b8c376817aafe5cfdda7aa9cfb60e1a) --- diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index 1b38eabfbe1..f56e4e0da48 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -138,7 +138,6 @@ cls_method_handle_t h_mirror_image_status_remove_down; #define RBD_DIR_ID_KEY_PREFIX "id_" #define RBD_DIR_NAME_KEY_PREFIX "name_" #define RBD_METADATA_KEY_PREFIX "metadata_" -#define RBD_MAX_OBJECT_MAP_OBJECT_COUNT 256000000 static int snap_read_header(cls_method_context_t hctx, bufferlist& bl) { @@ -2268,7 +2267,7 @@ int object_map_resize(cls_method_context_t hctx, bufferlist *in, bufferlist *out } // protect against excessive memory requirements - if (object_count > RBD_MAX_OBJECT_MAP_OBJECT_COUNT) { + if (object_count > cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT) { CLS_ERR("object map too large: %" PRIu64, object_count); return -EINVAL; } diff --git a/src/cls/rbd/cls_rbd_types.h b/src/cls/rbd/cls_rbd_types.h index c8780f06820..f98a942e2ad 100644 --- a/src/cls/rbd/cls_rbd_types.h +++ b/src/cls/rbd/cls_rbd_types.h @@ -16,6 +16,8 @@ namespace ceph { class Formatter; } namespace cls { namespace rbd { +static const uint32_t MAX_OBJECT_MAP_OBJECT_COUNT = 256000000; + enum MirrorMode { MIRROR_MODE_DISABLED = 0, MIRROR_MODE_IMAGE = 1, diff --git a/src/librbd/object_map/RefreshRequest.cc b/src/librbd/object_map/RefreshRequest.cc index 048f72fcdd2..1bd465e10be 100644 --- a/src/librbd/object_map/RefreshRequest.cc +++ b/src/librbd/object_map/RefreshRequest.cc @@ -3,9 +3,11 @@ #include "librbd/object_map/RefreshRequest.h" #include "cls/rbd/cls_rbd_client.h" +#include "cls/rbd/cls_rbd_types.h" #include "cls/lock/cls_lock_client.h" #include "common/dout.h" #include "common/errno.h" +#include "common/WorkQueue.h" #include "librbd/ImageCtx.h" #include "librbd/ObjectMap.h" #include "librbd/object_map/InvalidateRequest.h" @@ -42,6 +44,10 @@ void RefreshRequest::send() { m_image_ctx.layout, m_image_ctx.get_image_size(m_snap_id)); } + + CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << this << " " << __func__ << ": " + << "object_count=" << m_object_count << dendl; send_lock(); } @@ -60,12 +66,15 @@ void RefreshRequest::apply() { template void RefreshRequest::send_lock() { - if (m_snap_id != CEPH_NOSNAP) { + CephContext *cct = m_image_ctx.cct; + if (m_object_count > cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT) { + send_invalidate_and_close(); + return; + } else if (m_snap_id != CEPH_NOSNAP) { send_load(); return; } - CephContext *cct = m_image_ctx.cct; std::string oid(ObjectMap::object_map_name(m_image_ctx.id, m_snap_id)); ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl; @@ -248,6 +257,35 @@ Context *RefreshRequest::handle_resize(int *ret_val) { return m_on_finish; } +template +void RefreshRequest::send_invalidate_and_close() { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 10) << this << " " << __func__ << dendl; + + using klass = RefreshRequest; + Context *ctx = create_context_callback< + klass, &klass::handle_invalidate_and_close>(this); + InvalidateRequest *req = InvalidateRequest::create( + m_image_ctx, m_snap_id, false, ctx); + + lderr(cct) << "object map too large: " << m_object_count << dendl; + RWLock::RLocker owner_locker(m_image_ctx.owner_lock); + RWLock::WLocker snap_locker(m_image_ctx.snap_lock); + req->send(); +} + +template +Context *RefreshRequest::handle_invalidate_and_close(int *ret_val) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl; + + assert(*ret_val == 0); + + *ret_val = -EFBIG; + m_object_map->clear(); + return m_on_finish; +} + } // namespace object_map } // namespace librbd diff --git a/src/librbd/object_map/RefreshRequest.h b/src/librbd/object_map/RefreshRequest.h index 2c94d1ed25c..9ae1f270d83 100644 --- a/src/librbd/object_map/RefreshRequest.h +++ b/src/librbd/object_map/RefreshRequest.h @@ -28,24 +28,25 @@ private: * @verbatim * * -----> LOCK (skip if snapshot) - * | - * v (other errors) - * LOAD * * * * * * * > INVALIDATE ------------\ - * | * | - * | * (-EINVAL or too small) | - * | * * * * * * > INVALIDATE_AND_RESIZE | - * | | * | - * | | * | - * | v * | - * | RESIZE * | - * | | * | - * | | * * * * * * * | - * | | * | - * | v v | - * \--------------------> LOCK <-------------/ - * | - * v - * + * * | + * * v (other errors) + * * LOAD * * * * * * * > INVALIDATE ------------\ + * * | * | + * * | * (-EINVAL or too small) | + * * | * * * * * * > INVALIDATE_AND_RESIZE | + * * | | * | + * * | | * | + * * | v * | + * * | RESIZE * | + * * | | * | + * * | | * * * * * * * | + * * | | * | + * * | v v | + * * \--------------------> LOCK <-------------/ + * * | + * v v + * INVALIDATE_AND_CLOSE ---------------> + * * @endverbatim */ @@ -74,6 +75,9 @@ private: void send_resize(); Context *handle_resize(int *ret_val); + void send_invalidate_and_close(); + Context *handle_invalidate_and_close(int *ret_val); + void apply(); }; diff --git a/src/test/librbd/object_map/test_mock_RefreshRequest.cc b/src/test/librbd/object_map/test_mock_RefreshRequest.cc index 0dfbb4c07d6..be982ce684e 100644 --- a/src/test/librbd/object_map/test_mock_RefreshRequest.cc +++ b/src/test/librbd/object_map/test_mock_RefreshRequest.cc @@ -142,6 +142,8 @@ public: }; TEST_F(TestMockObjectMapRefreshRequest, SuccessHead) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -170,6 +172,8 @@ TEST_F(TestMockObjectMapRefreshRequest, SuccessHead) { } TEST_F(TestMockObjectMapRefreshRequest, SuccessSnapshot) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -196,6 +200,8 @@ TEST_F(TestMockObjectMapRefreshRequest, SuccessSnapshot) { } TEST_F(TestMockObjectMapRefreshRequest, LoadError) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -224,6 +230,8 @@ TEST_F(TestMockObjectMapRefreshRequest, LoadError) { } TEST_F(TestMockObjectMapRefreshRequest, LoadCorrupt) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -254,6 +262,8 @@ TEST_F(TestMockObjectMapRefreshRequest, LoadCorrupt) { } TEST_F(TestMockObjectMapRefreshRequest, TooSmall) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -285,6 +295,8 @@ TEST_F(TestMockObjectMapRefreshRequest, TooSmall) { } TEST_F(TestMockObjectMapRefreshRequest, TooLarge) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -312,6 +324,8 @@ TEST_F(TestMockObjectMapRefreshRequest, TooLarge) { } TEST_F(TestMockObjectMapRefreshRequest, ResizeError) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -342,6 +356,33 @@ TEST_F(TestMockObjectMapRefreshRequest, ResizeError) { ASSERT_EQ(0, ctx.wait()); } +TEST_F(TestMockObjectMapRefreshRequest, LargeImageError) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockObjectMapImageCtx mock_image_ctx(*ictx); + + ceph::BitVector<2> on_disk_object_map; + init_object_map(mock_image_ctx, &on_disk_object_map); + + C_SaferCond ctx; + ceph::BitVector<2> object_map; + MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map, + TEST_SNAP_ID, &ctx); + + InSequence seq; + expect_get_image_size(mock_image_ctx, TEST_SNAP_ID, + std::numeric_limits::max()); + + MockInvalidateRequest invalidate_request; + expect_invalidate_request(mock_image_ctx, invalidate_request); + + req->send(); + ASSERT_EQ(-EFBIG, ctx.wait()); +} + } // namespace object_map } // namespace librbd