1
0
mirror of https://github.com/ceph/ceph synced 2025-04-07 01:54:01 +00:00

rbd: add rbd_resize2 for allow_shrink option

This commit is contained in:
Vaibhav Bhembre 2016-06-21 20:17:25 -04:00
parent e489cd4f07
commit d1f2c557b2
23 changed files with 142 additions and 73 deletions

View 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_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_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_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, CEPH_RBD_API int rbd_resize_with_progress(rbd_image_t image, uint64_t size,
librbd_progress_fn_t cb, void *cbdata); librbd_progress_fn_t cb, void *cbdata);
CEPH_RBD_API int rbd_stat(rbd_image_t image, rbd_image_info_t *info, CEPH_RBD_API int rbd_stat(rbd_image_t image, rbd_image_info_t *info,

View File

@ -191,6 +191,7 @@ public:
int aio_close(RBD::AioCompletion *c); int aio_close(RBD::AioCompletion *c);
int resize(uint64_t size); 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 resize_with_progress(uint64_t size, ProgressContext& pctx);
int stat(image_info_t &info, size_t infosize); int stat(image_info_t &info, size_t infosize);
int parent_info(std::string *parent_poolname, std::string *parent_name, int parent_info(std::string *parent_poolname, std::string *parent_name,

View File

@ -213,7 +213,7 @@ void ImageWatcher::notify_flatten(uint64_t request_id,
} }
void ImageWatcher::notify_resize(uint64_t request_id, uint64_t size, void ImageWatcher::notify_resize(uint64_t request_id, uint64_t size,
ProgressContext &prog_ctx, bool allow_shrink, ProgressContext &prog_ctx,
Context *on_finish) { Context *on_finish) {
assert(m_image_ctx.owner_lock.is_locked()); assert(m_image_ctx.owner_lock.is_locked());
assert(m_image_ctx.exclusive_lock && 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); AsyncRequestId async_request_id(get_client_id(), request_id);
bufferlist bl; 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); 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) { if (new_request) {
ldout(m_image_ctx.cct, 10) << this << " remote resize request: " ldout(m_image_ctx.cct, 10) << this << " remote resize request: "
<< payload.async_request_id << " " << payload.async_request_id << " "
<< payload.size << dendl; << payload.size << " "
m_image_ctx.operations->execute_resize(payload.size, *prog_ctx, ctx, 0); << 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); ::encode(ResponseMessage(r), ack_ctx->out);

View File

@ -33,7 +33,7 @@ public:
void notify_flatten(uint64_t request_id, ProgressContext &prog_ctx, void notify_flatten(uint64_t request_id, ProgressContext &prog_ctx,
Context *on_finish); 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); ProgressContext &prog_ctx, Context *on_finish);
void notify_snap_create(const std::string &snap_name, 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, void notify_snap_rename(const snapid_t &src_snap_id,

View File

@ -558,7 +558,7 @@ void Operations<I>::execute_rename(const char *dstname, Context *on_finish) {
} }
template <typename I> 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; CephContext *cct = m_image_ctx.cct;
m_image_ctx.snap_lock.get_read(); 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; uint64_t request_id = ++m_async_request_seq;
r = invoke_async_request("resize", false, r = invoke_async_request("resize", false,
boost::bind(&Operations<I>::execute_resize, this, 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, boost::bind(&ImageWatcher::notify_resize,
m_image_ctx.image_watcher, request_id, 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); m_image_ctx.perfcounter->inc(l_librbd_resize);
ldout(cct, 2) << "resize finished" << dendl; ldout(cct, 2) << "resize finished" << dendl;
@ -592,7 +592,7 @@ int Operations<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
} }
template <typename I> 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, Context *on_finish,
uint64_t journal_op_tid) { uint64_t journal_op_tid) {
assert(m_image_ctx.owner_lock.is_locked()); 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(); m_image_ctx.snap_lock.put_read();
operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>( operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>(
m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, prog_ctx, m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, allow_shrink,
journal_op_tid, false); prog_ctx, journal_op_tid, false);
req->send(); req->send();
} }

View File

@ -39,8 +39,8 @@ public:
int rename(const char *dstname); int rename(const char *dstname);
void execute_rename(const char *dstname, Context *on_finish); void execute_rename(const char *dstname, Context *on_finish);
int resize(uint64_t size, ProgressContext& prog_ctx); int resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx);
void execute_resize(uint64_t size, ProgressContext &prog_ctx, void execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx,
Context *on_finish, uint64_t journal_op_tid); Context *on_finish, uint64_t journal_op_tid);
int snap_create(const char *snap_name); int snap_create(const char *snap_name);

View File

@ -207,17 +207,23 @@ void AsyncCompletePayload::dump(Formatter *f) const {
} }
void ResizePayload::encode(bufferlist &bl) const { void ResizePayload::encode(bufferlist &bl) const {
::encode(size, bl);
AsyncRequestPayloadBase::encode(bl); AsyncRequestPayloadBase::encode(bl);
::encode(size, bl);
::encode(allow_shrink, bl);
} }
void ResizePayload::decode(__u8 version, bufferlist::iterator &iter) { void ResizePayload::decode(__u8 version, bufferlist::iterator &iter) {
::decode(size, iter);
AsyncRequestPayloadBase::decode(version, iter); AsyncRequestPayloadBase::decode(version, iter);
::decode(size, iter);
if (version >= 4) {
::decode(allow_shrink, iter);
}
} }
void ResizePayload::dump(Formatter *f) const { void ResizePayload::dump(Formatter *f) const {
f->dump_unsigned("size", size); f->dump_unsigned("size", size);
f->dump_bool("allow_shrink", allow_shrink);
AsyncRequestPayloadBase::dump(f); AsyncRequestPayloadBase::dump(f);
} }
@ -275,7 +281,7 @@ bool NotifyMessage::check_for_refresh() const {
} }
void NotifyMessage::encode(bufferlist& bl) const { void NotifyMessage::encode(bufferlist& bl) const {
ENCODE_START(3, 1, bl); ENCODE_START(4, 1, bl);
boost::apply_visitor(EncodePayloadVisitor(bl), payload); boost::apply_visitor(EncodePayloadVisitor(bl), payload);
ENCODE_FINISH(bl); 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(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(AsyncCompletePayload(AsyncRequestId(ClientId(0, 1), 2), 3)));
o.push_back(new NotifyMessage(FlattenPayload(AsyncRequestId(ClientId(0, 1), 2)))); 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(SnapCreatePayload("foo")));
o.push_back(new NotifyMessage(SnapRemovePayload("foo"))); o.push_back(new NotifyMessage(SnapRemovePayload("foo")));
o.push_back(new NotifyMessage(SnapProtectPayload("foo"))); o.push_back(new NotifyMessage(SnapProtectPayload("foo")));

View File

@ -200,11 +200,12 @@ struct ResizePayload : public AsyncRequestPayloadBase {
static const NotifyOp NOTIFY_OP = NOTIFY_OP_RESIZE; static const NotifyOp NOTIFY_OP = NOTIFY_OP_RESIZE;
static const bool CHECK_FOR_REFRESH = true; static const bool CHECK_FOR_REFRESH = true;
ResizePayload() : size(0) {} ResizePayload() : size(0), allow_shrink(true) {}
ResizePayload(uint64_t size_, const AsyncRequestId &id) ResizePayload(uint64_t size_, bool allow_shrink_, const AsyncRequestId &id)
: AsyncRequestPayloadBase(id), size(size_) {} : AsyncRequestPayloadBase(id), size(size_), allow_shrink(allow_shrink_) {}
uint64_t size; uint64_t size;
bool allow_shrink;
void encode(bufferlist &bl) const; void encode(bufferlist &bl) const;
void decode(__u8 version, bufferlist::iterator &iter); void decode(__u8 version, bufferlist::iterator &iter);

View File

@ -76,7 +76,7 @@ struct ExecuteOp : public Context {
} }
void execute(const journal::ResizeEvent &_) { 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); on_op_complete, event.op_tid);
} }

