From c6327b63e6d3a11bb333829a8341d572e2fa7d9f Mon Sep 17 00:00:00 2001 From: Daniel Verite Date: Sat, 9 Jun 2012 04:16:11 +0200 Subject: [PATCH] Retry removal of busy minors When failing to remove a zvol device link because it's busy, wait a bit and retry in a loop instead of giving up immediately. This technique is similar to the loop in zpool_label_disk_wait(), with the same goal: waiting for the asynchronous udev processes to finish their work. Signed-off-by: Brian Behlendorf Closes #692 --- lib/libzfs/libzfs_dataset.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index e8c329ced9..661f9b5f97 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -3920,10 +3920,29 @@ int zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) { zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + int timeout = 3000; /* in milliseconds */ + int error = 0; + int i; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { + /* + * Due to concurrent updates by udev the device may be reported as + * busy. In this case don't immediately fail. Instead briefly delay + * and retry the ioctl() which is now likely to succeed. If unable + * remove the link after timeout milliseconds return the failure. + */ + for (i = 0; i < timeout; i++) { + error = ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); + if (error && errno == EBUSY) { + usleep(1000); + continue; + } else { + break; + } + } + + if (error) { switch (errno) { case ENXIO: /*