Skip to content

Commit 479014e

Browse files
committed
librbd/api/Mirror: return EINVAL from image_get_mode()
... when the image is disabled for mirroring. When an image is disabled for mirroring, fetching the image's mirroring mode is invalid. So, modify the Mirror::image_get_mode() internal API to return EINVAL instead of success when mirroring is disabled. The Mirror::image_get_mode() method is called by the public C++, C, and Python APIs that fetch the mirroring mode of an image. The behavior of these public APIs will change. They will return an error code or raise an exception indicating that it's an invalid operation to fetch the image's mirroring mode when mirroring is disabled. Fixes: https://tracker.ceph.com/issues/71226 Signed-off-by: Ramana Raja <[email protected]>
1 parent 268966a commit 479014e

File tree

5 files changed

+92
-23
lines changed

5 files changed

+92
-23
lines changed

PendingReleaseNotes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@
155155
Related trackers:
156156
- https://tracker.ceph.com/issues/67777
157157

158+
* RBD: Fetching the mirroring mode of an image is invalid if the image is
159+
disabled for mirroring. The public APIs -- C++ `mirror_image_get_mode()`,
160+
C `rbd_mirror_image_get_mode()`, and Python `Image.mirror_image_get_mode()`
161+
-- will return EINVAL when mirroring is disabled.
162+
158163
>=19.2.1
159164

160165
* CephFS: Command `fs subvolume create` now allows tagging subvolumes through option

