243 lines
6.7 KiB
Diff
243 lines
6.7 KiB
Diff
|
---
|
||
|
libmultipath/checkers/tur.c | 85 +++++++++++++++++++++++++++++++++-----------
|
||
|
libmultipath/discovery.c | 1
|
||
|
2 files changed, 65 insertions(+), 21 deletions(-)
|
||
|
|
||
|
Index: multipath-tools-120123/libmultipath/checkers/tur.c
|
||
|
===================================================================
|
||
|
--- multipath-tools-120123.orig/libmultipath/checkers/tur.c
|
||
|
+++ multipath-tools-120123/libmultipath/checkers/tur.c
|
||
|
@@ -35,10 +35,15 @@ struct tur_checker_context {
|
||
|
dev_t devt;
|
||
|
int state;
|
||
|
int running;
|
||
|
- time_t timeout;
|
||
|
+ int fd;
|
||
|
+ unsigned int timeout;
|
||
|
+ time_t time;
|
||
|
pthread_t thread;
|
||
|
pthread_mutex_t lock;
|
||
|
pthread_cond_t active;
|
||
|
+ pthread_spinlock_t hldr_lock;
|
||
|
+ int holders;
|
||
|
+ char message[CHECKER_MSG_LEN];
|
||
|
};
|
||
|
|
||
|
#define TUR_DEVT(c) major((c)->devt), minor((c)->devt)
|
||
|
@@ -53,28 +58,49 @@ int libcheck_init (struct checker * c)
|
||
|
memset(ct, 0, sizeof(struct tur_checker_context));
|
||
|
|
||
|
ct->state = PATH_UNCHECKED;
|
||
|
+ ct->fd = -1;
|
||
|
+ ct->holders = 1;
|
||
|
pthread_cond_init(&ct->active, NULL);
|
||
|
pthread_mutex_init(&ct->lock, NULL);
|
||
|
+ pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
|
||
|
c->context = ct;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+void cleanup_context(struct tur_checker_context *ct)
|
||
|
+{
|
||
|
+ pthread_mutex_destroy(&ct->lock);
|
||
|
+ pthread_cond_destroy(&ct->active);
|
||
|
+ pthread_spin_destroy(&ct->hldr_lock);
|
||
|
+ free(ct);
|
||
|
+}
|
||
|
+
|
||
|
void libcheck_free (struct checker * c)
|
||
|
{
|
||
|
if (c->context) {
|
||
|
struct tur_checker_context *ct = c->context;
|
||
|
+ int holders;
|
||
|
+ pthread_t thread;
|
||
|
|
||
|
- pthread_mutex_destroy(&ct->lock);
|
||
|
- pthread_cond_destroy(&ct->active);
|
||
|
- free(c->context);
|
||
|
+ pthread_spin_lock(&ct->hldr_lock);
|
||
|
+ ct->holders--;
|
||
|
+ holders = ct->holders;
|
||
|
+ thread = ct->thread;
|
||
|
+ pthread_spin_unlock(&ct->hldr_lock);
|
||
|
+ if (holders)
|
||
|
+ pthread_cancel(thread);
|
||
|
+ else
|
||
|
+ cleanup_context(ct);
|
||
|
c->context = NULL;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+#define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args);
|
||
|
+
|
||
|
int
|
||
|
-tur_check (struct checker * c)
|
||
|
+tur_check(int fd, unsigned int timeout, char *msg)
|
||
|
{
|
||
|
struct sg_io_hdr io_hdr;
|
||
|
unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
||
|
@@ -90,10 +116,10 @@ tur_check (struct checker * c)
|
||
|
io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
|
io_hdr.cmdp = turCmdBlk;
|
||
|
io_hdr.sbp = sense_buffer;
|
||
|
- io_hdr.timeout = c->timeout;
|
||
|
+ io_hdr.timeout = timeout;
|
||
|
io_hdr.pack_id = 0;
|
||
|
- if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
|
||
|
- MSG(c, MSG_TUR_DOWN);
|
||
|
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
|
+ TUR_MSG(msg, MSG_TUR_DOWN);
|
||
|
return PATH_DOWN;
|
||
|
}
|
||
|
if ((io_hdr.status & 0x7e) == 0x18) {
|
||
|
@@ -101,7 +127,7 @@ tur_check (struct checker * c)
|
||
|
* SCSI-3 arrays might return
|
||
|
* reservation conflict on TUR
|
||
|
*/
|
||
|
- MSG(c, MSG_TUR_UP);
|
||
|
+ TUR_MSG(msg, MSG_TUR_UP);
|
||
|
return PATH_UP;
|
||
|
}
|
||
|
if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
|
@@ -146,14 +172,14 @@ tur_check (struct checker * c)
|
||
|
* LOGICAL UNIT NOT ACCESSIBLE,
|
||
|
* TARGET PORT IN STANDBY STATE
|
||
|
*/
|
||
|
- MSG(c, MSG_TUR_GHOST);
|
||
|
+ TUR_MSG(msg, MSG_TUR_GHOST);
|
||
|
return PATH_GHOST;
|
||
|
}
|
||
|
}
|
||
|
- MSG(c, MSG_TUR_DOWN);
|
||
|
+ TUR_MSG(msg, MSG_TUR_DOWN);
|
||
|
return PATH_DOWN;
|
||
|
}
|
||
|
- MSG(c, MSG_TUR_UP);
|
||
|
+ TUR_MSG(msg, MSG_TUR_UP);
|
||
|
return PATH_UP;
|
||
|
}
|
||
|
|
||
|
@@ -162,18 +188,25 @@ tur_check (struct checker * c)
|
||
|
|
||
|
void cleanup_func(void *data)
|
||
|
{
|
||
|
+ int holders;
|
||
|
struct tur_checker_context *ct = data;
|
||
|
+ pthread_spin_lock(&ct->hldr_lock);
|
||
|
+ ct->holders--;
|
||
|
+ holders = ct->holders;
|
||
|
ct->thread = 0;
|
||
|
+ pthread_spin_unlock(&ct->hldr_lock);
|
||
|
+ if (!holders)
|
||
|
+ cleanup_context(ct);
|
||
|
}
|
||
|
|
||
|
void *tur_thread(void *ctx)
|
||
|
{
|
||
|
- struct checker *c = ctx;
|
||
|
- struct tur_checker_context *ct = c->context;
|
||
|
+ struct tur_checker_context *ct = ctx;
|
||
|
int state;
|
||
|
|
||
|
condlog(3, "%d:%d: tur checker starting up", TUR_DEVT(ct));
|
||
|
|
||
|
+ ct->message[0] = '\0';
|
||
|
/* This thread can be canceled, so setup clean up */
|
||
|
tur_thread_cleanup_push(ct)
|
||
|
|
||
|
@@ -182,7 +215,7 @@ void *tur_thread(void *ctx)
|
||
|
ct->state = PATH_PENDING;
|
||
|
pthread_mutex_unlock(&ct->lock);
|
||
|
|
||
|
- state = tur_check(c);
|
||
|
+ state = tur_check(ct->fd, ct->timeout, ct->message);
|
||
|
|
||
|
/* TUR checker done */
|
||
|
pthread_mutex_lock(&ct->lock);
|
||
|
@@ -213,7 +246,7 @@ void tur_set_async_timeout(struct checke
|
||
|
struct timeval now;
|
||
|
|
||
|
gettimeofday(&now, NULL);
|
||
|
- ct->timeout = now.tv_sec + c->timeout;
|
||
|
+ ct->time = now.tv_sec + c->timeout;
|
||
|
}
|
||
|
|
||
|
int tur_check_async_timeout(struct checker *c)
|
||
|
@@ -222,7 +255,7 @@ int tur_check_async_timeout(struct check
|
||
|
struct timeval now;
|
||
|
|
||
|
gettimeofday(&now, NULL);
|
||
|
- return (now.tv_sec > ct->timeout);
|
||
|
+ return (now.tv_sec > ct->time);
|
||
|
}
|
||
|
|
||
|
extern int
|
||
|
@@ -242,7 +275,7 @@ libcheck_check (struct checker * c)
|
||
|
ct->devt = sb.st_rdev;
|
||
|
|
||
|
if (c->sync)
|
||
|
- return tur_check(c);
|
||
|
+ return tur_check(c->fd, c->timeout, c->message);
|
||
|
|
||
|
/*
|
||
|
* Async mode
|
||
|
@@ -276,6 +309,8 @@ libcheck_check (struct checker * c)
|
||
|
/* TUR checker done */
|
||
|
ct->running = 0;
|
||
|
tur_status = ct->state;
|
||
|
+ strncpy(c->message, ct->message, CHECKER_MSG_LEN);
|
||
|
+ c->message[CHECKER_MSG_LEN - 1] = '\0';
|
||
|
}
|
||
|
pthread_mutex_unlock(&ct->lock);
|
||
|
} else {
|
||
|
@@ -284,24 +319,32 @@ libcheck_check (struct checker * c)
|
||
|
pthread_mutex_unlock(&ct->lock);
|
||
|
condlog(3, "%d:%d: tur thread not responding, "
|
||
|
"using sync mode", TUR_DEVT(ct));
|
||
|
- return tur_check(c);
|
||
|
+ return tur_check(c->fd, c->timeout, c->message);
|
||
|
}
|
||
|
/* Start new TUR checker */
|
||
|
ct->state = PATH_UNCHECKED;
|
||
|
+ ct->fd = c->fd;
|
||
|
+ ct->timeout = c->timeout;
|
||
|
+ pthread_spin_lock(&ct->hldr_lock);
|
||
|
+ ct->holders++;
|
||
|
+ pthread_spin_unlock(&ct->hldr_lock);
|
||
|
tur_set_async_timeout(c);
|
||
|
setup_thread_attr(&attr, 32 * 1024, 1);
|
||
|
- r = pthread_create(&ct->thread, &attr, tur_thread, c);
|
||
|
+ r = pthread_create(&ct->thread, &attr, tur_thread, ct);
|
||
|
if (r) {
|
||
|
pthread_mutex_unlock(&ct->lock);
|
||
|
ct->thread = 0;
|
||
|
+ ct->holders--;
|
||
|
condlog(3, "%d:%d: failed to start tur thread, using"
|
||
|
" sync mode", TUR_DEVT(ct));
|
||
|
- return tur_check(c);
|
||
|
+ return tur_check(c->fd, c->timeout, c->message);
|
||
|
}
|
||
|
pthread_attr_destroy(&attr);
|
||
|
tur_timeout(&tsp);
|
||
|
r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp);
|
||
|
tur_status = ct->state;
|
||
|
+ strncpy(c->message, ct->message,CHECKER_MSG_LEN);
|
||
|
+ c->message[CHECKER_MSG_LEN -1] = '\0';
|
||
|
pthread_mutex_unlock(&ct->lock);
|
||
|
if (ct->thread &&
|
||
|
(tur_status == PATH_PENDING || tur_status == PATH_UNCHECKED)) {
|
||
|
Index: multipath-tools-120123/libmultipath/discovery.c
|
||
|
===================================================================
|
||
|
--- multipath-tools-120123.orig/libmultipath/discovery.c
|
||
|
+++ multipath-tools-120123/libmultipath/discovery.c
|
||
|
@@ -842,6 +842,7 @@ get_state (struct path * pp, int daemon)
|
||
|
}
|
||
|
checker_set_fd(c, pp->fd);
|
||
|
if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
|
||
|
+ memset(c, 0x0, sizeof(struct checker));
|
||
|
condlog(3, "%s: checker init failed", pp->dev);
|
||
|
return PATH_UNCHECKED;
|
||
|
}
|