]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add rbd_resize2 for allow_shrink option 9878/head
authorVaibhav Bhembre <vaibhav@digitalocean.com>
Wed, 22 Jun 2016 00:17:25 +0000 (20:17 -0400)
committerVaibhav Bhembre <vaibhav@digitalocean.com>
Wed, 13 Jul 2016 19:50:04 +0000 (15:50 -0400)
23 files changed:
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/ImageWatcher.cc
src/librbd/ImageWatcher.h
src/librbd/Operations.cc
src/librbd/Operations.h
src/librbd/WatchNotifyTypes.cc
src/librbd/WatchNotifyTypes.h
src/librbd/journal/Replay.cc
src/librbd/librbd.cc
src/librbd/operation/ResizeRequest.cc
src/librbd/operation/ResizeRequest.h
src/librbd/operation/SnapshotRollbackRequest.cc
src/test/librbd/journal/test_Replay.cc
src/test/librbd/journal/test_mock_Replay.cc
src/test/librbd/mock/MockOperations.h
src/test/librbd/operation/test_mock_ResizeRequest.cc
src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc
src/test/librbd/test_ImageWatcher.cc
src/test/librbd/test_internal.cc
src/test/librbd/test_librbd.cc
src/test/rbd_mirror/test_ImageSync.cc
src/tools/rbd/action/Resize.cc

index 9c09547e954cb4a72a5a622e99d1ed101c503258..2147205ab2b41ee12551ff3891269d956dbdf7a5 100644 (file)
@@ -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,
index 6b2026d4e81f5e4992f1796a7d454a0e1e5b6741..982eb55b30b8edc2d1589461f4fdd905f44130a6 100644 (file)
@@ -191,6 +191,7 @@ public:
   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,
index ffe951904a9c8ba4b24c4a13aa924114fc6f55c8..1dfe6681e7dd06a1fe4369d17b61d4ad6124d944 100644 (file)
@@ -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);
index 5182a972772d314d51271b1656d46598cde8c471..0799cb8190416c9fd6c8ae8ec5c2b9071b0d943c 100644 (file)
@@ -33,7 +33,7 @@ public:
 
   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,
index a7fd659bb1c84806999bd21700fab5eed8f87cb1..48197d42e263b6eb31e117f68895d52717b27d53 100644 (file)
@@ -558,7 +558,7 @@ void Operations<I>::execute_rename(const char *dstname, Context *on_finish) {
 }
 
 template <typename I>
-int Operations<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
+int Operations<I>::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<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
   uint64_t request_id = ++m_async_request_seq;
   r = invoke_async_request("resize", false,
                            boost::bind(&Operations<I>::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<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
 }
 
 template <typename I>
-void Operations<I>::execute_resize(uint64_t size, ProgressContext &prog_ctx,
+void Operations<I>::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<I>::execute_resize(uint64_t size, ProgressContext &prog_ctx,
   m_image_ctx.snap_lock.put_read();
 
   operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>(
-    m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, prog_ctx,
-    journal_op_tid, false);
+    m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, allow_shrink,
+    prog_ctx, journal_op_tid, false);
   req->send();
 }
 
index b9e8615e4866b6fe4a6f50d097a855c09ec831dd..f0ae5a1e6582317f8ffb6888d9fed3bd86c3cbe9 100644 (file)
@@ -39,8 +39,8 @@ public:
   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);
index 65c334ae855f1639fcab845626e847c6fb854ede..949cce2695a2231544efc1fb263b94471f0586b7 100644 (file)
@@ -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<NotifyMessage *> &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")));
index f5ec6210e2228b902c38690081cc45813606c6bb..a7bae5310dbf58488cd1e421c219a0bad2389acb 100644 (file)
@@ -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);
index 6143f21889465ae954cce1664c37ba34e78bd4cd..9ee245e2d7462ffd3aa5858617da0f7866a70f11 100644 (file)
@@ -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);
   }
 
index 052822f03e5c203550bb4f216edfbf2a6e3e7ee8..f0ef3764db86419fa35461c7a30ca24f68bf24d9 100644 (file)
@@ -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;
 }
