summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Verite <[email protected]>2012-06-09 04:16:11 +0200
committerBrian Behlendorf <[email protected]>2012-06-11 10:50:20 -0700
commitc6327b63e6d3a11bb333829a8341d572e2fa7d9f (patch)
tree01a1764760e818068e83caf691a5ea3ee70fca44
parent92e91da20839ee50536223bedf2ba4fb7d2fae71 (diff)
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 <[email protected]> Closes #692
-rw-r--r--lib/libzfs/libzfs_dataset.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c
index e8c329ced..661f9b5f9 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:
/*