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:
parent
f989a55539
commit
355b2224b2
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user