index f7e5ba33a2d6108f90a1d98f1aee26cf460828db..0aef072c8f9b861c14e5397334f652fae0157109 100644 (file)
@@ -25,11 +25,11 @@ using util::create_rados_safe_callback;
 
 template <typename I>
 ResizeRequest<I>::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<I>(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<I>::handle_pre_block_writes(int *result) {
 template <typename I>
 Context *ResizeRequest<I>::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<I>, &ResizeRequest<I>::handle_append_op_event>(this)) {
     return send_grow_object_map();
   }
 
-  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   return nullptr;
 }
index bd5019f80475e7eefe65b5b0db189c7510cf12de..069718e0889e6a8aba58e1446440cd1fb8f8717a 100644 (file)
@@ -18,14 +18,15 @@ template <typename ImageCtxT = ImageCtx>
 class ResizeRequest : public Request<ImageCtxT> {
 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 @@ private:
 
   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;
index 6dcf3a71083506b29f1eeb2c8d403c6d5bc9b187..0ab5f34d330f7abcd62759002f5d9eeb69862662 100644 (file)
@@ -137,7 +137,7 @@ void SnapshotRollbackRequest<I>::send_resize_image() {
     SnapshotRollbackRequest<I>,
     &SnapshotRollbackRequest<I>::handle_resize_image>(this);
   ResizeRequest<I> *req = ResizeRequest<I>::create(image_ctx, ctx, m_snap_size,
-                                                   m_no_op_prog_ctx, 0, true);
+                                                   true, m_no_op_prog_ctx, 0, true);
   req->send();
 }
 
index cbde9ae72bdf66aa813e74347308ed6043a4dba5..b0acb69c0c5288fd7a47d6484fdb095ccb9b86ec 100644 (file)
@@ -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) {
index 8a9c86941d8b24f8776c13551f6e576a6f6ab1c2..c2d7982f51d35df5a8517f336b9a8e6997ff6719 100644 (file)
@@ -138,8 +138,8 @@ public:
 
   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)));
   }
 
index 5d4e2221e537dab29beac544f75d80e5ebf1a3ea..6d2ab21fd6a23f297fe6f1cf21cd5c77b828c6a2 100644 (file)
@@ -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,
index 34b0debde8b29ab0b4b8380e858232ba2190ae42..36aaa3d39d3afac5f8998a4d9efdab3432a7b4ec 100644 (file)
@@ -129,12 +129,13 @@ public:
   }
 
   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
index 617333676e6f9672188e417caa9876f1782fa22b..a1bfb6629782c78e4f666631d562fd4176085528 100644 (file)
@@ -32,8 +32,9 @@ struct ResizeRequest<MockOperationImageCtx> {
   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);
index a698e33b10e54e51ca0745ce246266b20837b4c3..f51595a66d32df9b0fbf00b57dcdbc7d2ae396b4 100644 (file)
@@ -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();
   }
 };
index 580d6125b8970b51189c8a209e93b69f8d8be3de..c5f6118433eb98f84d54a58d7636a1a8fc7ff1c8 100644 (file)
@@ -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'));
index d4dce59ca3bb5e4145c6550ba018055d82fc2a7c..5f29dcb29613272debdba91df30f0a214307192c 100644 (file)
@@ -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));
 
index 922d49933174019cc94ed4b46235c370df303264..eb93e6d7e2de2687b73f68cc6b49077cf15e1247 100644 (file)
@@ -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());
 
index 99044274286018b9984b0111ea728dbd95a0ddcf..f1e64a7bb12c85b3a9353b9ded3afebdbc3eb8eb 100644 (file)
@@ -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<bool>()) {
-    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<bool>());
+  r = do_resize(image, size, vm["allow-shrink"].as<bool>(), vm[at::NO_PROGRESS].as<bool>());
   if (r < 0) {
+    if (r == -EINVAL && !vm["allow-shrink"].as<bool>()) {
+      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;
   }