diff options
author | Daniel Verite <daniel@verite.pro> | 2012-06-09 04:16:11 +0200 |
---|---|---|
committer | Brian Behlendorf <behlendorf1@llnl.gov> | 2012-06-11 10:50:20 -0700 |
commit | c6327b63e6d3a11bb333829a8341d572e2fa7d9f (patch) | |
tree | 01a1764760e818068e83caf691a5ea3ee70fca44 | |
parent | 92e91da20839ee50536223bedf2ba4fb7d2fae71 (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 <behlendorf1@llnl.gov>
Closes #692
-rw-r--r-- | lib/libzfs/libzfs_dataset.c | 21 |
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: /* |