mirror of
https://github.com/ceph/ceph
synced 2025-03-11 02:39:05 +00:00
rbd: add rbd_resize2 for allow_shrink option
This commit is contained in:
parent
e489cd4f07
commit
d1f2c557b2
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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")));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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'));
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user