src/librbd/api/Mirror.cc

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -311,37 +311,29 @@ const char *pool_or_namespace(I *ictx) {
311311

312312
struct C_ImageGetInfo : public Context {
313313
mirror_image_info_t *mirror_image_info;
314-
mirror_image_mode_t *mirror_image_mode;
315314
Context *on_finish;
316315

317316
cls::rbd::MirrorImage mirror_image;
318317
mirror::PromotionState promotion_state = mirror::PROMOTION_STATE_PRIMARY;
319318
std::string primary_mirror_uuid;
320319

321-
C_ImageGetInfo(mirror_image_info_t *mirror_image_info,
322-
mirror_image_mode_t *mirror_image_mode, Context *on_finish)
323-
: mirror_image_info(mirror_image_info),
324-
mirror_image_mode(mirror_image_mode), on_finish(on_finish) {
320+
C_ImageGetInfo(mirror_image_info_t *mirror_image_info, Context *on_finish)
321+
: mirror_image_info(mirror_image_info), on_finish(on_finish) {
325322
}
326323

327324
void finish(int r) override {
325+
// Suppress ENOENT returned by GetInfoRequest when mirroring is
326+
// disabled -- mirror_image.state will indicate that anyway.
328327
if (r < 0 && r != -ENOENT) {
329328
on_finish->complete(r);
330329
return;
331330
}
332331

333-
if (mirror_image_info != nullptr) {
334-
mirror_image_info->global_id = mirror_image.global_image_id;
335-
mirror_image_info->state = static_cast<rbd_mirror_image_state_t>(
336-
mirror_image.state);
337-
mirror_image_info->primary = (
338-
promotion_state == mirror::PROMOTION_STATE_PRIMARY);
339-
}
340-
341-
if (mirror_image_mode != nullptr) {
342-
*mirror_image_mode =
343-
static_cast<rbd_mirror_image_mode_t>(mirror_image.mode);
344-
}
332+
mirror_image_info->global_id = mirror_image.global_image_id;
333+
mirror_image_info->state = static_cast<mirror_image_state_t>(
334+
mirror_image.state);
335+
mirror_image_info->primary = (
336+
promotion_state == mirror::PROMOTION_STATE_PRIMARY);
345337

346338
on_finish->complete(0);
347339
}
@@ -357,7 +349,7 @@ struct C_ImageGetGlobalStatus : public C_ImageGetInfo {
357349
const std::string &image_name,
358350
mirror_image_global_status_t *mirror_image_global_status,
359351
Context *on_finish)
360-
: C_ImageGetInfo(&mirror_image_global_status->info, nullptr, on_finish),
352+
: C_ImageGetInfo(&mirror_image_global_status->info, on_finish),
361353
image_name(image_name),
362354
mirror_image_global_status(mirror_image_global_status) {
363355
}
@@ -384,6 +376,36 @@ struct C_ImageGetGlobalStatus : public C_ImageGetInfo {
384376
}
385377
};
386378

379+
struct C_ImageGetMode : public Context {
380+
mirror_image_mode_t *mirror_image_mode;
381+
Context *on_finish;
382+
383+
cls::rbd::MirrorImage mirror_image;
384+
mirror::PromotionState promotion_state = mirror::PROMOTION_STATE_PRIMARY;
385+
std::string primary_mirror_uuid;
386+
387+
C_ImageGetMode(mirror_image_mode_t *mirror_image_mode, Context *on_finish)
388+
: mirror_image_mode(mirror_image_mode), on_finish(on_finish) {
389+
}
390+
391+
void finish(int r) override {
392+
// Suppress ENOENT returned by GetInfoRequest when mirroring is
393+
// disabled -- mirror_image.state will indicate that anyway.
394+
if (r < 0 && r != -ENOENT) {
395+
on_finish->complete(r);
396+
return;
397+
} else if (mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLED) {
398+
on_finish->complete(-EINVAL);
399+
return;
400+
}
401+
402+
*mirror_image_mode =
403+
static_cast<mirror_image_mode_t>(mirror_image.mode);
404+
405+
on_finish->complete(0);
406+
}
407+
};
408+
387409
template <typename I>
388410
struct C_ImageSnapshotCreate : public Context {
389411
I *ictx;
@@ -858,7 +880,7 @@ void Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
858880
return;
859881
}
860882

861-
auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
883+
auto ctx = new C_ImageGetInfo(mirror_image_info, on_finish);
862884
auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
863885
&ctx->promotion_state,
864886
&ctx->primary_mirror_uuid,
@@ -895,7 +917,7 @@ void Mirror<I>::image_get_info(librados::IoCtx& io_ctx,
895917
ldout(cct, 20) << "pool_id=" << io_ctx.get_id() << ", image_id=" << image_id
896918
<< dendl;
897919

898-
auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
920+
auto ctx = new C_ImageGetInfo(mirror_image_info, on_finish);
899921
auto req = mirror::GetInfoRequest<I>::create(io_ctx, op_work_queue, image_id,
900922
&ctx->mirror_image,
901923
&ctx->promotion_state,
@@ -924,7 +946,7 @@ void Mirror<I>::image_get_mode(I *ictx, mirror_image_mode_t *mode,
924946
CephContext *cct = ictx->cct;
925947
ldout(cct, 20) << "ictx=" << ictx << dendl;
926948

927-
auto ctx = new C_ImageGetInfo(nullptr, mode, on_finish);
949+
auto ctx = new C_ImageGetMode(mode, on_finish);
928950
auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
929951
&ctx->promotion_state,
930952
&ctx->primary_mirror_uuid, ctx);

src/test/librbd/test_librbd.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11338,6 +11338,13 @@ TEST_F(TestLibRBD, CreateWithMirrorEnabled) {
1133811338
librbd::Image parent_image;
1133911339
ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
1134011340

11341+
librbd::mirror_image_info_t mirror_image_info;
11342+
ASSERT_EQ(0, parent_image.mirror_image_get_info(&mirror_image_info,
11343+
sizeof(mirror_image_info)));
11344+
ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, mirror_image_info.state);
11345+
ASSERT_NE("", mirror_image_info.global_id);
11346+
ASSERT_EQ(true, mirror_image_info.primary);
11347+
1134111348
librbd::mirror_image_mode_t mirror_image_mode;
1134211349
ASSERT_EQ(0, parent_image.mirror_image_get_mode(&mirror_image_mode));
1134311350
ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
@@ -11358,6 +11365,14 @@ TEST_F(TestLibRBD, CreateWithMirrorEnabled) {
1135811365
ASSERT_EQ(0, child_image.mirror_image_disable(true));
1135911366
ASSERT_EQ(0, parent_image.mirror_image_disable(true));
1136011367
ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
11368+
11369+
ASSERT_EQ(0, parent_image.mirror_image_get_info(&mirror_image_info,
11370+
sizeof(mirror_image_info)));
11371+
ASSERT_EQ(RBD_MIRROR_IMAGE_DISABLED, mirror_image_info.state);
11372+
ASSERT_EQ("", mirror_image_info.global_id);
11373+
ASSERT_EQ(false, mirror_image_info.primary);
11374+
11375+
ASSERT_EQ(-EINVAL, parent_image.mirror_image_get_mode(&mirror_image_mode));
1136111376
}
1136211377

1136311378
TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {

src/test/librbd/test_mirroring.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ class TestMirroring : public TestFixture {
160160
ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
161161
ASSERT_EQ(mirror_state, mirror_image.state);
162162

163+
librbd::mirror_image_mode_t mirror_image_mode;
164+
ASSERT_EQ(mirror_state != RBD_MIRROR_IMAGE_DISABLED ? 0 : -EINVAL,
165+
image.mirror_image_get_mode(&mirror_image_mode));
166+
163167
librbd::mirror_image_global_status_t status;
164168
ASSERT_EQ(0, image.mirror_image_get_global_status(&status, sizeof(status)));
165169
librbd::mirror_image_site_status_t local_status;

src/test/pybind/test_rbd.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,6 +2678,7 @@ def test_mirror_image(self):
26782678
self.image.mirror_image_disable(True)
26792679
info = self.image.mirror_image_get_info()
26802680
self.check_info(info, '', RBD_MIRROR_IMAGE_DISABLED, False)
2681+
assert_raises(InvalidArgument, self.image.mirror_image_get_mode)
26812682

26822683
self.image.mirror_image_enable()
26832684
info = self.image.mirror_image_get_info()
@@ -2835,15 +2836,37 @@ def test_aio_mirror_image_create_snapshot(self):
28352836
peer_uuid = self.rbd.mirror_peer_add(ioctx, "cluster", "client")
28362837
self.rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE)
28372838
self.image.mirror_image_disable(False)
2838-
self.image.mirror_image_enable(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)
28392839

2840+
# this is a list so that the local cb() can modify it
2841+
info = [123]
2842+
def cb(_, _info):
2843+
info[0] = _info
2844+
2845+
comp = self.image.aio_mirror_image_get_info(cb)
2846+
comp.wait_for_complete_and_cb()
2847+
assert_not_equal(info[0], None)
2848+
eq(comp.get_return_value(), 0)
2849+
eq(sys.getrefcount(comp), 2)
2850+
info = info[0]
2851+
self.check_info(info, "", RBD_MIRROR_IMAGE_DISABLED, False)
2852+
2853+
mode = [123]
2854+
def cb(_, _mode):
2855+
mode[0] = _mode
2856+
2857+
comp = self.image.aio_mirror_image_get_mode(cb)
2858+
comp.wait_for_complete_and_cb()
2859+
eq(comp.get_return_value(), -errno.EINVAL)
2860+
eq(sys.getrefcount(comp), 2)
2861+
eq(mode[0], None)
2862+
2863+
self.image.mirror_image_enable(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)
28402864
snaps = list(self.image.list_snaps())
28412865
eq(1, len(snaps))
28422866
snap = snaps[0]
28432867
eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR)
28442868
eq(RBD_SNAP_MIRROR_STATE_PRIMARY, snap['mirror']['state'])
28452869

2846-
# this is a list so that the local cb() can modify it
28472870
info = [None]
28482871
def cb(_, _info):
28492872
info[0] = _info

0 commit comments

Comments
 (0)