View File

@ -615,7 +615,16 @@ namespace librbd {
ImageCtx *ictx = (ImageCtx *)ctx; ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
librbd::NoOpProgressContext prog_ctx; 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); tracepoint(librbd, resize_exit, r);
return r; return r;
} }
@ -624,7 +633,7 @@ namespace librbd {
{ {
ImageCtx *ictx = (ImageCtx *)ctx; ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); 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); tracepoint(librbd, resize_exit, r);
return 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; librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
librbd::NoOpProgressContext prog_ctx; 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); tracepoint(librbd, resize_exit, r);
return 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; librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size); tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
librbd::CProgressContext prog_ctx(cb, cbdata); 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); tracepoint(librbd, resize_exit, r);
return r; return r;
} }

View File

@ -25,11 +25,11 @@ using util::create_rados_safe_callback;
template <typename I> template <typename I>
ResizeRequest<I>::ResizeRequest(I &image_ctx, Context *on_finish, 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) uint64_t journal_op_tid, bool disable_journal)
: Request<I>(image_ctx, on_finish, journal_op_tid), : Request<I>(image_ctx, on_finish, journal_op_tid),
m_original_size(0), m_new_size(new_size), m_prog_ctx(prog_ctx), m_original_size(0), m_new_size(new_size), m_allow_shrink(allow_shrink),
m_new_parent_overlap(0), m_disable_journal(disable_journal), m_prog_ctx(prog_ctx), m_new_parent_overlap(0), m_disable_journal(disable_journal),
m_xlist_item(this) m_xlist_item(this)
{ {
} }
@ -114,12 +114,19 @@ Context *ResizeRequest<I>::handle_pre_block_writes(int *result) {
template <typename I> template <typename I>
Context *ResizeRequest<I>::send_append_op_event() { Context *ResizeRequest<I>::send_append_op_event() {
I &image_ctx = this->m_image_ctx; 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< if (m_disable_journal || !this->template append_op_event<
ResizeRequest<I>, &ResizeRequest<I>::handle_append_op_event>(this)) { ResizeRequest<I>, &ResizeRequest<I>::handle_append_op_event>(this)) {
return send_grow_object_map(); return send_grow_object_map();
} }
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << dendl; ldout(cct, 5) << this << " " << __func__ << dendl;
return nullptr; return nullptr;
} }

