Skip to content

Commit db2a4a6

Browse files
authored
Merge pull request ceph#63149 from ajarr/wip-ajarr-fix-mirror-image-get-mode
librbd/api/Mirror: return EINVAL from image_get_mode() when the image is disabled for mirroring Reviewed-by: Ilya Dryomov <[email protected]> Reviewed-by: Afreen Misbah <[email protected]>
2 parents 18e473b + 0a70511 commit db2a4a6

File tree

11 files changed

+184
-81
lines changed

11 files changed

+184
-81
lines changed

PendingReleaseNotes

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,21 @@
156156
Related trackers:
157157
- https://tracker.ceph.com/issues/67777
158158

159+
* RBD: Fetching the mirroring mode of an image is invalid if the image is
160+
disabled for mirroring. The public APIs -- C++ `mirror_image_get_mode()`,
161+
C `rbd_mirror_image_get_mode()`, and Python `Image.mirror_image_get_mode()`
162+
-- will return EINVAL when mirroring is disabled.
163+
164+
* RBD: Promoting an image is invalid if the image is not enabled for mirroring.
165+
The public APIs -- C++ `mirror_image_promote()`,
166+
C `rbd_mirror_image_promote()`, and Python `Image.mirror_image_promote()` --
167+
will return EINVAL instead of ENOENT when mirroring is not enabled.
168+
169+
* RBD: Requesting a resync on an image is invalid if the image is not enabled
170+
for mirroring. The public APIs -- C++ `mirror_image_resync()`,
171+
C `rbd_mirror_image_resync()`, and Python `Image.mirror_image_resync()` --
172+
will return EINVAL instead of ENOENT when mirroring is not enabled.
173+
159174
>=19.2.1
160175

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

src/librbd/api/Mirror.cc

