Skip to content

Commit

Permalink
multipathd: use timestamps to tell when the directio checker timed out
Browse files Browse the repository at this point in the history
Instead of counting the number of times the path checker has been
called and treating that as the number of seconds that have passed,
calculate the actual timestamp when the checker will time out, and
check that instead.

Suggested-by: Martin Wilck <[email protected]>
Signed-off-by: Benjamin Marzinski <[email protected]>
Reviewed-by: Martin Wilck <[email protected]>
  • Loading branch information
bmarzins authored and mwilck committed Nov 6, 2024
1 parent 076b7b2 commit 7dc7b90
Showing 1 changed file with 29 additions and 13 deletions.
42 changes: 29 additions & 13 deletions libmultipath/checkers/directio.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,26 @@ const char *libcheck_msgtable[] = {
#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)

struct directio_context {
unsigned int running;
int reset_flags;
struct timespec timeout;
int reset_flags;
struct aio_group *aio_grp;
struct async_req *req;
bool checked_state;
};

static bool is_running(struct directio_context *ct) {
return (ct->timeout.tv_sec != 0 || ct->timeout.tv_nsec != 0);
}

static void start_running(struct directio_context *ct, int timeout_secs) {
get_monotonic_time(&ct->timeout);
ct->timeout.tv_sec += timeout_secs;
}

static void stop_running(struct directio_context *ct) {
ct->timeout.tv_sec = ct->timeout.tv_nsec = 0;
}

static struct aio_group *
add_aio_group(void)
{
Expand Down Expand Up @@ -234,9 +247,9 @@ void libcheck_free (struct checker * c)
}
}

if (ct->running && ct->req->state != PATH_PENDING)
ct->running = 0;
if (!ct->running) {
if (is_running(ct) && ct->req->state != PATH_PENDING)
stop_running(ct);
if (!is_running(ct)) {
free(ct->req->buf);
free(ct->req);
ct->aio_grp->holders--;
Expand Down Expand Up @@ -304,7 +317,7 @@ check_pending(struct directio_context *ct, struct timespec timeout)
r = get_events(ct->aio_grp, &timeout);

if (ct->req->state != PATH_PENDING) {
ct->running = 0;
stop_running(ct);
return;
} else if (r == 0 ||
(timeout.tv_sec == 0 && timeout.tv_nsec == 0))
Expand All @@ -330,10 +343,10 @@ check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
if (sync > 0)
LOG(4, "called in synchronous mode");

if (ct->running) {
if (is_running(ct)) {
ct->checked_state = true;
if (ct->req->state != PATH_PENDING) {
ct->running = 0;
stop_running(ct);
return ct->req->state;
}
} else {
Expand All @@ -348,9 +361,9 @@ check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
LOG(3, "io_submit error %i", -rc);
return PATH_UNCHECKED;
}
start_running(ct, timeout_secs);
ct->checked_state = false;
}
ct->running++;
if (!sync)
return PATH_PENDING;

Expand Down Expand Up @@ -388,7 +401,7 @@ static void set_msgid(struct checker *c, int state)
bool libcheck_need_wait(struct checker *c)
{
struct directio_context *ct = (struct directio_context *)c->context;
return (ct && ct->running && ct->req->state == PATH_PENDING &&
return (ct && is_running(ct) && ct->req->state == PATH_PENDING &&
!ct->checked_state);
}

Expand All @@ -400,18 +413,21 @@ int libcheck_pending(struct checker *c)
struct timespec no_wait = { .tv_sec = 0 };

/* The if path checker isn't running, just return the exiting value. */
if (!ct || !ct->running) {
if (!ct || !is_running(ct)) {
rc = c->path_state;
goto out;
}

if (ct->req->state == PATH_PENDING)
check_pending(ct, no_wait);
else
ct->running = 0;
stop_running(ct);
rc = ct->req->state;
if (rc == PATH_PENDING) {
if (ct->running > c->timeout) {
struct timespec now;

get_monotonic_time(&now);
if (timespeccmp(&now, &ct->timeout) > 0) {
LOG(3, "abort check on timeout");
io_cancel(ct->aio_grp->ioctx, &ct->req->io, &event);
rc = PATH_DOWN;
Expand Down

0 comments on commit 7dc7b90

Please sign in to comment.