Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librbd: deferred image deletion #13105

Merged
merged 12 commits into from Apr 11, 2017

Conversation

Projects
None yet
5 participants
@rjfd
Copy link
Contributor

rjfd commented Jan 25, 2017

@rjfd rjfd added feature rbd labels Jan 25, 2017

@rjfd rjfd force-pushed the rjfd:wip-18481 branch 2 times, most recently from be0e0a7 to 71ef95e Feb 1, 2017

@rjfd rjfd force-pushed the rjfd:wip-18481 branch from 99d87e9 to 11133f4 Feb 10, 2017

@rjfd rjfd changed the title [DNM] librbd: deferred image deletion [RFC] librbd: deferred image deletion Feb 10, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Feb 10, 2017

@dillaman organized the commits and pushed. I think you can start reviewing it.

@@ -4748,6 +4748,191 @@ int image_get_group(cls_method_context_t hctx,
return 0;
}

namespace purgatory {

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Nit: something about "purgatory" doesn't sit well with me -- to me it conveys more religious undertones vs the concept of deferred deletion. Perhaps just "trash" [1]?

[1] https://en.wikipedia.org/wiki/Trash_(computing)

: m_image_ctx(image_ctx), m_skip_open_parent_image(skip_open_parent),
m_on_finish(on_finish), m_error_result(0),
m_last_metadata_key(ImageCtx::METADATA_CONF_PREFIX) {
OpenRequest<I>::OpenRequest(I *image_ctx, bool skip_get_name,

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

You can probably just simplify this logic to not attempt to retrieve the name if both the ImageCtx::id and ImageCtx::name are non-empty. If id is specified, it should continue to open the image using the id -- but if name is specified it can skip the lookup and move right to the get immutable metadata state.

Alternatively, when opening by id-only, it could check the rbd_trash object to retrieve the image name. I am leaning towards this second option -- because if combined with adding a new "--image-id" optional to the rbd CLI for all commands where "--image" is valid, I could run commands like "rbd info --image-id ", "rbd snap ls --image-id ", or "rbd children --image-id " and that would be awesome.

This comment has been minimized.

Copy link
@rjfd

rjfd Feb 17, 2017

Author Contributor

I'm also in favor for the second option. Are you suggesting that I drop the skip_get_name bool and first try to get the image name from the rbd_directory and if it does not exist, try to get the name from the rbd_trash?

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 17, 2017

Contributor

@rjfd Yeah -- that was my thinking

@@ -217,6 +217,11 @@ namespace librbd {
return open(io_ctx, image, name, NULL);
}

int RBD::open_by_id(IoCtx& io_ctx, Image& image, const char *id)
{
return open_by_id(io_ctx, image, id, NULL);

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Nit: nullptr for new code here and below

@@ -4748,6 +4748,191 @@ int image_get_group(cls_method_context_t hctx,
return 0;
}

namespace purgatory {

static const std::string IMAGE_KEY_PREFIX("purg_id_");

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Nit: can just use "id_" -- it's going to be in its own file, so no need to prepend an extra qualifier.

return key.substr(IMAGE_KEY_PREFIX.size());
}

}

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Nit: "// namespace XYZ"

{
ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, false);
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(),

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Nit: ImageCtx::name is empty here (and in similar usages below). You would need a new tracepoint for open_by_id

union {
rbd_delay_condition_t delay_cond;
} cond;
} rbd_remove_condition_t;

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

I think it would be nice if this was a trash "stat"-like structure. I think it would be nice to know the original image name, the date of deletion, and the (optional) time at which deletion should be permitted. I don't think we need to support detained conditions of why it cannot be deleted (i.e. I could have an image w/ protected snapshots due to clones that is also in a consistency group + timed delete enabled to it gets complex).

This comment has been minimized.

Copy link
@rjfd

rjfd Feb 20, 2017

Author Contributor

To support this info, we will need to keep image entries in the RBD_TRASh object even after the image as been deleted.
Who will remove the entries for already purged images, and when?

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 20, 2017

Contributor

Hmm -- not sure I am following? You already have a image id -> struct mapping in RBD_TRASH. Once the image is purged from the trash, we wouldn't need this information anymore.

This comment has been minimized.

Copy link
@rjfd

rjfd Feb 20, 2017

Author Contributor

forget it. I misinterpreted the "date of deletion" as the date at which the image was purged from trash.

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 20, 2017

Contributor

Ah -- sorry about that.

@@ -240,6 +256,13 @@ CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name);
CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
librbd_progress_fn_t cb,
void *cbdata);
CEPH_RBD_API int rbd_deferred_remove(rados_ioctx_t io, const char *name,

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

Rename to _ style --rbd_trash_add / rbd_trash_list / rbd_trash_purge / rbd_trash_purge_with_progress / rbd_remove_deferred. The rbd_trash_add call would take the number of seconds (0 being immediate) for the deferred deletion to be delayed. The *purge calls should perhaps support a force argument that would permit deleting delayed deletions.

@@ -69,6 +69,7 @@
nbd unmap Unmap a nbd device.
object-map check Verify the object map is correct.
object-map rebuild Rebuild an invalid object map.
purge Deletes a pending deletion image.

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

I'd vote for a whole class of "trash XYX" functions for managing the trash. "trash list" / "trash purge [--all] [--image-id] [--pool pool-name] [[]/<image_id>]" / "trash restore" instead of trying to merge the trash list into the normal list function since I'd expect the columns to be different. Perhaps "trash move" to move images to the trash?

@@ -1163,6 +1182,8 @@
-p [ --pool ] arg pool name
--image arg image name
--no-progress disable progress output
--delay arg time delay in milliseconds until effectively remove the

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 14, 2017

Contributor

I think we are probably ok to just assume seconds (or even minutes). It's the amount of time that the image will remain locked in the trash.

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Feb 22, 2017

@rjfd Last night I was thinking that perhaps we might want to add some sort of "source" enum for who initiated the move to the trash. My thought is that rbd-mirror should always move an image to the trash and its image deleter process should periodically attempt to remove any items in the trash (that aren't being delayed) if the source is set to "rbd-mirror". Otherwise, if rbd-mirror is running, it would potentially start deleting images in the trash that a user moved to the trash -- and it might get confusing.

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Feb 24, 2017

@dillaman I agree with your idea. How many sources do we need? currently I'm only thinking in these two (user, rbd_mirror), do we need more?

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Feb 24, 2017

@rjfd I can only think of the two cases -- the enum could always be expanded if needed in the future.

@rjfd rjfd force-pushed the rjfd:wip-18481 branch from adefde1 to d8eca6d Feb 24, 2017

@rjfd rjfd changed the title [RFC] librbd: deferred image deletion librbd: deferred image deletion Feb 24, 2017

@rjfd rjfd force-pushed the rjfd:wip-18481 branch 2 times, most recently from f65c8fd to 3ca79d5 Feb 24, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Feb 24, 2017

@dillaman pushed the new changes and rebased on top of master. Ready for a second round of reviews.

@dillaman
Copy link
Contributor

dillaman left a comment

I think we might also want some way to force-delete an image that has a deferred deletion time specified (i.e. I fat-fingered a very large time) -- perhaps a new API method that deletes a specific image from the trash (by id) w/ and optional "--force" optional

*
* Input:
* @param id the id of the image
* @param cond the encoded deletion condition

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: needs update

r = read_key(hctx, key, &tmp);
if (r != -ENOENT) {
CLS_LOG(10, "id already exists");
return -EEXIST;

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: might have hit a different error from -ENOENT -- should only return -EEXISTS if "r == 0"

return cls_cxx_map_set_vals(hctx, &omap_vals);


return 0;

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: dead code

for (; it != raw_data.end(); ++it)
::decode(data[trash::image_id_from_key(it->first)], it->second);

if (r < max_read)

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: braces for single-line conditionals

CLS_ERR("failed to read the vals off of disk: %s", cpp_strerror(r).c_str());
return r;
}
if (raw_data.empty())

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: braces for single-line conditionals

@@ -575,6 +577,11 @@ Context *RemoveRequest<I>::handle_mirror_image_remove(int *result) {
*result = 0;
}

if (m_from_trash_purge) {
// image was already removed from the directory

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Note: should remove image from directory and remove the "rbd_id.XYZ" object (so that I can move image XYZ to the trash and immediately create a new image named XYZ).

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 1, 2017

Author Contributor

Not sure if I'm following. If m_from_trash_purge is true, then it means that the image was already removed from the directory, and the "rbd_id.XYZwas also removed, whentrash_move` was called for that image.

Am I missing some case here?

This comment has been minimized.

Copy link
@dillaman

dillaman Mar 1, 2017

Contributor

I think I was thrown off by the comment when going through the review from top-to-bottom. The comment says "it's removed from the directory" but it should really say that both the id object and the directory entry have been removed.

ictx->owner_lock.get_read();
if (ictx->exclusive_lock != nullptr) {
r = ictx->operations->prepare_image_update();
if (r < 0 || !ictx->exclusive_lock->is_lock_owner()) {

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

ImageCtx::exclusive_lock could now be a nullptr since lock is released by Operations::prepare_image_update

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 1, 2017

Author Contributor

I don't see where the exclusive-lock is released in Operations::prepare_image_update... Can you point where it is released?

This comment has been minimized.

Copy link
@dillaman
ictx->owner_lock.put_read();
if (is_locked) {
C_SaferCond ctx;
ictx->exclusive_lock->shut_down(&ctx);

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

ImageCtx::exclusive_lock could now be a nullptr since lock is released

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 1, 2017

Author Contributor

I'm checking if ictx->exclusive_lock is null in when assigning the is_locked variable. But if it is possible to exist another thread that releases the exclusive-lock (assigning nullptr to ictx->exclusive_lock) after I release the RLock on the ictx->owner_lock, then checking if ictx->exclusive_lock is null at this point is not enough, and the current locking protocol for shutting down the lock must change a bit.

This comment has been minimized.

Copy link
@dillaman

dillaman Mar 1, 2017

Contributor

On line 1676 you release ImageCtx::owner_lock and that is the lock that protects ImageCtx::exclusive_lock from being modified

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 1, 2017

Author Contributor

I had to release it because otherwise if I call shut_down while holding a read/write-lock over owner_lock it creates a deadlock between L1680 and https://github.com/ceph/ceph/blob/master/src/librbd/ExclusiveLock.cc#L281

This comment has been minimized.

Copy link
@dillaman

dillaman Mar 1, 2017

Contributor

You need to use the async version and perform the "wait()" after you release the owner lock.

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 1, 2017

Author Contributor

ah, yes -- my bad, the solution was right in front of my eyes. Thanks

source = RBD_RBD_MIRROR_TRASH_MOVE;
break;
default:
source = RBD_USER_TRASH_MOVE;

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: I'd say either treat this as an error or just reinterpret_cast between the two enums

@@ -242,6 +254,17 @@ CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name);
CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
librbd_progress_fn_t cb,
void *cbdata);
CEPH_RBD_API int rbd_trash_move(rados_ioctx_t io, const char *name,
uint64_t delay);
CEPH_RBD_API int rbd_trash_list(rados_ioctx_t io, char **ids,

This comment has been minimized.

Copy link
@dillaman

dillaman Feb 27, 2017

Contributor

Nit: we usually offer a cleanup method when our API allocates memory

@rjfd rjfd force-pushed the rjfd:wip-18481 branch 2 times, most recently from 9557472 to 0b1c00e Mar 1, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 1, 2017

@dillaman regarding your comment about deleting an image that the deferred time hasn't expired yet, the current trash_purge command does not check the status of the deferment_end_time and it deletes any image from the trash at any time.

Should I change this behavior to only delete when the deferment time has expired, or when passing an explicit force value?

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Mar 1, 2017

@rjfd I think purge needs to respect the deferred deletion time. I think the individual image deletion API method w/ its force override can be used to delete any deferred deletions (i.e. we add an extra hoop to jump through)

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Mar 1, 2017

@rjfd ... also, can you add/extend a workunit test case for all the new CLI commands?

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 1, 2017

@dillaman yes, I'll do that as well

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 1, 2017

I think the individual image deletion API method w/ its force override can be used to delete any deferred deletions (i.e. we add an extra hoop to jump through)

@dillaman Can you clarify this point? are you talking about supporting deletion of deferred images at the librbd only, or also using the CLI using the rbd remove command?

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Mar 1, 2017

@rjfd supported via the API and via the "rbd trash remove --force " command

lderr(cct) << "error checking if image " << image_name << " exists: "
<< cpp_strerror(r) << dendl;
return r;
} else if (r != -ENOENT){

This comment has been minimized.

Copy link
@zy751713126

zy751713126 Mar 2, 2017

Contributor

r == -ENOENT ?

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 2, 2017

Author Contributor

No, in this case we are checking the case where r == 0, which corresponds to the scenario that already exist an id object.

This comment has been minimized.

Copy link
@zy751713126

zy751713126 Mar 2, 2017

Contributor

ok, I see, thanks

lderr(cct) << "error adding image to v2 directory: "
<< cpp_strerror(r) << dendl;
return r;
}

This comment has been minimized.

Copy link
@zy751713126

zy751713126 Mar 2, 2017

Contributor

else if (r == -EEXIST) {
}

This comment has been minimized.

Copy link
@rjfd

rjfd Mar 2, 2017

Author Contributor

We don't need to handle the case that r == -EEXIST because if the rbd_directory already has an entry then it means that we are recovering from a failed restore

This comment has been minimized.

Copy link
@zy751713126

zy751713126 Mar 2, 2017

Contributor

ok, thanks

@rjfd rjfd force-pushed the rjfd:wip-18481 branch from 0b1c00e to fc8685f Mar 2, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 2, 2017

@dillaman pushed the fix to the trash_purge with the force optional. I think all the code for this feature is done, I'm just missing the test workunit which I'll add in a new commit.

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 2, 2017

@dillaman pushed the workunit commit

@rjfd rjfd force-pushed the rjfd:wip-18481 branch from 238a613 to 0197156 Mar 27, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Mar 27, 2017

@dillaman just pushed python bindings implementation

@rjfd rjfd force-pushed the rjfd:wip-18481 branch 2 times, most recently from 5e3a519 to 830689d Mar 28, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Apr 6, 2017

@dillaman do you think we are still missing something?

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Apr 6, 2017

@rjfd sorry, I've been chasing down other items and haven't gotten a chance to re-review this. I'll do it this afternoon.

'id' : decode_cstr(self.entries[i].id),
'name' : decode_cstr(self.entries[i].name),
'source' : self.entries[i].source,
'deletion_time' : self.entries[i].deletion_time,

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

Convert time_ts to datetimes via datetime.fromtimestamp and update the docs above

yield {
'id' : decode_cstr(self.entries[i].id),
'name' : decode_cstr(self.entries[i].name),
'source' : self.entries[i].source,

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

Convert to human-readable string -- the enum doesn't serve much value besides informational purposes

<< std::endl;
} else if (r == -EMLINK) {
std::cerr << std::endl
<< "Remove the image from the consistency group and try again."

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

It looks like this comment is still valid -- the "rbd group image remove" command needs to support the "--image-id" optional

*snap_name = vm[snap_key].as<std::string>();
}

if (pool_name->empty()) {

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

Nit: add pool_name != nullptr so Coverity doesn't complain

read_only, rados, io_ctx, image);
}

int init_and_open_image_by_id(const std::string &pool_name,

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

Nit: the _by_id suffix seems off to me since it can open by name as well. I would just drop it and always open by id as first choice if it's provided.

@@ -446,6 +446,37 @@ int get_pool_image_snapshot_names(const po::variables_map &vm,
return 0;
}

int get_pool_snapshot_names(const po::variables_map &vm,

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 6, 2017

Contributor

Nit: probably a good idea to ensure that --[<mod>-]image hasn't been populated when expecting to open by id

@rjfd rjfd force-pushed the rjfd:wip-18481 branch 3 times, most recently from fba3cdc to 424dad0 Apr 10, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Apr 10, 2017

@dillaman pushed the changes addressing your last review. @yangdongsheng concerns about CLI params are also fixed.

Some unit test is failing but I don't think it's caused by these changes.

@dillaman

This comment has been minimized.

Copy link
Contributor

dillaman commented Apr 11, 2017

retest this please

rjfd added some commits Feb 24, 2017

cls_rbd: methods to manipulate the rbd_trash object
Signed-off-by: Ricardo Dias <rdias@suse.com>
librbd: added open an image by id to API
Signed-off-by: Ricardo Dias <rdias@suse.com>
librbd: open image gets name from directory or trash
Signed-off-by: Ricardo Dias <rdias@suse.com>
librbd: added trash methods to API
Signed-off-by: Ricardo Dias <rdias@suse.com>
rbd: added CLI support for trash operations
Signed-off-by: Ricardo Dias <rdias@suse.com>
qa/workunits/rbd: cli testing of rbd trash commands
Signed-off-by: Ricardo Dias <rdias@suse.com>
rbd: added image-id optional to Info command
Signed-off-by: Ricardo Dias <rdias@suse.com>
pybind: librbd: added trash API to python RBD binding
Signed-off-by: Ricardo Dias <rdias@suse.com>
librbd: added group image remove by id to API
Signed-off-by: Ricardo Dias <rdias@suse.com>
rbd: added group image remove by id to CLI
Signed-off-by: Ricardo Dias <rdias@suse.com>
rbd: added image_id param to Utils::init_and_open_image
Signed-off-by: Ricardo Dias <rdias@suse.com>
rbd: Added image-id optional to Snap commands
Signed-off-by: Ricardo Dias <rdias@suse.com>

@rjfd rjfd force-pushed the rjfd:wip-18481 branch from 424dad0 to 6b54288 Apr 11, 2017

@rjfd

This comment has been minimized.

Copy link
Contributor Author

rjfd commented Apr 11, 2017

@dillaman rebased on top of master and the unit tests passed

@dillaman dillaman merged commit d084f68 into ceph:master Apr 11, 2017

3 checks passed

Signed-off-by all commits in this PR are signed
Details
Unmodifed Submodules submodules for project are unmodified
Details
default Build finished.
Details
<< dendl;

std::string image_id;
ImageCtx *ictx = new ImageCtx(image_name, "", nullptr, io_ctx, false);

This comment has been minimized.

Copy link
@runsisi

runsisi Apr 28, 2017

Contributor

hi @dillaman @rjfd , i am wondering why we do not have to validate the removal of the image, i.e., like the normal remove operation we have to check snapshots, watchers, consistency group, etc. ?

This comment has been minimized.

Copy link
@rjfd

rjfd Apr 28, 2017

Author Contributor

@runsisi because we aren't really deleting the image. We are moving the image to the trash bin, and when we do a trash rm only then we run all the validations.

This comment has been minimized.

Copy link
@runsisi

runsisi Apr 28, 2017

Contributor

@rjfd thanks! so the error messages like below is just a noise and we can safely ignore?

[root@cs1 ~]# rbd info c1
rbd image 'c1':
        size 1024 MB in 256 objects
        order 22 (4096 kB objects)
        block_name_prefix: rbd_data.1047238e1f29
        format: 2
        features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
        flags: 
2017-04-28 17:52:41.534002 7fe11afa6900 -1 librbd: error getting parent image name: (2) No such file or directory

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 28, 2017

Contributor

@runsisi That looks like a bug in our handling of opening parent images -- we would want the parent to be opened even if the image is in the trash.

This comment has been minimized.

Copy link
@rjfd

rjfd Apr 28, 2017

Author Contributor

@runsisi @dillaman yes it looks like a bug. I'll open a ticket and will assign it to me.

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 28, 2017

Contributor

@rjfd No worries -- I already have a patch for it. I'm just adding a new API so that rbd info can return some text that the parent is actually deleted.

This comment has been minimized.

Copy link
@rjfd

rjfd Apr 28, 2017

Author Contributor

@dillaman great!

This comment has been minimized.

Copy link
@runsisi

runsisi Apr 28, 2017

Contributor

@rjfd @dillaman thank you for your help :)

This comment has been minimized.

Copy link
@dillaman

dillaman Apr 28, 2017

Contributor

@runsisi Thanks for the sanity check! I opened PR #14875

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.