From d1f2c557b2c039730baca9efa3f5244bc19dcb1a Mon Sep 17 00:00:00 2001 From: Vaibhav Bhembre Date: Tue, 21 Jun 2016 20:17:25 -0400 Subject: [PATCH] rbd: add rbd_resize2 for allow_shrink option --- src/include/rbd/librbd.h | 2 + src/include/rbd/librbd.hpp | 1 + src/librbd/ImageWatcher.cc | 9 ++-- src/librbd/ImageWatcher.h | 2 +- src/librbd/Operations.cc | 12 ++--- src/librbd/Operations.h | 4 +- src/librbd/WatchNotifyTypes.cc | 14 ++++-- src/librbd/WatchNotifyTypes.h | 7 +-- src/librbd/journal/Replay.cc | 2 +- src/librbd/librbd.cc | 28 ++++++++++-- src/librbd/operation/ResizeRequest.cc | 15 +++++-- src/librbd/operation/ResizeRequest.h | 10 +++-- .../operation/SnapshotRollbackRequest.cc | 2 +- src/test/librbd/journal/test_Replay.cc | 2 +- src/test/librbd/journal/test_mock_Replay.cc | 4 +- src/test/librbd/mock/MockOperations.h | 4 +- .../operation/test_mock_ResizeRequest.cc | 45 +++++++++++++------ .../test_mock_SnapshotRollbackRequest.cc | 5 ++- src/test/librbd/test_ImageWatcher.cc | 2 +- src/test/librbd/test_internal.cc | 16 +++---- src/test/librbd/test_librbd.cc | 10 +++++ src/test/rbd_mirror/test_ImageSync.cc | 2 +- src/tools/rbd/action/Resize.cc | 17 ++++--- 23 files changed, 142 insertions(+), 73 deletions(-) diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 9c09547e954cb..2147205ab2b41 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -272,6 +272,8 @@ CEPH_RBD_API int rbd_aio_open_read_only(rados_ioctx_t io, const char *name, CEPH_RBD_API int rbd_close(rbd_image_t image); CEPH_RBD_API int rbd_aio_close(rbd_image_t image, rbd_completion_t c); CEPH_RBD_API int rbd_resize(rbd_image_t image, uint64_t size); +CEPH_RBD_API int rbd_resize2(rbd_image_t image, uint64_t size, bool allow_shrink, + librbd_progress_fn_t cb, void *cbdata); CEPH_RBD_API int rbd_resize_with_progress(rbd_image_t image, uint64_t size, librbd_progress_fn_t cb, void *cbdata); CEPH_RBD_API int rbd_stat(rbd_image_t image, rbd_image_info_t *info, diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 6b2026d4e81f5..982eb55b30b8e 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -191,6 +191,7 @@ class CEPH_RBD_API Image int aio_close(RBD::AioCompletion *c); int resize(uint64_t size); + int resize2(uint64_t size, bool allow_shrink, ProgressContext& pctx); int resize_with_progress(uint64_t size, ProgressContext& pctx); int stat(image_info_t &info, size_t infosize); int parent_info(std::string *parent_poolname, std::string *parent_name, diff --git a/src/librbd/ImageWatcher.cc b/src/librbd/ImageWatcher.cc index ffe951904a9c8..1dfe6681e7dd0 100644 --- a/src/librbd/ImageWatcher.cc +++ b/src/librbd/ImageWatcher.cc @@ -213,7 +213,7 @@ void ImageWatcher::notify_flatten(uint64_t request_id, } void ImageWatcher::notify_resize(uint64_t request_id, uint64_t size, - ProgressContext &prog_ctx, + bool allow_shrink, ProgressContext &prog_ctx, Context *on_finish) { assert(m_image_ctx.owner_lock.is_locked()); assert(m_image_ctx.exclusive_lock && @@ -222,7 +222,7 @@ void ImageWatcher::notify_resize(uint64_t request_id, uint64_t size, AsyncRequestId async_request_id(get_client_id(), request_id); bufferlist bl; - ::encode(NotifyMessage(ResizePayload(size, async_request_id)), bl); + ::encode(NotifyMessage(ResizePayload(size, allow_shrink, async_request_id)), bl); notify_async_request(async_request_id, std::move(bl), prog_ctx, on_finish); } @@ -711,8 +711,9 @@ bool ImageWatcher::handle_payload(const ResizePayload &payload, if (new_request) { ldout(m_image_ctx.cct, 10) << this << " remote resize request: " << payload.async_request_id << " " - << payload.size << dendl; - m_image_ctx.operations->execute_resize(payload.size, *prog_ctx, ctx, 0); + << payload.size << " " + << payload.allow_shrink << dendl; + m_image_ctx.operations->execute_resize(payload.size, payload.allow_shrink, *prog_ctx, ctx, 0); } ::encode(ResponseMessage(r), ack_ctx->out); diff --git a/src/librbd/ImageWatcher.h b/src/librbd/ImageWatcher.h index 5182a972772d3..0799cb8190416 100644 --- a/src/librbd/ImageWatcher.h +++ b/src/librbd/ImageWatcher.h @@ -33,7 +33,7 @@ class ImageWatcher { void notify_flatten(uint64_t request_id, ProgressContext &prog_ctx, Context *on_finish); - void notify_resize(uint64_t request_id, uint64_t size, + void notify_resize(uint64_t request_id, uint64_t size, bool allow_shrink, ProgressContext &prog_ctx, Context *on_finish); void notify_snap_create(const std::string &snap_name, Context *on_finish); void notify_snap_rename(const snapid_t &src_snap_id, diff --git a/src/librbd/Operations.cc b/src/librbd/Operations.cc index a7fd659bb1c84..48197d42e263b 100644 --- a/src/librbd/Operations.cc +++ b/src/librbd/Operations.cc @@ -558,7 +558,7 @@ void Operations::execute_rename(const char *dstname, Context *on_finish) { } template -int Operations::resize(uint64_t size, ProgressContext& prog_ctx) { +int Operations::resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx) { CephContext *cct = m_image_ctx.cct; m_image_ctx.snap_lock.get_read(); @@ -581,10 +581,10 @@ int Operations::resize(uint64_t size, ProgressContext& prog_ctx) { uint64_t request_id = ++m_async_request_seq; r = invoke_async_request("resize", false, boost::bind(&Operations::execute_resize, this, - size, boost::ref(prog_ctx), _1, 0), + size, allow_shrink, boost::ref(prog_ctx), _1, 0), boost::bind(&ImageWatcher::notify_resize, m_image_ctx.image_watcher, request_id, - size, boost::ref(prog_ctx), _1)); + size, allow_shrink, boost::ref(prog_ctx), _1)); m_image_ctx.perfcounter->inc(l_librbd_resize); ldout(cct, 2) << "resize finished" << dendl; @@ -592,7 +592,7 @@ int Operations::resize(uint64_t size, ProgressContext& prog_ctx) { } template -void Operations::execute_resize(uint64_t size, ProgressContext &prog_ctx, +void Operations::execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx, Context *on_finish, uint64_t journal_op_tid) { assert(m_image_ctx.owner_lock.is_locked()); @@ -619,8 +619,8 @@ void Operations::execute_resize(uint64_t size, ProgressContext &prog_ctx, m_image_ctx.snap_lock.put_read(); operation::ResizeRequest *req = new operation::ResizeRequest( - m_image_ctx, new C_NotifyUpdate(m_image_ctx, on_finish), size, prog_ctx, - journal_op_tid, false); + m_image_ctx, new C_NotifyUpdate(m_image_ctx, on_finish), size, allow_shrink, + prog_ctx, journal_op_tid, false); req->send(); } diff --git a/src/librbd/Operations.h b/src/librbd/Operations.h index b9e8615e4866b..f0ae5a1e65823 100644 --- a/src/librbd/Operations.h +++ b/src/librbd/Operations.h @@ -39,8 +39,8 @@ class Operations { int rename(const char *dstname); void execute_rename(const char *dstname, Context *on_finish); - int resize(uint64_t size, ProgressContext& prog_ctx); - void execute_resize(uint64_t size, ProgressContext &prog_ctx, + int resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx); + void execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx, Context *on_finish, uint64_t journal_op_tid); int snap_create(const char *snap_name); diff --git a/src/librbd/WatchNotifyTypes.cc b/src/librbd/WatchNotifyTypes.cc index 65c334ae855f1..949cce2695a22 100644 --- a/src/librbd/WatchNotifyTypes.cc +++ b/src/librbd/WatchNotifyTypes.cc @@ -207,17 +207,23 @@ void AsyncCompletePayload::dump(Formatter *f) const { } void ResizePayload::encode(bufferlist &bl) const { - ::encode(size, bl); AsyncRequestPayloadBase::encode(bl); + ::encode(size, bl); + ::encode(allow_shrink, bl); } void ResizePayload::decode(__u8 version, bufferlist::iterator &iter) { - ::decode(size, iter); AsyncRequestPayloadBase::decode(version, iter); + ::decode(size, iter); + + if (version >= 4) { + ::decode(allow_shrink, iter); + } } void ResizePayload::dump(Formatter *f) const { f->dump_unsigned("size", size); + f->dump_bool("allow_shrink", allow_shrink); AsyncRequestPayloadBase::dump(f); } @@ -275,7 +281,7 @@ bool NotifyMessage::check_for_refresh() const { } void NotifyMessage::encode(bufferlist& bl) const { - ENCODE_START(3, 1, bl); + ENCODE_START(4, 1, bl); boost::apply_visitor(EncodePayloadVisitor(bl), payload); ENCODE_FINISH(bl); } @@ -354,7 +360,7 @@ void NotifyMessage::generate_test_instances(std::list &o) { o.push_back(new NotifyMessage(AsyncProgressPayload(AsyncRequestId(ClientId(0, 1), 2), 3, 4))); o.push_back(new NotifyMessage(AsyncCompletePayload(AsyncRequestId(ClientId(0, 1), 2), 3))); o.push_back(new NotifyMessage(FlattenPayload(AsyncRequestId(ClientId(0, 1), 2)))); - o.push_back(new NotifyMessage(ResizePayload(123, AsyncRequestId(ClientId(0, 1), 2)))); + o.push_back(new NotifyMessage(ResizePayload(123, true, AsyncRequestId(ClientId(0, 1), 2)))); o.push_back(new NotifyMessage(SnapCreatePayload("foo"))); o.push_back(new NotifyMessage(SnapRemovePayload("foo"))); o.push_back(new NotifyMessage(SnapProtectPayload("foo"))); diff --git a/src/librbd/WatchNotifyTypes.h b/src/librbd/WatchNotifyTypes.h index f5ec6210e2228..a7bae5310dbf5 100644 --- a/src/librbd/WatchNotifyTypes.h +++ b/src/librbd/WatchNotifyTypes.h @@ -200,11 +200,12 @@ struct ResizePayload : public AsyncRequestPayloadBase { static const NotifyOp NOTIFY_OP = NOTIFY_OP_RESIZE; static const bool CHECK_FOR_REFRESH = true; - ResizePayload() : size(0) {} - ResizePayload(uint64_t size_, const AsyncRequestId &id) - : AsyncRequestPayloadBase(id), size(size_) {} + ResizePayload() : size(0), allow_shrink(true) {} + ResizePayload(uint64_t size_, bool allow_shrink_, const AsyncRequestId &id) + : AsyncRequestPayloadBase(id), size(size_), allow_shrink(allow_shrink_) {} uint64_t size; + bool allow_shrink; void encode(bufferlist &bl) const; void decode(__u8 version, bufferlist::iterator &iter); diff --git a/src/librbd/journal/Replay.cc b/src/librbd/journal/Replay.cc index 6143f21889465..9ee245e2d7462 100644 --- a/src/librbd/journal/Replay.cc +++ b/src/librbd/journal/Replay.cc @@ -76,7 +76,7 @@ struct ExecuteOp : public Context { } void execute(const journal::ResizeEvent &_) { - image_ctx.operations->execute_resize(event.size, no_op_progress_callback, + image_ctx.operations->execute_resize(event.size, true, no_op_progress_callback, on_op_complete, event.op_tid); } diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 052822f03e5c2..f0ef3764db864 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -615,7 +615,16 @@ namespace librbd { ImageCtx *ictx = (ImageCtx *)ctx; tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); librbd::NoOpProgressContext prog_ctx; - int r = ictx->operations->resize(size, prog_ctx); + int r = ictx->operations->resize(size, true, prog_ctx); + tracepoint(librbd, resize_exit, r); + return r; + } + + int Image::resize2(uint64_t size, bool allow_shrink, librbd::ProgressContext& pctx) + { + ImageCtx *ictx = (ImageCtx *)ctx; + tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); + int r = ictx->operations->resize(size, allow_shrink, pctx); tracepoint(librbd, resize_exit, r); return r; } @@ -624,7 +633,7 @@ namespace librbd { { ImageCtx *ictx = (ImageCtx *)ctx; tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); - int r = ictx->operations->resize(size, pctx); + int r = ictx->operations->resize(size, true, pctx); tracepoint(librbd, resize_exit, r); return r; } @@ -1969,7 +1978,18 @@ extern "C" int rbd_resize(rbd_image_t image, uint64_t size) librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); librbd::NoOpProgressContext prog_ctx; - int r = ictx->operations->resize(size, prog_ctx); + int r = ictx->operations->resize(size, true, prog_ctx); + tracepoint(librbd, resize_exit, r); + return r; +} + +extern "C" int rbd_resize2(rbd_image_t image, uint64_t size, bool allow_shrink, + librbd_progress_fn_t cb, void *cbdata) +{ + librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; + tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); + librbd::CProgressContext prog_ctx(cb, cbdata); + int r = ictx->operations->resize(size, allow_shrink, prog_ctx); tracepoint(librbd, resize_exit, r); return r; } @@ -1980,7 +2000,7 @@ extern "C" int rbd_resize_with_progress(rbd_image_t image, uint64_t size, librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); librbd::CProgressContext prog_ctx(cb, cbdata); - int r = ictx->operations->resize(size, prog_ctx); + int r = ictx->operations->resize(size, true, prog_ctx); tracepoint(librbd, resize_exit, r); return r; } diff --git a/src/librbd/operation/ResizeRequest.cc b/src/librbd/operation/ResizeRequest.cc index f7e5ba33a2d61..0aef072c8f9b8 100644 --- a/src/librbd/operation/ResizeRequest.cc +++ b/src/librbd/operation/ResizeRequest.cc @@ -25,11 +25,11 @@ using util::create_rados_safe_callback; template ResizeRequest::ResizeRequest(I &image_ctx, Context *on_finish, - uint64_t new_size, ProgressContext &prog_ctx, + uint64_t new_size, bool allow_shrink, ProgressContext &prog_ctx, uint64_t journal_op_tid, bool disable_journal) : Request(image_ctx, on_finish, journal_op_tid), - m_original_size(0), m_new_size(new_size), m_prog_ctx(prog_ctx), - m_new_parent_overlap(0), m_disable_journal(disable_journal), + m_original_size(0), m_new_size(new_size), m_allow_shrink(allow_shrink), + m_prog_ctx(prog_ctx), m_new_parent_overlap(0), m_disable_journal(disable_journal), m_xlist_item(this) { } @@ -114,12 +114,19 @@ Context *ResizeRequest::handle_pre_block_writes(int *result) { template Context *ResizeRequest::send_append_op_event() { I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + + if (m_new_size < m_original_size && !m_allow_shrink) { + ldout(cct, 1) << " shrinking the image is not permitted" << dendl; + this->async_complete(-EINVAL); + return nullptr; + } + if (m_disable_journal || !this->template append_op_event< ResizeRequest, &ResizeRequest::handle_append_op_event>(this)) { return send_grow_object_map(); } - CephContext *cct = image_ctx.cct; ldout(cct, 5) << this << " " << __func__ << dendl; return nullptr; } diff --git a/src/librbd/operation/ResizeRequest.h b/src/librbd/operation/ResizeRequest.h index bd5019f80475e..069718e0889e6 100644 --- a/src/librbd/operation/ResizeRequest.h +++ b/src/librbd/operation/ResizeRequest.h @@ -18,14 +18,15 @@ template class ResizeRequest : public Request { public: static ResizeRequest *create(ImageCtxT &image_ctx, Context *on_finish, - uint64_t new_size, ProgressContext &prog_ctx, - uint64_t journal_op_tid, bool disable_journal) { - return new ResizeRequest(image_ctx, on_finish, new_size, prog_ctx, + uint64_t new_size, bool allow_shrink, + ProgressContext &prog_ctx, uint64_t journal_op_tid, + bool disable_journal) { + return new ResizeRequest(image_ctx, on_finish, new_size, allow_shrink, prog_ctx, journal_op_tid, disable_journal); } ResizeRequest(ImageCtxT &image_ctx, Context *on_finish, uint64_t new_size, - ProgressContext &prog_ctx, uint64_t journal_op_tid, + bool allow_shrink, ProgressContext &prog_ctx, uint64_t journal_op_tid, bool disable_journal); virtual ~ResizeRequest(); @@ -106,6 +107,7 @@ class ResizeRequest : public Request { uint64_t m_original_size; uint64_t m_new_size; + bool m_allow_shrink = true; ProgressContext &m_prog_ctx; uint64_t m_new_parent_overlap; bool m_shrink_size_visible = false; diff --git a/src/librbd/operation/SnapshotRollbackRequest.cc b/src/librbd/operation/SnapshotRollbackRequest.cc index 6dcf3a7108350..0ab5f34d330f7 100644 --- a/src/librbd/operation/SnapshotRollbackRequest.cc +++ b/src/librbd/operation/SnapshotRollbackRequest.cc @@ -137,7 +137,7 @@ void SnapshotRollbackRequest::send_resize_image() { SnapshotRollbackRequest, &SnapshotRollbackRequest::handle_resize_image>(this); ResizeRequest *req = ResizeRequest::create(image_ctx, ctx, m_snap_size, - m_no_op_prog_ctx, 0, true); + true, m_no_op_prog_ctx, 0, true); req->send(); } diff --git a/src/test/librbd/journal/test_Replay.cc b/src/test/librbd/journal/test_Replay.cc index cbde9ae72bdf6..b0acb69c0c528 100644 --- a/src/test/librbd/journal/test_Replay.cc +++ b/src/test/librbd/journal/test_Replay.cc @@ -617,7 +617,7 @@ TEST_F(TestJournalReplay, Resize) { // verify lock ordering constraints librbd::NoOpProgressContext no_op_progress; - ASSERT_EQ(0, ictx->operations->resize(0, no_op_progress)); + ASSERT_EQ(0, ictx->operations->resize(0, true, no_op_progress)); } TEST_F(TestJournalReplay, Flatten) { diff --git a/src/test/librbd/journal/test_mock_Replay.cc b/src/test/librbd/journal/test_mock_Replay.cc index 8a9c86941d8b2..c2d7982f51d35 100644 --- a/src/test/librbd/journal/test_mock_Replay.cc +++ b/src/test/librbd/journal/test_mock_Replay.cc @@ -138,8 +138,8 @@ class TestMockJournalReplay : public TestMockFixture { void expect_resize(MockReplayImageCtx &mock_image_ctx, Context **on_finish, uint64_t size, uint64_t op_tid) { - EXPECT_CALL(*mock_image_ctx.operations, execute_resize(size, _, _, op_tid)) - .WillOnce(DoAll(SaveArg<2>(on_finish), + EXPECT_CALL(*mock_image_ctx.operations, execute_resize(size, _, _, _, op_tid)) + .WillOnce(DoAll(SaveArg<3>(on_finish), NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); } diff --git a/src/test/librbd/mock/MockOperations.h b/src/test/librbd/mock/MockOperations.h index 5d4e2221e537d..6d2ab21fd6a23 100644 --- a/src/test/librbd/mock/MockOperations.h +++ b/src/test/librbd/mock/MockOperations.h @@ -18,8 +18,8 @@ struct MockOperations { MOCK_METHOD2(execute_rebuild_object_map, void(ProgressContext &prog_ctx, Context *on_finish)); MOCK_METHOD2(execute_rename, void(const char *dstname, Context *on_finish)); - MOCK_METHOD4(execute_resize, void(uint64_t size, ProgressContext &prog_ctx, - Context *on_finish, + MOCK_METHOD5(execute_resize, void(uint64_t size, bool allow_shrink, + ProgressContext &prog_ctx, Context *on_finish, uint64_t journal_op_tid)); MOCK_METHOD2(snap_create, void(const char *snap_name, Context *on_finish)); MOCK_METHOD4(execute_snap_create, void(const char *snap_name, diff --git a/src/test/librbd/operation/test_mock_ResizeRequest.cc b/src/test/librbd/operation/test_mock_ResizeRequest.cc index 34b0debde8b29..36aaa3d39d3af 100644 --- a/src/test/librbd/operation/test_mock_ResizeRequest.cc +++ b/src/test/librbd/operation/test_mock_ResizeRequest.cc @@ -129,12 +129,13 @@ class TestMockOperationResizeRequest : public TestMockFixture { } int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size, - uint64_t journal_op_tid, bool disable_journal) { + bool allow_shrink, uint64_t journal_op_tid, + bool disable_journal) { C_SaferCond cond_ctx; librbd::NoOpProgressContext prog_ctx; MockResizeRequest *req = new MockResizeRequest( - mock_image_ctx, &cond_ctx, new_size, prog_ctx, journal_op_tid, - disable_journal); + mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx, + journal_op_tid, disable_journal); { RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); req->send(); @@ -159,7 +160,7 @@ TEST_F(TestMockOperationResizeRequest, NoOpSuccess) { expect_append_op_event(mock_image_ctx, 0); expect_unblock_writes(mock_image_ctx); expect_commit_op_event(mock_image_ctx, 0); - ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, 0, false)); + ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, GrowSuccess) { @@ -182,7 +183,7 @@ TEST_F(TestMockOperationResizeRequest, GrowSuccess) { expect_update_header(mock_image_ctx, 0); expect_commit_op_event(mock_image_ctx, 0); expect_unblock_writes(mock_image_ctx); - ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2, 0, false)); + ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) { @@ -209,7 +210,25 @@ TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) { expect_commit_op_event(mock_image_ctx, 0); expect_shrink_object_map(mock_image_ctx); expect_unblock_writes(mock_image_ctx); - ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, 0, false)); + ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false)); +} + +TEST_F(TestMockOperationResizeRequest, ShrinkError) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + MockExclusiveLock mock_exclusive_lock; + MockJournal mock_journal; + MockObjectMap mock_object_map; + initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal, + mock_object_map); + + InSequence seq; + expect_block_writes(mock_image_ctx, -EINVAL); + expect_unblock_writes(mock_image_ctx); + + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, false, 0, false)); } TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) { @@ -226,7 +245,7 @@ TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) { InSequence seq; expect_block_writes(mock_image_ctx, -EINVAL); expect_unblock_writes(mock_image_ctx); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, TrimError) { @@ -248,7 +267,7 @@ TEST_F(TestMockOperationResizeRequest, TrimError) { MockTrimRequest mock_trim_request; expect_trim(mock_image_ctx, mock_trim_request, -EINVAL); expect_commit_op_event(mock_image_ctx, -EINVAL); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) { @@ -271,7 +290,7 @@ TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) { expect_trim(mock_image_ctx, mock_trim_request, 0); expect_invalidate_cache(mock_image_ctx, -EINVAL); expect_commit_op_event(mock_image_ctx, -EINVAL); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) { @@ -293,7 +312,7 @@ TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) { expect_block_writes(mock_image_ctx, -EINVAL); expect_unblock_writes(mock_image_ctx); expect_commit_op_event(mock_image_ctx, -EINVAL); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) { @@ -316,7 +335,7 @@ TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) { expect_update_header(mock_image_ctx, -EINVAL); expect_unblock_writes(mock_image_ctx); expect_commit_op_event(mock_image_ctx, -EINVAL); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, JournalAppendError) { @@ -336,7 +355,7 @@ TEST_F(TestMockOperationResizeRequest, JournalAppendError) { expect_block_writes(mock_image_ctx, 0); expect_append_op_event(mock_image_ctx, -EINVAL); expect_unblock_writes(mock_image_ctx); - ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, 0, false)); + ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false)); } TEST_F(TestMockOperationResizeRequest, JournalDisabled) { @@ -353,7 +372,7 @@ TEST_F(TestMockOperationResizeRequest, JournalDisabled) { InSequence seq; expect_block_writes(mock_image_ctx, 0); expect_unblock_writes(mock_image_ctx); - ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, 0, true)); + ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, true)); } } // namespace operation diff --git a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc index 617333676e6f9..a1bfb6629782c 100644 --- a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc +++ b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc @@ -32,8 +32,9 @@ struct ResizeRequest { Context *on_finish = nullptr; static ResizeRequest* create(MockOperationImageCtx &image_ctx, Context *on_finish, - uint64_t new_size, ProgressContext &prog_ctx, - uint64_t journal_op_tid, bool disable_journal) { + uint64_t new_size, bool allow_shrink, + ProgressContext &prog_ctx, uint64_t journal_op_tid, + bool disable_journal) { assert(s_instance != nullptr); assert(journal_op_tid == 0); assert(disable_journal); diff --git a/src/test/librbd/test_ImageWatcher.cc b/src/test/librbd/test_ImageWatcher.cc index a698e33b10e54..f51595a66d32d 100644 --- a/src/test/librbd/test_ImageWatcher.cc +++ b/src/test/librbd/test_ImageWatcher.cc @@ -274,7 +274,7 @@ struct ResizeTask { void operator()() { RWLock::RLocker l(ictx->owner_lock); C_SaferCond ctx; - ictx->image_watcher->notify_resize(0, 0, *progress_context, &ctx); + ictx->image_watcher->notify_resize(0, 0, true, *progress_context, &ctx); result = ctx.wait(); } }; diff --git a/src/test/librbd/test_internal.cc b/src/test/librbd/test_internal.cc index 580d6125b8970..c5f6118433eb9 100644 --- a/src/test/librbd/test_internal.cc +++ b/src/test/librbd/test_internal.cc @@ -113,7 +113,7 @@ TEST_F(TestInternal, ResizeLocksImage) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); librbd::NoOpProgressContext no_op; - ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, no_op)); + ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, true, no_op)); bool is_owner; ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner)); @@ -128,7 +128,7 @@ TEST_F(TestInternal, ResizeFailsToLockImage) { ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked")); librbd::NoOpProgressContext no_op; - ASSERT_EQ(-EROFS, ictx->operations->resize(m_image_size >> 1, no_op)); + ASSERT_EQ(-EROFS, ictx->operations->resize(m_image_size >> 1, true, no_op)); } TEST_F(TestInternal, SnapCreateLocksImage) { @@ -336,7 +336,7 @@ TEST_F(TestInternal, CancelAsyncResize) { size -= MIN(size, 1<<18); { RWLock::RLocker l(ictx->owner_lock); - ictx->operations->execute_resize(size, prog_ctx, &ctx, 0); + ictx->operations->execute_resize(size, true, prog_ctx, &ctx, 0); } // try to interrupt the in-progress resize @@ -384,7 +384,7 @@ TEST_F(TestInternal, MultipleResize) { RWLock::RLocker l(ictx->owner_lock); contexts.push_back(new C_SaferCond()); - ictx->operations->execute_resize(new_size, prog_ctx, contexts.back(), 0); + ictx->operations->execute_resize(new_size, true, prog_ctx, contexts.back(), 0); } for (uint32_t i = 0; i < contexts.size(); ++i) { @@ -610,9 +610,9 @@ TEST_F(TestInternal, ResizeCopyup) // verify full / partial object removal properly copyup librbd::NoOpProgressContext no_op; ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (1 << order) - 32, - no_op)); + true, no_op)); ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (2 << order) - 32, - no_op)); + true, no_op)); ASSERT_EQ(0, librbd::snap_set(ictx2, "snap1")); { @@ -699,7 +699,7 @@ TEST_F(TestInternal, ShrinkFlushesCache) { ictx->aio_work_queue->aio_write(c, 0, buffer.size(), buffer.c_str(), 0); librbd::NoOpProgressContext no_op; - ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, no_op)); + ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, true, no_op)); ASSERT_TRUE(c->is_complete()); ASSERT_EQ(0, c->wait_for_complete()); @@ -781,7 +781,7 @@ TEST_F(TestInternal, WriteFullCopyup) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); librbd::NoOpProgressContext no_op; - ASSERT_EQ(0, ictx->operations->resize(1 << ictx->order, no_op)); + ASSERT_EQ(0, ictx->operations->resize(1 << ictx->order, true, no_op)); bufferlist bl; bl.append(std::string(1 << ictx->order, '1')); diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index d4dce59ca3bb5..5f29dcb296132 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -420,6 +420,16 @@ TEST_F(TestLibRBD, ResizeAndStat) ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); ASSERT_EQ(info.size, size / 2); + // downsizing without allowing shrink should fail + // and image size should not change + ASSERT_EQ(-EINVAL, rbd_resize2(image, size / 4, false, NULL, NULL)); + ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); + ASSERT_EQ(info.size, size / 2); + + ASSERT_EQ(0, rbd_resize2(image, size / 4, true, NULL, NULL)); + ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); + ASSERT_EQ(info.size, size / 4); + ASSERT_PASSED(validate_object_map, image); ASSERT_EQ(0, rbd_close(image)); diff --git a/src/test/rbd_mirror/test_ImageSync.cc b/src/test/rbd_mirror/test_ImageSync.cc index 922d499331740..eb93e6d7e2de2 100644 --- a/src/test/rbd_mirror/test_ImageSync.cc +++ b/src/test/rbd_mirror/test_ImageSync.cc @@ -144,7 +144,7 @@ TEST_F(TestImageSync, SnapshotStress) { librbd::NoOpProgressContext no_op_progress_ctx; uint64_t size = 1 + rand() % m_image_size; - ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, + ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true, no_op_progress_ctx)); ASSERT_EQ(0, m_remote_image_ctx->state->refresh()); diff --git a/src/tools/rbd/action/Resize.cc b/src/tools/rbd/action/Resize.cc index 9904427428601..f1e64a7bb12c8 100644 --- a/src/tools/rbd/action/Resize.cc +++ b/src/tools/rbd/action/Resize.cc @@ -15,10 +15,10 @@ namespace resize { namespace at = argument_types; namespace po = boost::program_options; -static int do_resize(librbd::Image& image, uint64_t size, bool no_progress) +static int do_resize(librbd::Image& image, uint64_t size, bool allow_shrink, bool no_progress) { utils::ProgressContext pc("Resizing image", no_progress); - int r = image.resize_with_progress(size, pc); + int r = image.resize2(size, allow_shrink, pc); if (r < 0) { pc.fail(); return r; @@ -70,14 +70,13 @@ int execute(const po::variables_map &vm) { return r; } - if (info.size > size && !vm["allow-shrink"].as()) { - std::cerr << "rbd: shrinking an image is only allowed with the " - << "--allow-shrink flag" << std::endl; - return -EINVAL; - } - - r = do_resize(image, size, vm[at::NO_PROGRESS].as()); + r = do_resize(image, size, vm["allow-shrink"].as(), vm[at::NO_PROGRESS].as()); if (r < 0) { + if (r == -EINVAL && !vm["allow-shrink"].as()) { + std::cerr << "rbd: shrinking an image is only allowed with the " + << "--allow-shrink flag" << std::endl; + return r; + } std::cerr << "rbd: resize error: " << cpp_strerror(r) << std::endl; return r; }