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
This commit is contained in:
Daniel Verite 2012-06-09 04:16:11 +02:00 committed by Brian Behlendorf
parent 92e91da208
commit c6327b63e6
1 changed files with 20 additions and 1 deletions

View File

@ -3920,10 +3920,29 @@ int
zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) zvol_remove_link(libzfs_handle_t *hdl, const char *dataset)
{ {
zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; 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)); (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) { switch (errno) {
case ENXIO: case ENXIO:
/* /*