@@ -26,6 +26,7 @@ struct checker_class {
void (*free)(struct checker *); /* to free the context */
void (*reset)(void); /* to reset the global variables */
void *(*thread)(void *); /* async thread entry point */
+ int (*pending)(struct checker *); /* to recheck pending paths */
const char **msgtable;
short msgtable_size;
};
@@ -180,7 +181,8 @@ static struct checker_class *add_checker_class(const char *name)
c->mp_init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_mp_init");
c->reset = (void (*)(void)) dlsym(c->handle, "libcheck_reset");
c->thread = (void *(*)(void*)) dlsym(c->handle, "libcheck_thread");
- /* These 3 functions can be NULL. call dlerror() to clear out any
+ c->pending = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_pending");
+ /* These 4 functions can be NULL. call dlerror() to clear out any
* error string */
dlerror();
@@ -190,6 +190,7 @@ void libcheck_free(struct checker *);
void *libcheck_thread(struct checker_context *ctx);
void libcheck_reset(void);
int libcheck_mp_init(struct checker *);
+int libcheck_pending(struct checker *c);
/*
@@ -288,14 +288,36 @@ get_events(struct aio_group *aio_grp, struct timespec *timeout)
return got_events;
}
+static void
+check_pending(struct directio_context *ct, struct timespec endtime)
+{
+ int r;
+ struct timespec currtime, timeout;
+
+ while(1) {
+ get_monotonic_time(&currtime);
+ timespecsub(&endtime, &currtime, &timeout);
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_nsec = 0;
+
+ r = get_events(ct->aio_grp, &timeout);
+
+ if (ct->req->state != PATH_PENDING) {
+ ct->running = 0;
+ return;
+ } else if (r == 0 ||
+ (timeout.tv_sec == 0 && timeout.tv_nsec == 0))
+ return;
+ }
+}
+
static int
check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
{
struct timespec timeout = { .tv_nsec = 1000 };
struct stat sb;
int rc;
- long r;
- struct timespec currtime, endtime;
+ struct timespec endtime;
if (fstat(fd, &sb) == 0) {
LOG(4, "called for %x", (unsigned) sb.st_rdev);
@@ -330,21 +352,11 @@ check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
endtime.tv_sec += timeout.tv_sec;
endtime.tv_nsec += timeout.tv_nsec;
normalize_timespec(&endtime);
- while(1) {
- r = get_events(ct->aio_grp, &timeout);
- if (ct->req->state != PATH_PENDING) {
- ct->running = 0;
- return ct->req->state;
- } else if (r == 0 ||
- (timeout.tv_sec == 0 && timeout.tv_nsec == 0))
- break;
+ check_pending(ct, endtime);
+ if (ct->req->state != PATH_PENDING)
+ return ct->req->state;
- get_monotonic_time(&currtime);
- timespecsub(&endtime, &currtime, &timeout);
- if (timeout.tv_sec < 0)
- timeout.tv_sec = timeout.tv_nsec = 0;
- }
if (ct->running > timeout_secs || sync) {
struct io_event event;
@@ -360,17 +372,9 @@ check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
return rc;
}
-int libcheck_check (struct checker * c)
+static void set_msgid(struct checker *c, int state)
{
- int ret;
- struct directio_context * ct = (struct directio_context *)c->context;
-
- if (!ct)
- return PATH_UNCHECKED;
-
- ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
-
- switch (ret)
+ switch (state)
{
case PATH_UNCHECKED:
c->msgid = MSG_DIRECTIO_UNKNOWN;
@@ -387,5 +391,37 @@ int libcheck_check (struct checker * c)
default:
break;
}
+}
+
+int libcheck_pending(struct checker *c)
+{
+ struct timespec endtime;
+ struct directio_context *ct = (struct directio_context *)c->context;
+
+ /* The if path checker isn't running, just return the exiting value. */
+ if (!ct || !ct->running)
+ return c->path_state;
+
+ if (ct->req->state == PATH_PENDING) {
+ get_monotonic_time(&endtime);
+ check_pending(ct, endtime);
+ } else
+ ct->running = 0;
+ set_msgid(c, ct->req->state);
+
+ return ct->req->state;
+}
+
+int libcheck_check (struct checker * c)
+{
+ int ret;
+ struct directio_context * ct = (struct directio_context *)c->context;
+
+ if (!ct)
+ return PATH_UNCHECKED;
+
+ ret = check_state(c->fd, ct, checker_is_sync(c), c->timeout);
+ set_msgid(c, ret);
+
return ret;
}
@@ -323,6 +323,49 @@ static int tur_check_async_timeout(struct checker *c)
return (now.tv_sec > ct->time);
}
+int check_pending(struct checker *c, struct timespec endtime)
+{
+ struct tur_checker_context *ct = c->context;
+ int r, tur_status = PATH_PENDING;
+
+ pthread_mutex_lock(&ct->lock);
+
+ for (r = 0;
+ r == 0 && ct->state == PATH_PENDING &&
+ ct->msgid == MSG_TUR_RUNNING;
+ r = pthread_cond_timedwait(&ct->active, &ct->lock, &endtime));
+
+ if (!r) {
+ tur_status = ct->state;
+ c->msgid = ct->msgid;
+ }
+ pthread_mutex_unlock(&ct->lock);
+ if (tur_status == PATH_PENDING && c->msgid == MSG_TUR_RUNNING) {
+ condlog(4, "%d:%d : tur checker still running",
+ major(ct->devt), minor(ct->devt));
+ } else {
+ int running = uatomic_xchg(&ct->running, 0);
+ if (running)
+ pthread_cancel(ct->thread);
+ ct->thread = 0;
+ }
+
+ return tur_status;
+}
+
+int libcheck_pending(struct checker *c)
+{
+ struct timespec endtime;
+ struct tur_checker_context *ct = c->context;
+
+ /* The if path checker isn't running, just return the exiting value. */
+ if (!ct || !ct->thread)
+ return c->path_state;
+
+ get_monotonic_time(&endtime);
+ return check_pending(c, endtime);
+}
+
int libcheck_check(struct checker * c)
{
struct tur_checker_context *ct = c->context;
@@ -437,27 +480,7 @@ int libcheck_check(struct checker * c)
return tur_check(c->fd, c->timeout, &c->msgid);
}
tur_timeout(&tsp);
- pthread_mutex_lock(&ct->lock);
-
- for (r = 0;
- r == 0 && ct->state == PATH_PENDING &&
- ct->msgid == MSG_TUR_RUNNING;
- r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp));
-
- if (!r) {
- tur_status = ct->state;
- c->msgid = ct->msgid;
- }
- pthread_mutex_unlock(&ct->lock);
- if (tur_status == PATH_PENDING && c->msgid == MSG_TUR_RUNNING) {
- condlog(4, "%d:%d : tur checker still running",
- major(ct->devt), minor(ct->devt));
- } else {
- int running = uatomic_xchg(&ct->running, 0);
- if (running)
- pthread_cancel(ct->thread);
- ct->thread = 0;
- }
+ tur_status = check_pending(c, tsp);
}
return tur_status;