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,
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,
}
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 &&
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);
}
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);
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,
}
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();
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;
}
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());
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();
}
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);
}
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);
}
}
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);
}
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")));
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);
}
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);
}
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;
}
{
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;
}
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;
}
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;
}
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)
{
}
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;
}
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();
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;
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();
}
// 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) {
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)));
}
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,
}
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();
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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
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);
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();
}
};
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));
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) {
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
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) {
// 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"));
{
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());
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'));
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));
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());
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;
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;
}