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

libdm: Add dm_task_get_errno to return ioctl errno.

There are reports of unexplained ioctl failures when using dmeventd.
An explanation might be that the wrong value of errno is being used.

Change libdevmapper to store an errno set by from dm ioctl() directly
and provide it to the caller through a new dm_task_get_errno() function.

[Replaced f9510548667754d9209b232348ccd2d806c0f1d8]
This commit is contained in:
Alasdair G Kergon 2015-05-26 15:13:49 +01:00
parent b244fffc18
commit eeb498627c
6 changed files with 38 additions and 18 deletions

View File

@ -1,5 +1,7 @@
Version 1.02.98 - Version 1.02.98 -
=============================== ===============================
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
Use copy of errno made after each dm ioctl call in case errno changes later.
Version 1.02.97 - 15th May 2015 Version 1.02.97 - 15th May 2015
=============================== ===============================

View File

@ -710,6 +710,7 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
int ret = DM_WAIT_RETRY; int ret = DM_WAIT_RETRY;
struct dm_task *dmt; struct dm_task *dmt;
struct dm_info info; struct dm_info info;
int ioctl_errno;
*task = 0; *task = 0;
@ -739,27 +740,29 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
* either for a timeout event, or to cancel the thread. * either for a timeout event, or to cancel the thread.
*/ */
set = _unblock_sigalrm(); set = _unblock_sigalrm();
errno = 0;
if (dm_task_run(dmt)) { if (dm_task_run(dmt)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR; thread->current_events |= DM_EVENT_DEVICE_ERROR;
ret = DM_WAIT_INTR; ret = DM_WAIT_INTR;
if ((ret = dm_task_get_info(dmt, &info))) if ((ret = dm_task_get_info(dmt, &info)))
thread->event_nr = info.event_nr; thread->event_nr = info.event_nr;
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) { } else {
ioctl_errno = dm_task_get_errno(dmt);
if (thread->events & DM_EVENT_TIMEOUT && ioctl_errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT; thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR; ret = DM_WAIT_INTR;
} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) { } else if (thread->status == DM_THREAD_SHUTDOWN && ioctl_errno == EINTR)
ret = DM_WAIT_FATAL; ret = DM_WAIT_FATAL;
} else { else {
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s", syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
errno, strerror(errno)); ioctl_errno, strerror(ioctl_errno));
if (errno == ENXIO) { if (ioctl_errno == ENXIO) {
syslog(LOG_ERR, "%s disappeared, detaching", syslog(LOG_ERR, "%s disappeared, detaching",
thread->device.name); thread->device.name);
ret = DM_WAIT_FATAL; ret = DM_WAIT_FATAL;
} }
} }
}
DEBUGLOG("Completed waitevent task for %s", thread->device.uuid); DEBUGLOG("Completed waitevent task for %s", thread->device.uuid);
pthread_sigmask(SIG_SETMASK, &set, NULL); pthread_sigmask(SIG_SETMASK, &set, NULL);

View File

@ -0,0 +1 @@
dm_task_get_errno

View File

@ -1717,6 +1717,8 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
struct dm_ioctl *dmi; struct dm_ioctl *dmi;
int ioctl_with_uevent; int ioctl_with_uevent;
dmt->ioctl_errno = 0;
dmi = _flatten(dmt, buffer_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.");
@ -1803,12 +1805,13 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
#ifdef DM_IOCTLS #ifdef DM_IOCTLS
if (ioctl(_control_fd, command, dmi) < 0 && if (ioctl(_control_fd, command, dmi) < 0 &&
dmt->expected_errno != errno) { dmt->expected_errno != errno) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) || dmt->ioctl_errno = errno;
if (dmt->ioctl_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 */
else { else {
if (_log_suppress || errno == EINTR) if (_log_suppress || dmt->ioctl_errno == EINTR)
log_verbose("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s " log_verbose("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s "
"failed: %s", "failed: %s",
_cmd_data_v4[dmt->type].name, _cmd_data_v4[dmt->type].name,
@ -1819,7 +1822,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmt->minor > 0 ? dmt->minor : 0, dmt->minor > 0 ? dmt->minor : 0,
dmt->major > 0 && dmt->minor == 0 ? "0" : "", dmt->major > 0 && dmt->minor == 0 ? "0" : "",
dmt->major > 0 ? ")" : "", dmt->major > 0 ? ")" : "",
strerror(errno)); strerror(dmt->ioctl_errno));
else else
log_error("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s " log_error("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s "
"failed: %s", "failed: %s",
@ -1831,14 +1834,14 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmt->minor > 0 ? dmt->minor : 0, dmt->minor > 0 ? dmt->minor : 0,
dmt->major > 0 && dmt->minor == 0 ? "0" : "", dmt->major > 0 && dmt->minor == 0 ? "0" : "",
dmt->major > 0 ? ")" : "", dmt->major > 0 ? ")" : "",
strerror(errno)); strerror(dmt->ioctl_errno));
/* /*
* It's sometimes worth retrying after EBUSY in case * It's sometimes worth retrying after EBUSY in case
* it's a transient failure caused by an asynchronous * it's a transient failure caused by an asynchronous
* process quickly scanning the device. * process quickly scanning the device.
*/ */
*retryable = errno == EBUSY; *retryable = dmt->ioctl_errno == EBUSY;
goto error; goto error;
} }
@ -1876,6 +1879,11 @@ void dm_task_update_nodes(void)
#define DM_IOCTL_RETRIES 25 #define DM_IOCTL_RETRIES 25
#define DM_RETRY_USLEEP_DELAY 200000 #define DM_RETRY_USLEEP_DELAY 200000
int dm_task_get_errno(struct dm_task *dmt)
{
return dmt->ioctl_errno;
}
int dm_task_run(struct dm_task *dmt) int dm_task_run(struct dm_task *dmt)
{ {
struct dm_ioctl *dmi; struct dm_ioctl *dmi;

View File

@ -68,6 +68,7 @@ struct dm_task {
int deferred_remove; int deferred_remove;
int enable_checks; int enable_checks;
int expected_errno; int expected_errno;
int ioctl_errno;
char *uuid; char *uuid;
char *mangled_uuid; char *mangled_uuid;

View File

@ -392,6 +392,11 @@ int dm_get_status_thin(struct dm_pool *mem, const char *params,
*/ */
int dm_task_run(struct dm_task *dmt); int dm_task_run(struct dm_task *dmt);
/*
* The errno from the last device-mapper ioctl performed by dm_task_run.
*/
int dm_task_get_errno(struct dm_task *dmt);
/* /*
* Call this to make or remove the device nodes associated with previously * Call this to make or remove the device nodes associated with previously
* issued commands. * issued commands.