View File

@ -18,14 +18,15 @@ template <typename ImageCtxT = ImageCtx>
class ResizeRequest : public Request<ImageCtxT> { class ResizeRequest : public Request<ImageCtxT> {
public: public:
static ResizeRequest *create(ImageCtxT &image_ctx, Context *on_finish, static ResizeRequest *create(ImageCtxT &image_ctx, Context *on_finish,
uint64_t new_size, ProgressContext &prog_ctx, uint64_t new_size, bool allow_shrink,
uint64_t journal_op_tid, bool disable_journal) { ProgressContext &prog_ctx, uint64_t journal_op_tid,
return new ResizeRequest(image_ctx, on_finish, new_size, prog_ctx, bool disable_journal) {
return new ResizeRequest(image_ctx, on_finish, new_size, allow_shrink, prog_ctx,
journal_op_tid, disable_journal); journal_op_tid, disable_journal);
} }
ResizeRequest(ImageCtxT &image_ctx, Context *on_finish, uint64_t new_size, 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); bool disable_journal);
virtual ~ResizeRequest(); virtual ~ResizeRequest();
@ -106,6 +107,7 @@ private:
uint64_t m_original_size; uint64_t m_original_size;
uint64_t m_new_size; uint64_t m_new_size;
bool m_allow_shrink = true;
ProgressContext &m_prog_ctx; ProgressContext &m_prog_ctx;
uint64_t m_new_parent_overlap; uint64_t m_new_parent_overlap;
bool m_shrink_size_visible = false; bool m_shrink_size_visible = false;

View File

@ -137,7 +137,7 @@ void SnapshotRollbackRequest<I>::send_resize_image() {
SnapshotRollbackRequest<I>, SnapshotRollbackRequest<I>,
&SnapshotRollbackRequest<I>::handle_resize_image>(this); &SnapshotRollbackRequest<I>::handle_resize_image>(this);
ResizeRequest<I> *req = ResizeRequest<I>::create(image_ctx, ctx, m_snap_size, 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(); req->send();
} }

View File

@ -617,7 +617,7 @@ TEST_F(TestJournalReplay, Resize) {
// verify lock ordering constraints // verify lock ordering constraints
librbd::NoOpProgressContext no_op_progress; 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) { TEST_F(TestJournalReplay, Flatten) {

View File

@ -138,8 +138,8 @@ public:
void expect_resize(MockReplayImageCtx &mock_image_ctx, Context **on_finish, void expect_resize(MockReplayImageCtx &mock_image_ctx, Context **on_finish,
uint64_t size, uint64_t op_tid) { uint64_t size, uint64_t op_tid) {
EXPECT_CALL(*mock_image_ctx.operations, execute_resize(size, _, _, op_tid)) EXPECT_CALL(*mock_image_ctx.operations, execute_resize(size, _, _, _, op_tid))
.WillOnce(DoAll(SaveArg<2>(on_finish), .WillOnce(DoAll(SaveArg<3>(on_finish),
NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); NotifyInvoke(&m_invoke_lock, &m_invoke_cond)));
} }

View File

@ -18,8 +18,8 @@ struct MockOperations {
MOCK_METHOD2(execute_rebuild_object_map, void(ProgressContext &prog_ctx, MOCK_METHOD2(execute_rebuild_object_map, void(ProgressContext &prog_ctx,
Context *on_finish)); Context *on_finish));
MOCK_METHOD2(execute_rename, void(const char *dstname, 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, MOCK_METHOD5(execute_resize, void(uint64_t size, bool allow_shrink,
Context *on_finish, ProgressContext &prog_ctx, Context *on_finish,
uint64_t journal_op_tid)); uint64_t journal_op_tid));
MOCK_METHOD2(snap_create, void(const char *snap_name, Context *on_finish)); MOCK_METHOD2(snap_create, void(const char *snap_name, Context *on_finish));
MOCK_METHOD4(execute_snap_create, void(const char *snap_name, MOCK_METHOD4(execute_snap_create, void(const char *snap_name,

View File

@ -129,12 +129,13 @@ public:
} }
int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size, 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; C_SaferCond cond_ctx;
librbd::NoOpProgressContext prog_ctx; librbd::NoOpProgressContext prog_ctx;
MockResizeRequest *req = new MockResizeRequest( MockResizeRequest *req = new MockResizeRequest(
mock_image_ctx, &cond_ctx, new_size, prog_ctx, journal_op_tid, mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx,
disable_journal); journal_op_tid, disable_journal);
{ {
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
req->send(); req->send();
@ -159,7 +160,7 @@ TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
expect_append_op_event(mock_image_ctx, 0); expect_append_op_event(mock_image_ctx, 0);
expect_unblock_writes(mock_image_ctx); expect_unblock_writes(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, 0); 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) { TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
@ -182,7 +183,7 @@ TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
expect_update_header(mock_image_ctx, 0); expect_update_header(mock_image_ctx, 0);
expect_commit_op_event(mock_image_ctx, 0); expect_commit_op_event(mock_image_ctx, 0);
expect_unblock_writes(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, ShrinkSuccess) { TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
@ -209,7 +210,25 @@ TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
expect_commit_op_event(mock_image_ctx, 0); expect_commit_op_event(mock_image_ctx, 0);
expect_shrink_object_map(mock_image_ctx); expect_shrink_object_map(mock_image_ctx);
expect_unblock_writes(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) { TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
@ -226,7 +245,7 @@ TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
InSequence seq; InSequence seq;
expect_block_writes(mock_image_ctx, -EINVAL); expect_block_writes(mock_image_ctx, -EINVAL);
expect_unblock_writes(mock_image_ctx); 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) { TEST_F(TestMockOperationResizeRequest, TrimError) {
@ -248,7 +267,7 @@ TEST_F(TestMockOperationResizeRequest, TrimError) {
MockTrimRequest mock_trim_request; MockTrimRequest mock_trim_request;
expect_trim(mock_image_ctx, mock_trim_request, -EINVAL); expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
expect_commit_op_event(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, InvalidateCacheError) { TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
@ -271,7 +290,7 @@ TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
expect_trim(mock_image_ctx, mock_trim_request, 0); expect_trim(mock_image_ctx, mock_trim_request, 0);
expect_invalidate_cache(mock_image_ctx, -EINVAL); expect_invalidate_cache(mock_image_ctx, -EINVAL);
expect_commit_op_event(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) { TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
@ -293,7 +312,7 @@ TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
expect_block_writes(mock_image_ctx, -EINVAL); expect_block_writes(mock_image_ctx, -EINVAL);
expect_unblock_writes(mock_image_ctx); expect_unblock_writes(mock_image_ctx);
expect_commit_op_event(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, UpdateHeaderError) { TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
@ -316,7 +335,7 @@ TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
expect_update_header(mock_image_ctx, -EINVAL); expect_update_header(mock_image_ctx, -EINVAL);
expect_unblock_writes(mock_image_ctx); expect_unblock_writes(mock_image_ctx);
expect_commit_op_event(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, JournalAppendError) { TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
@ -336,7 +355,7 @@ TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
expect_block_writes(mock_image_ctx, 0); expect_block_writes(mock_image_ctx, 0);
expect_append_op_event(mock_image_ctx, -EINVAL); expect_append_op_event(mock_image_ctx, -EINVAL);
expect_unblock_writes(mock_image_ctx); 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) { TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
@ -353,7 +372,7 @@ TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
InSequence seq; InSequence seq;
expect_block_writes(mock_image_ctx, 0); expect_block_writes(mock_image_ctx, 0);
expect_unblock_writes(mock_image_ctx); 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 } // namespace operation

View File

@ -32,8 +32,9 @@ struct ResizeRequest<MockOperationImageCtx> {
Context *on_finish = nullptr; Context *on_finish = nullptr;
static ResizeRequest* create(MockOperationImageCtx &image_ctx, Context *on_finish, static ResizeRequest* create(MockOperationImageCtx &image_ctx, Context *on_finish,
uint64_t new_size, ProgressContext &prog_ctx, uint64_t new_size, bool allow_shrink,
uint64_t journal_op_tid, bool disable_journal) { ProgressContext &prog_ctx, uint64_t journal_op_tid,
bool disable_journal) {
assert(s_instance != nullptr); assert(s_instance != nullptr);
assert(journal_op_tid == 0); assert(journal_op_tid == 0);
assert(disable_journal); assert(disable_journal);

View File

@ -274,7 +274,7 @@ struct ResizeTask {
void operator()() { void operator()() {
RWLock::RLocker l(ictx->owner_lock); RWLock::RLocker l(ictx->owner_lock);
C_SaferCond ctx; 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(); result = ctx.wait();
} }
}; };

View File

@ -113,7 +113,7 @@ TEST_F(TestInternal, ResizeLocksImage) {
ASSERT_EQ(0, open_image(m_image_name, &ictx)); ASSERT_EQ(0, open_image(m_image_name, &ictx));
librbd::NoOpProgressContext no_op; 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; bool is_owner;
ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &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")); ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
librbd::NoOpProgressContext no_op; 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) { TEST_F(TestInternal, SnapCreateLocksImage) {
@ -336,7 +336,7 @@ TEST_F(TestInternal, CancelAsyncResize) {
size -= MIN(size, 1<<18); size -= MIN(size, 1<<18);
{ {
RWLock::RLocker l(ictx->owner_lock); 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 // try to interrupt the in-progress resize
@ -384,7 +384,7 @@ TEST_F(TestInternal, MultipleResize) {
RWLock::RLocker l(ictx->owner_lock); RWLock::RLocker l(ictx->owner_lock);
contexts.push_back(new C_SaferCond()); 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) { for (uint32_t i = 0; i < contexts.size(); ++i) {
@ -610,9 +610,9 @@ TEST_F(TestInternal, ResizeCopyup)
// verify full / partial object removal properly copyup // verify full / partial object removal properly copyup
librbd::NoOpProgressContext no_op; librbd::NoOpProgressContext no_op;
ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (1 << order) - 32, 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, 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")); 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); ictx->aio_work_queue->aio_write(c, 0, buffer.size(), buffer.c_str(), 0);
librbd::NoOpProgressContext no_op; 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_TRUE(c->is_complete());
ASSERT_EQ(0, c->wait_for_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)); ASSERT_EQ(0, open_image(m_image_name, &ictx));
librbd::NoOpProgressContext no_op; 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; bufferlist bl;
bl.append(std::string(1 << ictx->order, '1')); bl.append(std::string(1 << ictx->order, '1'));

View File

@ -420,6 +420,16 @@ TEST_F(TestLibRBD, ResizeAndStat)
ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
ASSERT_EQ(info.size, size / 2); 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_PASSED(validate_object_map, image);
ASSERT_EQ(0, rbd_close(image)); ASSERT_EQ(0, rbd_close(image));

View File

@ -144,7 +144,7 @@ TEST_F(TestImageSync, SnapshotStress) {
librbd::NoOpProgressContext no_op_progress_ctx; librbd::NoOpProgressContext no_op_progress_ctx;
uint64_t size = 1 + rand() % m_image_size; 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)); no_op_progress_ctx));
ASSERT_EQ(0, m_remote_image_ctx->state->refresh()); ASSERT_EQ(0, m_remote_image_ctx->state->refresh());

View File

@ -15,10 +15,10 @@ namespace resize {
namespace at = argument_types; namespace at = argument_types;
namespace po = boost::program_options; 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); 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) { if (r < 0) {
pc.fail(); pc.fail();
return r; return r;
@ -70,14 +70,13 @@ int execute(const po::variables_map &vm) {
return r; return r;
} }
if (info.size > size && !vm["allow-shrink"].as<bool>()) { r = do_resize(image, size, vm["allow-shrink"].as<bool>(), vm[at::NO_PROGRESS].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>());
if (r < 0) { 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; std::cerr << "rbd: resize error: " << cpp_strerror(r) << std::endl;
return r; return r;
} }