Lines changed: 50 additions & 25 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;
@@ -793,11 +815,14 @@ int Mirror<I>::image_resync(I *ictx) {
793815
req->send();
794816

795817
r = get_info_ctx.wait();
796-
if (r < 0) {
818+
if (r < 0 && r != -ENOENT) {
819+
lderr(cct) << "failed to retrieve mirroring state, cannot resync: "
820+
<< cpp_strerror(r) << dendl;
797821
return r;
798-
}
799-
800-
if (promotion_state == mirror::PROMOTION_STATE_PRIMARY) {
822+
} else if (mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
823+
lderr(cct) << "mirroring is not enabled, cannot resync" << dendl;
824+
return -EINVAL;
825+
} else if (promotion_state == mirror::PROMOTION_STATE_PRIMARY) {
801826
lderr(cct) << "image is primary, cannot resync to itself" << dendl;
802827
return -EINVAL;
803828
}
@@ -858,7 +883,7 @@ void Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
858883
return;
859884
}
860885

861-
auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
886+
auto ctx = new C_ImageGetInfo(mirror_image_info, on_finish);
862887
auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
863888
&ctx->promotion_state,
864889
&ctx->primary_mirror_uuid,
@@ -895,7 +920,7 @@ void Mirror<I>::image_get_info(librados::IoCtx& io_ctx,
895920
ldout(cct, 20) << "pool_id=" << io_ctx.get_id() << ", image_id=" << image_id
896921
<< dendl;
897922

898-
auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
923+
auto ctx = new C_ImageGetInfo(mirror_image_info, on_finish);
899924
auto req = mirror::GetInfoRequest<I>::create(io_ctx, op_work_queue, image_id,
900925
&ctx->mirror_image,
901926
&ctx->promotion_state,
@@ -924,7 +949,7 @@ void Mirror<I>::image_get_mode(I *ictx, mirror_image_mode_t *mode,
924949
CephContext *cct = ictx->cct;
925950
ldout(cct, 20) << "ictx=" << ictx << dendl;
926951

927-
auto ctx = new C_ImageGetInfo(nullptr, mode, on_finish);
952+
auto ctx = new C_ImageGetMode(mode, on_finish);
928953
auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
929954
&ctx->promotion_state,
930955
&ctx->primary_mirror_uuid, ctx);

src/librbd/mirror/PromoteRequest.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void PromoteRequest<I>::handle_get_info(int r) {
4545
CephContext *cct = m_image_ctx.cct;
4646
ldout(cct, 20) << "r=" << r << dendl;
4747

48-
if (r < 0) {
48+
if (r < 0 && r != -ENOENT) {
4949
lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r)
5050
<< dendl;
5151
finish(r);

src/pybind/mgr/dashboard/controllers/rbd.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,11 @@ def create(self, image_spec, snapshot_name, mirrorImageSnapshot):
235235

236236
def _create_snapshot(ioctx, img, snapshot_name):
237237
mirror_info = img.mirror_image_get_info()
238-
mirror_mode = img.mirror_image_get_mode()
239-
if (mirror_info['state'] == rbd.RBD_MIRROR_IMAGE_ENABLED and mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT) and mirrorImageSnapshot: # noqa E501 #pylint: disable=line-too-long
238+
mirror_mode = None
239+
if mirror_info['state'] == rbd.RBD_MIRROR_IMAGE_ENABLED:
240+
mirror_mode = img.mirror_image_get_mode()
241+
242+
if (mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT) and mirrorImageSnapshot:
240243
img.mirror_image_create_snapshot()
241244
else:
242245
img.create_snap(snapshot_name)

src/pybind/mgr/dashboard/controllers/rbd_mirroring.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,14 @@ class ReplayingData(NamedTuple):
241241

242242
def _get_mirror_mode(ioctx, image_name):
243243
with rbd.Image(ioctx, image_name) as img:
244-
mirror_mode = img.mirror_image_get_mode()
244+
mirror_mode = None
245245
mirror_mode_str = 'Disabled'
246+
try:
247+
mirror_mode = img.mirror_image_get_mode()
248+
except rbd.InvalidArgument:
249+
# Suppress exception raised when mirroring is disabled
250+
pass
251+
246252
if mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_JOURNAL:
247253
mirror_mode_str = 'journal'
248254
elif mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT:

src/pybind/mgr/dashboard/services/rbd.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,13 @@ def _rbd_image(cls, ioctx, pool_name, namespace, image_name, # pylint: disable=
305305
with rbd.Image(ioctx, image_name) as img:
306306
stat = img.stat()
307307
mirror_info = img.mirror_image_get_info()
308-
mirror_mode = img.mirror_image_get_mode()
309-
if mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_JOURNAL and mirror_info['state'] != rbd.RBD_MIRROR_IMAGE_DISABLED: # noqa E501 #pylint: disable=line-too-long
308+
mirror_mode = None
309+
if mirror_info['state'] != rbd.RBD_MIRROR_IMAGE_DISABLED:
310+
mirror_mode = img.mirror_image_get_mode()
311+
else:
312+
stat['mirror_mode'] = 'Disabled'
313+
314+
if mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_JOURNAL:
310315
stat['mirror_mode'] = 'journal'
311316
elif mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT:
312317
stat['mirror_mode'] = 'snapshot'
@@ -315,8 +320,6 @@ def _rbd_image(cls, ioctx, pool_name, namespace, image_name, # pylint: disable=
315320
for scheduled_image in schedule_status['scheduled_images']:
316321
if scheduled_image['image'] == get_image_spec(pool_name, namespace, image_name):
317322
stat['schedule_info'] = scheduled_image
318-
else:
319-
stat['mirror_mode'] = 'Disabled'
320323

321324
stat['name'] = image_name
322325

@@ -364,10 +367,8 @@ def _rbd_image(cls, ioctx, pool_name, namespace, image_name, # pylint: disable=
364367
if snap['namespace'] == rbd.RBD_SNAP_NAMESPACE_TYPE_TRASH:
365368
continue
366369

367-
try:
368-
snap['mirror_mode'] = MIRROR_IMAGE_MODE(img.mirror_image_get_mode()).name
369-
except ValueError as ex:
370-
raise DashboardException(f'Unknown RBD Mirror mode: {ex}')
370+
if mirror_mode:
371+
snap['mirror_mode'] = mirror_mode
371372

372373
snap['timestamp'] = "{}Z".format(
373374
img.get_snap_timestamp(snap['id']).isoformat())

src/pybind/mgr/rbd_support/mirror_snapshot_schedule.py

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -113,95 +113,101 @@ def handle_open_image(self,
113113
self.finish(image_spec)
114114
return
115115

116-
self.get_mirror_mode(image_spec, image)
116+
self.get_mirror_info(image_spec, image)
117117

118-
def get_mirror_mode(self, image_spec: ImageSpec, image: rbd.Image) -> None:
118+
def get_mirror_info(self, image_spec: ImageSpec, image: rbd.Image) -> None:
119119
pool_id, namespace, image_id = image_spec
120120

121-
self.log.debug("CreateSnapshotRequests.get_mirror_mode: {}/{}/{}".format(
121+
self.log.debug("CreateSnapshotRequests.get_mirror_info: {}/{}/{}".format(
122122
pool_id, namespace, image_id))
123123

124-
def cb(comp: rados.Completion, mode: Optional[int]) -> None:
125-
self.handle_get_mirror_mode(image_spec, image, comp, mode)
124+
def cb(comp: rados.Completion, info: Optional[Dict[str, Union[str, int]]]) -> None:
125+
self.handle_get_mirror_info(image_spec, image, comp, info)
126126

127127
try:
128-
image.aio_mirror_image_get_mode(cb)
128+
image.aio_mirror_image_get_info(cb)
129129
except Exception as e:
130130
self.log.error(
131-
"exception when getting mirror mode for {}/{}/{}: {}".format(
131+
"exception when getting mirror info for {}/{}/{}: {}".format(
132132
pool_id, namespace, image_id, e))
133133
self.close_image(image_spec, image)
134134

135-
def handle_get_mirror_mode(self,
135+
def handle_get_mirror_info(self,
136136
image_spec: ImageSpec,
137137
image: rbd.Image,
138138
comp: rados.Completion,
139-
mode: Optional[int]) -> None:
139+
info: Optional[Dict[str, Union[str, int]]]) -> None:
140140
pool_id, namespace, image_id = image_spec
141141

142142
self.log.debug(
143-
"CreateSnapshotRequests.handle_get_mirror_mode {}/{}/{}: r={} mode={}".format(
144-
pool_id, namespace, image_id, comp.get_return_value(), mode))
143+
"CreateSnapshotRequests.handle_get_mirror_info {}/{}/{}: r={} info={}".format(
144+
pool_id, namespace, image_id, comp.get_return_value(), info))
145145

146-
if mode is None:
147-
if comp.get_return_value() != -errno.ENOENT:
148-
self.log.error(
149-
"error when getting mirror mode for {}/{}/{}: {}".format(
150-
pool_id, namespace, image_id, comp.get_return_value()))
146+
if info is None:
147+
self.log.error(
148+
"error when getting mirror info for {}/{}/{}: {}".format(
149+
pool_id, namespace, image_id, comp.get_return_value()))
151150
self.close_image(image_spec, image)
152151
return
153152

154-
if mode != rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT:
153+
if info['state'] != rbd.RBD_MIRROR_IMAGE_ENABLED:
155154
self.log.debug(
156-
"CreateSnapshotRequests.handle_get_mirror_mode: {}/{}/{}: {}".format(
155+
"CreateSnapshotRequests.handle_get_mirror_info: {}/{}/{}: {}".format(
157156
pool_id, namespace, image_id,
158-
"snapshot mirroring is not enabled"))
157+
"mirroring is not enabled"))
159158
self.close_image(image_spec, image)
160159
return
161160

162-
self.get_mirror_info(image_spec, image)
161+
if not info['primary']:
162+
self.log.debug(
163+
"CreateSnapshotRequests.handle_get_mirror_info: {}/{}/{}: {}".format(
164+
pool_id, namespace, image_id,
165+
"is not primary"))
166+
self.close_image(image_spec, image)
167+
return
163168

164-
def get_mirror_info(self, image_spec: ImageSpec, image: rbd.Image) -> None:
169+
self.get_mirror_mode(image_spec, image)
170+
171+
def get_mirror_mode(self, image_spec: ImageSpec, image: rbd.Image) -> None:
165172
pool_id, namespace, image_id = image_spec
166173

167-
self.log.debug("CreateSnapshotRequests.get_mirror_info: {}/{}/{}".format(
174+
self.log.debug("CreateSnapshotRequests.get_mirror_mode: {}/{}/{}".format(
168175
pool_id, namespace, image_id))
169176

170-
def cb(comp: rados.Completion, info: Optional[Dict[str, Union[str, int]]]) -> None:
171-
self.handle_get_mirror_info(image_spec, image, comp, info)
177+
def cb(comp: rados.Completion, mode: Optional[int]) -> None:
178+
self.handle_get_mirror_mode(image_spec, image, comp, mode)
172179

173180
try:
174-
image.aio_mirror_image_get_info(cb)
181+
image.aio_mirror_image_get_mode(cb)
175182
except Exception as e:
176183
self.log.error(
177-
"exception when getting mirror info for {}/{}/{}: {}".format(
184+
"exception when getting mirror mode for {}/{}/{}: {}".format(
178185
pool_id, namespace, image_id, e))
179186
self.close_image(image_spec, image)
180187

181-
def handle_get_mirror_info(self,
188+
def handle_get_mirror_mode(self,
182189
image_spec: ImageSpec,
183190
image: rbd.Image,
184191
comp: rados.Completion,
185-
info: Optional[Dict[str, Union[str, int]]]) -> None:
192+
mode: Optional[int]) -> None:
186193
pool_id, namespace, image_id = image_spec
187194

188195
self.log.debug(
189-
"CreateSnapshotRequests.handle_get_mirror_info {}/{}/{}: r={} info={}".format(
190-
pool_id, namespace, image_id, comp.get_return_value(), info))
196+
"CreateSnapshotRequests.handle_get_mirror_mode {}/{}/{}: r={} mode={}".format(
197+
pool_id, namespace, image_id, comp.get_return_value(), mode))
191198

192-
if info is None:
193-
if comp.get_return_value() != -errno.ENOENT:
194-
self.log.error(
195-
"error when getting mirror info for {}/{}/{}: {}".format(
196-
pool_id, namespace, image_id, comp.get_return_value()))
199+
if mode is None:
200+
self.log.error(
201+
"error when getting mirror mode for {}/{}/{}: {}".format(
202+
pool_id, namespace, image_id, comp.get_return_value()))
197203
self.close_image(image_spec, image)
198204
return
199205

200-
if not info['primary']:
206+
if mode != rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT:
201207
self.log.debug(
202-
"CreateSnapshotRequests.handle_get_mirror_info: {}/{}/{}: {}".format(
208+
"CreateSnapshotRequests.handle_get_mirror_mode: {}/{}/{}: {}".format(
203209
pool_id, namespace, image_id,
204-
"is not primary"))
210+
"not enabled for snapshot mirroring"))
205211
self.close_image(image_spec, image)
206212
return
207213

0 commit comments

Comments
 (0)