1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Add dm_task_retry_remove fn to use retry logic for device removal.

This call ensures that the dm device removal is retried several
times before failing.
This commit is contained in:
Peter Rajnoha 2011-09-22 17:09:48 +00:00
parent f989a55539
commit 355b2224b2
4 changed files with 33 additions and 21 deletions

View File

@ -1,6 +1,6 @@
Version 1.02.68 - Version 1.02.68 -
================================== ==================================
Retry DM_DEVICE_REMOVE ioctl if device is busy. Add dm_task_retry_remove fn to use retry logic for device removal.
Remove unused passed parameters for _mirror_emit_segment_line(). Remove unused passed parameters for _mirror_emit_segment_line().
Add dm_config and string character escaping functions to libdevmapper. Add dm_config and string character escaping functions to libdevmapper.
Mark unreleased memory pools as internal error. Mark unreleased memory pools as internal error.

View File

@ -828,6 +828,13 @@ int dm_task_secure_data(struct dm_task *dmt)
return 1; return 1;
} }
int dm_task_retry_remove(struct dm_task *dmt)
{
dmt->retry_remove = 1;
return 1;
}
int dm_task_query_inactive_table(struct dm_task *dmt) int dm_task_query_inactive_table(struct dm_task *dmt)
{ {
dmt->query_inactive_table = 1; dmt->query_inactive_table = 1;
@ -1539,16 +1546,15 @@ static const char *_sanitise_message(char *message)
return sanitised_message; return sanitised_message;
} }
#define DM_REMOVE_IOCTL_RETRIES 25
static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command, static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
unsigned repeat_count) unsigned buffer_repeat_count,
unsigned retry_repeat_count,
int *retryable)
{ {
struct dm_ioctl *dmi; struct dm_ioctl *dmi;
int ioctl_with_uevent; int ioctl_with_uevent;
int retries = DM_REMOVE_IOCTL_RETRIES;
dmi = _flatten(dmt, repeat_count); dmi = _flatten(dmt, buffer_repeat_count);
if (!dmi) { if (!dmi) {
log_error("Couldn't create ioctl argument."); log_error("Couldn't create ioctl argument.");
return NULL; return NULL;
@ -1609,7 +1615,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
} }
log_debug("dm %s %s%s %s%s%s %s%.0d%s%.0d%s" log_debug("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
"%s%c%c%s%s%s%s%s %.0" PRIu64 " %s [%u]", "%s%c%c%s%s%s%s%s%s %.0" PRIu64 " %s [%u] (*%u)",
_cmd_data_v4[dmt->type].name, _cmd_data_v4[dmt->type].name,
dmt->new_uuid ? "UUID " : "", dmt->new_uuid ? "UUID " : "",
dmi->name, dmi->uuid, dmt->newname ? " " : "", dmi->name, dmi->uuid, dmt->newname ? " " : "",
@ -1624,29 +1630,18 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmt->no_flush ? 'N' : 'F', dmt->no_flush ? 'N' : 'F',
dmt->read_only ? "R" : "", dmt->read_only ? "R" : "",
dmt->skip_lockfs ? "S " : "", dmt->skip_lockfs ? "S " : "",
dmt->retry_remove ? "T " : "",
dmt->secure_data ? "W " : "", dmt->secure_data ? "W " : "",
dmt->query_inactive_table ? "I " : "", dmt->query_inactive_table ? "I " : "",
dmt->enable_checks ? "C" : "", dmt->enable_checks ? "C" : "",
dmt->sector, _sanitise_message(dmt->message), dmt->sector, _sanitise_message(dmt->message),
dmi->data_size); dmi->data_size, retry_repeat_count);
#ifdef DM_IOCTLS #ifdef DM_IOCTLS
repeat_dm_ioctl:
if (ioctl(_control_fd, command, dmi) < 0) { if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) || if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
(dmt->type == DM_DEVICE_MKNODES) || (dmt->type == DM_DEVICE_MKNODES) ||
(dmt->type == DM_DEVICE_STATUS))) (dmt->type == DM_DEVICE_STATUS)))
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */ dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
/*
* FIXME: This is a workaround for asynchronous events generated
* as a result of using the WATCH udev rule with which we
* have no way of synchronizing. Processing such events in
* parallel causes devices to be open.
*/
else if (errno == EBUSY && (dmt->type == DM_DEVICE_REMOVE) && retries--) {
log_debug("device-mapper: device is busy, retrying removal");
usleep(200000);
goto repeat_dm_ioctl;
}
else { else {
if (_log_suppress) if (_log_suppress)
log_verbose("device-mapper: %s ioctl " log_verbose("device-mapper: %s ioctl "
@ -1658,6 +1653,9 @@ repeat_dm_ioctl:
"failed: %s", "failed: %s",
_cmd_data_v4[dmt->type].name, _cmd_data_v4[dmt->type].name,
strerror(errno)); strerror(errno));
*retryable = errno == EBUSY;
_dm_zfree_dmi(dmi); _dm_zfree_dmi(dmi);
return NULL; return NULL;
} }
@ -1680,6 +1678,9 @@ void dm_task_update_nodes(void)
update_devs(); update_devs();
} }
#define DM_IOCTL_RETRIES 25
#define DM_RETRY_USLEEP_DELAY 200000
int dm_task_run(struct dm_task *dmt) int dm_task_run(struct dm_task *dmt)
{ {
struct dm_ioctl *dmi; struct dm_ioctl *dmi;
@ -1687,6 +1688,8 @@ int dm_task_run(struct dm_task *dmt)
int check_udev; int check_udev;
int rely_on_udev; int rely_on_udev;
int suspended_counter; int suspended_counter;
unsigned ioctl_retry = 1;
int retryable;
if ((unsigned) dmt->type >= if ((unsigned) dmt->type >=
(sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
@ -1734,7 +1737,14 @@ int dm_task_run(struct dm_task *dmt)
/* FIXME Detect and warn if cookie set but should not be. */ /* FIXME Detect and warn if cookie set but should not be. */
repeat_ioctl: repeat_ioctl:
if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor))) { if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor,
ioctl_retry, &retryable))) {
if (retryable && dmt->type == DM_DEVICE_REMOVE &&
dmt->retry_remove && ++ioctl_retry <= DM_IOCTL_RETRIES) {
usleep(DM_RETRY_USLEEP_DELAY);
goto repeat_ioctl;
}
_udev_complete(dmt); _udev_complete(dmt);
return 0; return 0;
} }

View File

@ -63,6 +63,7 @@ struct dm_task {
int cookie_set; int cookie_set;
int new_uuid; int new_uuid;
int secure_data; int secure_data;
int retry_remove;
int enable_checks; int enable_checks;
char *uuid; char *uuid;

View File

@ -191,6 +191,7 @@ int dm_task_skip_lockfs(struct dm_task *dmt);
int dm_task_query_inactive_table(struct dm_task *dmt); int dm_task_query_inactive_table(struct dm_task *dmt);
int dm_task_suppress_identical_reload(struct dm_task *dmt); int dm_task_suppress_identical_reload(struct dm_task *dmt);
int dm_task_secure_data(struct dm_task *dmt); int dm_task_secure_data(struct dm_task *dmt);
int dm_task_retry_remove(struct dm_task *dmt);
/* /*
* Enable checks for common mistakes such as issuing ioctls in an unsafe order. * Enable checks for common mistakes such as issuing ioctls in an unsafe order.