--- v1
+++ v2
@@ -1,98 +1,354 @@
-Make the RDAC checker use the async checker framework.
+The TUR checker now just exports the message table and the
+"libcheck_async_func" symbol. This converts it into an instance of
+the generic async checker model.
+
+With this change, struct checker_context isn't used any more and
+can be removed.
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
- libmultipath/checkers/rdac.c | 30 ++++++++++--------------------
- 1 file changed, 10 insertions(+), 20 deletions(-)
+ libmultipath/checkers.h | 3 -
+ libmultipath/checkers/tur.c | 253 +++---------------------------------
+ 2 files changed, 15 insertions(+), 241 deletions(-)
-diff --git a/libmultipath/checkers/rdac.c b/libmultipath/checkers/rdac.c
-index 87b8872..a477fb5 100644
---- a/libmultipath/checkers/rdac.c
-+++ b/libmultipath/checkers/rdac.c
-@@ -1,8 +1,6 @@
- /*
- * Copyright (c) 2005 Christophe Varoqui
+diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
+index 05dbd7c..4846ea9 100644
+--- a/libmultipath/checkers.h
++++ b/libmultipath/checkers.h
+@@ -180,9 +180,6 @@ void checker_set_async (struct checker *);
+ void checker_set_fd (struct checker *, int);
+ void checker_enable (struct checker *);
+ void checker_disable(struct checker *);
+-struct checker_context {
+- struct checker_class *cls;
+-};
+ int checker_get_state(struct checker *c);
+ bool checker_need_wait(struct checker *c);
+ void checker_check (struct checker *, int);
+diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
+index 6791172..62460cb 100644
+--- a/libmultipath/checkers/tur.c
++++ b/libmultipath/checkers/tur.c
+@@ -3,87 +3,29 @@
+ *
+ * Copyright (c) 2004 Christophe Varoqui
*/
--#include <stdio.h>
-#include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-@@ -15,6 +13,7 @@
- #include "debug.h"
-
+-#include <string.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <unistd.h>
+-#include <fcntl.h>
+ #include <sys/ioctl.h>
+-#include <sys/sysmacros.h>
++#include <sys/types.h>
++
+ #include <errno.h>
+-#include <sys/time.h>
+
+ #include "checkers.h"
+-#include "debug.h"
++#include "async_checker.h"
#include "sg_include.h"
-+#include "async_checker.h"
-
- #define INQUIRY_CMDLEN 6
- #define INQUIRY_CMD 0x12
-@@ -55,11 +54,7 @@ struct control_mode_page {
- unsigned char dontcare1[6];
+-#include "runner.h"
+
+ #define TUR_CMD_LEN 6
+ #define HEAVY_CHECK_COUNT 10
+-#define MAX_NR_TIMEOUTS 1
+
+ enum {
+- MSG_TUR_RUNNING = CHECKER_FIRST_MSGID,
+- MSG_TUR_TIMEOUT,
+- MSG_TUR_FAILED,
+- MSG_TUR_TRANSITIONING,
++ MSG_TUR_TRANSITIONING = CHECKER_FIRST_MSGID,
};
--struct rdac_checker_context {
-- void * dummy;
+ #define IDX_(x) (MSG_ ## x - CHECKER_FIRST_MSGID)
+ const char *libcheck_msgtable[] = {
+- [IDX_(TUR_RUNNING)] = " still running",
+- [IDX_(TUR_TIMEOUT)] = " timed out",
+- [IDX_(TUR_FAILED)] = " failed to initialize",
+ [IDX_(TUR_TRANSITIONING)] = " reports path is transitioning",
+ NULL,
+ };
+
+-struct tur_data {
+- int fd;
+- dev_t devt;
+- unsigned int timeout;
+- int state;
+- short msgid;
-};
-
--int libcheck_init (struct checker * c)
-+int libcheck_init(struct checker *c)
- {
- unsigned char cmd[MODE_SEN_SEL_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
-@@ -133,11 +128,6 @@ out:
- return 0;
- }
-
--void libcheck_free(__attribute__((unused)) struct checker *c)
--{
-- return;
--}
--
- static int
- do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len,
- unsigned int timeout)
-@@ -288,15 +278,15 @@ checker_msg_string(const struct volume_access_inq *inq)
- }
- }
-
--int libcheck_check(struct checker * c)
+-struct tur_checker_context {
+- struct checker_context chkr;
+- int last_runner_state;
+- unsigned int nr_timeouts;
+- struct runner_context *rtx;
+- struct tur_data tdata;
+-};
+-
+-int libcheck_init(struct checker *c)
+-{
+- struct tur_checker_context *tcc;
+- struct stat sb;
+-
+- tcc = calloc(1, sizeof(*tcc));
+- tcc->tdata.state = PATH_UNCHECKED;
+- tcc->tdata.fd = -1;
+- if (fstat(c->fd, &sb) == 0)
+- tcc->tdata.devt = sb.st_rdev;
+- tcc->chkr.cls = c->cls;
+- c->context = tcc;
+- return 0;
+-}
+-
+-void libcheck_free (struct checker * c)
+-{
+- struct tur_checker_context *tcc = c->context;
+-
+- if (!tcc)
+- return;
+- c->context = NULL;
+- if (tcc->rtx)
+- release_runner(tcc->rtx);
+- free(tcc);
+-}
+-
+-static int
+-tur_check(int fd, unsigned int timeout, short *msgid)
+int libcheck_async_func(struct runner_data *rdata)
{
- struct volume_access_inq inq;
- int ret, inqfail;
-
- inqfail = 0;
- memset(&inq, 0, sizeof(struct volume_access_inq));
-- ret = do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
-- c->timeout);
-+ ret = do_inq(rdata->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
-+ rdata->timeout);
- if (ret != PATH_UP) {
- inqfail = 1;
- goto done;
-@@ -340,17 +330,17 @@ int libcheck_check(struct checker * c)
- done:
- switch (ret) {
- case PATH_WILD:
-- c->msgid = CHECKER_MSGID_UNSUPPORTED;
-+ rdata->msgid = CHECKER_MSGID_UNSUPPORTED;
- break;
- case PATH_DOWN:
-- c->msgid = (inqfail ? RDAC_MSGID_INQUIRY_FAILED :
-- checker_msg_string(&inq));
-+ rdata->msgid = (inqfail ? RDAC_MSGID_INQUIRY_FAILED
-+ : checker_msg_string(&inq));
- break;
- case PATH_UP:
-- c->msgid = CHECKER_MSGID_UP;
+ struct sg_io_hdr io_hdr;
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+@@ -99,14 +41,14 @@ retry:
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sense_buffer;
+- io_hdr.timeout = timeout * 1000;
++ io_hdr.timeout = rdata->timeout * 1000;
+ io_hdr.pack_id = 0;
+- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
++ if (ioctl(rdata->fd, SG_IO, &io_hdr) < 0) {
+ if (errno == ENOTTY) {
+- *msgid = CHECKER_MSGID_UNSUPPORTED;
++ rdata->msgid = CHECKER_MSGID_UNSUPPORTED;
+ return PATH_WILD;
+ }
+- *msgid = CHECKER_MSGID_DOWN;
++ rdata->msgid = CHECKER_MSGID_DOWN;
+ return PATH_DOWN;
+ }
+ if ((io_hdr.status & 0x7e) == 0x18) {
+@@ -114,7 +56,7 @@ retry:
+ * SCSI-3 arrays might return
+ * reservation conflict on TUR
+ */
+- *msgid = CHECKER_MSGID_UP;
+ rdata->msgid = CHECKER_MSGID_UP;
- break;
- case PATH_GHOST:
-- c->msgid = CHECKER_MSGID_GHOST;
-+ rdata->msgid = CHECKER_MSGID_GHOST;
- break;
+ return PATH_UP;
}
-
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+@@ -159,14 +101,14 @@ retry:
+ * LOGICAL UNIT NOT ACCESSIBLE,
+ * TARGET PORT IN STANDBY STATE
+ */
+- *msgid = CHECKER_MSGID_GHOST;
++ rdata->msgid = CHECKER_MSGID_GHOST;
+ return PATH_GHOST;
+ } else if (asc == 0x04 && ascq == 0x0a) {
+ /*
+ * LOGICAL UNIT NOT ACCESSIBLE,
+ * ASYMMETRIC ACCESS STATE TRANSITION
+ */
+- *msgid = MSG_TUR_TRANSITIONING;
++ rdata->msgid = MSG_TUR_TRANSITIONING;
+ return PATH_PENDING;
+ }
+ } else if (key == 0x5) {
+@@ -176,178 +118,13 @@ retry:
+ * LUN NOT SUPPORTED: unmapped at target.
+ * Signals pp->disconnected, becomes PATH_DOWN.
+ */
+- *msgid = CHECKER_MSGID_DISCONNECTED;
++ rdata->msgid = CHECKER_MSGID_DISCONNECTED;
+ return PATH_DISCONNECTED;
+ }
+ }
+- *msgid = CHECKER_MSGID_DOWN;
++ rdata->msgid = CHECKER_MSGID_DOWN;
+ return PATH_DOWN;
+ }
+- *msgid = CHECKER_MSGID_UP;
++ rdata->msgid = CHECKER_MSGID_UP;
+ return PATH_UP;
+ }
+-
+-/*
+- * Test code for "zombie tur thread" handling.
+- * Compile e.g. with CFLAGS=-DTUR_TEST_MAJOR=8
+- * Additional parameters can be configure with the macros below.
+- *
+- * Everty nth started TUR thread will hang in non-cancellable state
+- * for given number of seconds, for device given by major/minor.
+- */
+-#ifdef TUR_TEST_MAJOR
+-
+-#ifndef TUR_TEST_MINOR
+-#define TUR_TEST_MINOR 0
+-#endif
+-#ifndef TUR_SLEEP_INTERVAL
+-#define TUR_SLEEP_INTERVAL 3
+-#endif
+-#ifndef TUR_SLEEP_SECS
+-#define TUR_SLEEP_SECS 60
+-#endif
+-
+-static void tur_deep_sleep(const struct tur_data *tdata)
+-{
+- static int sleep_cnt;
+- const struct timespec ts = { .tv_sec = TUR_SLEEP_SECS, .tv_nsec = 0 };
+- int oldstate;
+-
+- if (tdata->devt != makedev(TUR_TEST_MAJOR, TUR_TEST_MINOR) ||
+- ++sleep_cnt % TUR_SLEEP_INTERVAL == 0)
+- return;
+-
+- condlog(3, "tur thread going to sleep for %ld seconds", ts.tv_sec);
+- if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0)
+- condlog(0, "pthread_setcancelstate: %m");
+- if (nanosleep(&ts, NULL) != 0)
+- condlog(0, "nanosleep: %m");
+- condlog(3, "tur zombie thread woke up");
+- if (pthread_setcancelstate(oldstate, NULL) != 0)
+- condlog(0, "pthread_setcancelstate (2): %m");
+- pthread_testcancel();
+-}
+-#else
+-#define tur_deep_sleep(x) do {} while (0)
+-#endif /* TUR_TEST_MAJOR */
+-
+-void runner_callback(void *arg)
+-{
+- struct tur_data *tdata = arg;
+- int state;
+-
+- condlog(4, "%d:%d : tur checker starting up", major(tdata->devt),
+- minor(tdata->devt));
+-
+- tur_deep_sleep(tdata);
+- state = tur_check(tdata->fd, tdata->timeout, &tdata->msgid);
+- tdata->state = state;
+- pthread_testcancel();
+- condlog(4, "%d:%d : tur checker finished, state %s", major(tdata->devt),
+- minor(tdata->devt), checker_state_name(state));
+-}
+-
+-static int check_runner_state(struct tur_checker_context *tcc)
+-{
+- struct runner_context *rtx = tcc->rtx;
+- int rc;
+-
+- rc = check_runner(rtx, &tcc->tdata, sizeof(tcc->tdata));
+- switch (rc) {
+- case RUNNER_DEAD:
+- tcc->tdata.state = PATH_TIMEOUT;
+- tcc->tdata.msgid = MSG_TUR_TIMEOUT;
+- /* fallthrough */
+- case RUNNER_DONE:
+- release_runner(tcc->rtx);
+- tcc->rtx = NULL;
+- tcc->last_runner_state = rc;
+- tcc->nr_timeouts = 0;
+- condlog(rc == RUNNER_DONE ? 4 : 3,
+- "%d:%d : tur checker finished, state %s, runner state %s",
+- major(tcc->tdata.devt), minor(tcc->tdata.devt),
+- checker_state_name(tcc->tdata.state),
+- runner_state_name(rc));
+- break;
+- case RUNNER_CANCELLED:
+- tcc->last_runner_state = rc;
+- tcc->tdata.state = PATH_TIMEOUT;
+- tcc->tdata.msgid = MSG_TUR_TIMEOUT;
+- if (tcc->nr_timeouts < MAX_NR_TIMEOUTS) {
+- condlog(3, "%d:%d : tur checker timed out, releasing it",
+- major(tcc->tdata.devt), minor(tcc->tdata.devt));
+- tcc->nr_timeouts++;
+- release_runner(tcc->rtx);
+- tcc->rtx = NULL;
+- } else if (tcc->nr_timeouts == MAX_NR_TIMEOUTS) {
+- tcc->nr_timeouts++;
+- condlog(3, "%d:%d : tur checker timed out, waiting for it",
+- major(tcc->tdata.devt), minor(tcc->tdata.devt));
+- }
+- break;
+- default:
+- condlog(4, "%d:%d : tur checker still running",
+- major(tcc->tdata.devt), minor(tcc->tdata.devt));
+- tcc->tdata.msgid = MSG_TUR_RUNNING;
+- break;
+- }
+- return rc;
+-}
+-
+-bool libcheck_need_wait(struct checker *c)
+-{
+- struct tur_checker_context *ct = c->context;
+-
+- return ct && ct->rtx;
+-}
+-
+-int libcheck_pending(struct checker *c)
+-{
+- struct tur_checker_context *ct = c->context;
+- /* The if path checker isn't running, just return the exiting value. */
+- if (!ct || !ct->rtx)
+- return c->path_state;
+-
+- /* This may nullify ct->rtx */
+- check_runner_state(ct);
+- c->msgid = ct->tdata.msgid;
+- return ct->tdata.state;
+-}
+-
+-int libcheck_check(struct checker * c)
+-{
+- struct tur_checker_context *ct = c->context;
+-
+- if (!ct)
+- return PATH_UNCHECKED;
+-
+- if (checker_is_sync(c))
+- return tur_check(c->fd, c->timeout, &c->msgid);
+-
+- /* Handle the case that the checker just completed */
+- if (ct->rtx) {
+- check_runner_state(ct);
+- c->msgid = ct->tdata.msgid;
+- return ct->tdata.state;
+- }
+-
+- /* create new checker thread */
+- ct->tdata.fd = c->fd;
+- ct->tdata.timeout = c->timeout;
+-
+- ct->tdata.state = PATH_PENDING;
+- ct->tdata.msgid = MSG_TUR_RUNNING;
+- condlog(3, "%d:%d : starting checker", major(ct->tdata.devt),
+- minor(ct->tdata.devt));
+- ct->rtx = get_runner(runner_callback, &ct->tdata, sizeof(ct->tdata),
+- 1000000 * c->timeout);
+-
+- if (ct->rtx) {
+- c->msgid = ct->tdata.msgid;
+- return ct->tdata.state;
+- } else {
+- condlog(3, "%d:%d : failed to start tur thread, using sync mode",
+- major(ct->tdata.devt), minor(ct->tdata.devt));
+- return tur_check(c->fd, c->timeout, &c->msgid);
+- }
+-}
--
2.54.0