From 8d61c3965873286bf3173edbe67f734a8a2d144b Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Tue, 3 Feb 2015 06:07:00 -0500 Subject: [PATCH] librbd: prevent copyup during image shrink operations If a cloned image was shrunk, it was possible for a copyup to be performed on objects outside of the new image range. Resize now pre-shrinks the parent overlap to disable copyup when removing objects. Signed-off-by: Jason Dillaman --- src/librbd/AioRequest.h | 7 +++++-- src/librbd/AsyncResizeRequest.cc | 13 +++++++++++++ src/librbd/AsyncResizeRequest.h | 5 ++++- src/librbd/ObjectMap.cc | 6 +++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/librbd/AioRequest.h b/src/librbd/AioRequest.h index ba9ae71eb3a94..a5da41edbefd5 100644 --- a/src/librbd/AioRequest.h +++ b/src/librbd/AioRequest.h @@ -249,15 +249,18 @@ namespace librbd { protected: virtual void add_write_ops(librados::ObjectWriteOperation *wr) { if (has_parent()) { - m_object_state = OBJECT_EXISTS; wr->truncate(0); } else { - m_object_state = OBJECT_PENDING; wr->remove(); } } virtual void pre_object_map_update(uint8_t *new_state) { + if (has_parent()) { + m_object_state = OBJECT_EXISTS; + } else { + m_object_state = OBJECT_PENDING; + } *new_state = m_object_state; } diff --git a/src/librbd/AsyncResizeRequest.cc b/src/librbd/AsyncResizeRequest.cc index af2a3cdf8dccf..8b161d50daa8f 100644 --- a/src/librbd/AsyncResizeRequest.cc +++ b/src/librbd/AsyncResizeRequest.cc @@ -27,6 +27,12 @@ bool AsyncResizeRequest::should_complete(int r) if (m_image_ctx.size == m_new_size) { m_image_ctx.size = m_original_size; } + + RWLock::WLocker l2(m_image_ctx.parent_lock); + if (m_image_ctx.parent != NULL && + m_image_ctx.parent_md.overlap == m_new_parent_overlap) { + m_image_ctx.parent_md.overlap = m_original_parent_overlap; + } return true; } @@ -92,6 +98,13 @@ void AsyncResizeRequest::send_trim_image() { // update in-memory size to clip concurrent IO operations RWLock::WLocker l(m_image_ctx.md_lock); m_image_ctx.size = m_new_size; + + RWLock::WLocker l2(m_image_ctx.parent_lock); + if (m_image_ctx.parent != NULL) { + m_original_parent_overlap = m_image_ctx.parent_md.overlap; + m_new_parent_overlap = MIN(m_new_size, m_original_parent_overlap); + m_image_ctx.parent_md.overlap = m_new_parent_overlap; + } } AsyncTrimRequest *req = new AsyncTrimRequest(m_image_ctx, diff --git a/src/librbd/AsyncResizeRequest.h b/src/librbd/AsyncResizeRequest.h index 0e72a101e7ffa..6884abf003936 100644 --- a/src/librbd/AsyncResizeRequest.h +++ b/src/librbd/AsyncResizeRequest.h @@ -19,7 +19,8 @@ public: ProgressContext &prog_ctx) : AsyncRequest(image_ctx, on_finish), m_original_size(original_size), m_new_size(new_size), - m_prog_ctx(prog_ctx) + m_prog_ctx(prog_ctx), m_original_parent_overlap(0), + m_new_parent_overlap(0) { } @@ -60,6 +61,8 @@ protected: uint64_t m_original_size; uint64_t m_new_size; ProgressContext &m_prog_ctx; + uint64_t m_original_parent_overlap; + uint64_t m_new_parent_overlap; virtual bool should_complete(int r); diff --git a/src/librbd/ObjectMap.cc b/src/librbd/ObjectMap.cc index f179fa8330290..6b2be6389cc49 100644 --- a/src/librbd/ObjectMap.cc +++ b/src/librbd/ObjectMap.cc @@ -187,6 +187,9 @@ bool ObjectMap::aio_update(uint64_t start_object_no, uint64_t end_object_no, assert(start_object_no < end_object_no); CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << &m_image_ctx << " aio_update: start=" << start_object_no + << ", end=" << end_object_no << ", new_state=" + << static_cast(new_state) << dendl; if (end_object_no > object_map.size()) { ldout(cct, 20) << "skipping update of invalid object map" << dendl; return false; @@ -319,7 +322,8 @@ void ObjectMap::UpdateRequest::send() { ldout(cct, 20) << &m_image_ctx << " updating on-disk object map: [" << m_start_object_no << "," << m_end_object_no << ") = " - << (m_current_state ? stringify(*m_current_state) : "") + << (m_current_state ? + stringify(static_cast(*m_current_state)) : "") << "->" << static_cast(m_new_state) << dendl; -- 2.39.5