9 #include <libdevmapper.h>
19 #define FILENAMESIZE 256
20 #define MAPNAMESIZE 64
21 #define TARGETTYPESIZE 16
22 #define PARAMSSIZE 2048
25 #define MULTIPATH "/sbin/multipath"
26 #define PIDFILE "/var/run/multipathd.pid"
31 #define LOG(x, y, z...) if (DEBUG >= x) syslog(x, y, ##z)
37 char mapname[MAPNAMESIZE];
38 int (*checkfn) (char *);
43 pthread_mutex_t *lock;
50 pthread_mutex_t *waiter_lock;
51 char mapname[MAPNAMESIZE];
56 char mapname[MAPNAMESIZE];
60 pthread_mutex_t *event_lock;
61 pthread_cond_t *event;
63 int makenode (char *devnode, int major, int minor)
67 dev = makedev (major, minor);
70 return mknod(devnode, S_IFBLK | S_IRUSR | S_IWUSR, dev);
73 int select_checkfn(struct path *path_p)
75 char devnode[FILENAMESIZE];
82 path_p->checkfn = &readsector0;
84 sprintf (devnode, "/tmp/.select.%i.%i", path_p->major, path_p->minor);
86 r = makenode (devnode, path_p->major, path_p->minor);
89 LOG(2, "[select_checkfn] can not make node %s", devnode);
93 r = get_lun_strings(vendor, product, rev, devnode);
96 LOG(2, "[select_checkfn] can not get strings");
100 r = unlink (devnode);
103 LOG(2, "[select_checkfn] can not unlink %s", devnode);
110 int (*checkfn) (char *);
112 {"COMPAQ ", "HSV110 (C)COMPAQ", &tur},
113 {"COMPAQ ", "MSA1000 ", &tur},
114 {"COMPAQ ", "MSA1000 VOLUME ", &tur},
115 {"DEC ", "HSG80 ", &tur},
116 {"HP ", "HSV100 ", &readsector0},
120 for (i = 0; wlist[i].vendor; i++) {
121 if (strncmp(vendor, wlist[i].vendor, 8) == 0 &&
122 strncmp(product, wlist[i].product, 16) == 0) {
123 path_p->checkfn = wlist[i].checkfn;
130 int get_devmaps (struct devmap *devmaps)
132 struct devmap *devmaps_p;
133 struct dm_task *dmt, *dmt1;
134 struct dm_names *names = NULL;
138 long long start, length;
139 char *target_type = NULL;
142 memset (devmaps, 0, MAXMAPS * sizeof (struct devmap));
144 if (!(dmt = dm_task_create(DM_DEVICE_LIST))) {
149 if (!dm_task_run(dmt)) {
154 if (!(names = dm_task_get_names(dmt))) {
160 LOG (1, "[get_devmaps] no devmap found");
167 /* keep only multipath maps */
169 names = (void *) names + next;
171 LOG (3, "[get_devmaps] iterate on devmap names : %s", names->name);
173 LOG (3, "[get_devmaps] dm_task_create(DM_DEVICE_STATUS)");
174 if (!(dmt1 = dm_task_create(DM_DEVICE_STATUS)))
177 LOG (3, "[get_devmaps] dm_task_set_name(dmt1, names->name)");
178 if (!dm_task_set_name(dmt1, names->name))
181 LOG (3, "[get_devmaps] dm_task_run(dmt1)");
182 if (!dm_task_run(dmt1))
184 LOG (3, "[get_devmaps] DM_DEVICE_STATUS ioctl done");
186 LOG (3, "[get_devmaps] iterate on devmap's targets");
187 nexttgt = dm_get_next_target(dmt1, nexttgt,
194 LOG (3, "[get_devmaps] test target_type existence");
198 LOG (3, "[get_devmaps] test target_type is multipath");
199 if (!strncmp (target_type, "multipath", 9)) {
200 strcpy (devmaps_p->mapname, names->name);
203 /* test vector overflow */
204 if (devmaps_p - devmaps >= MAXMAPS * sizeof (struct devmap)) {
205 LOG (1, "[get_devmaps] devmaps overflow");
206 dm_task_destroy(dmt1);
215 dm_task_destroy(dmt1);
221 dm_task_destroy(dmt);
223 LOG (3, "[get_devmaps] done");
227 int checkpath (struct path *path_p)
229 char devnode[FILENAMESIZE];
232 LOG (2, "[checkpath] checking path %i:%i", path_p->major, path_p->minor);
233 sprintf (devnode, "/tmp/.checker.%i.%i", path_p->major, path_p->minor);
235 if (path_p->checkfn == NULL) {
236 LOG (1, "[checkpath] test function not set for path %i:%i",
237 path_p->major, path_p->minor);
241 r = makenode (devnode, path_p->major, path_p->minor);
244 LOG (2, "[checkpath] can not make node for %s", devnode);
248 r = path_p->checkfn(devnode);
254 int updatepaths (struct devmap *devmaps, struct paths *failedpaths)
257 struct devmap *devmaps_p;
260 long long start, length;
261 char *target_type = NULL;
262 char *params, *p1, *p2;
266 path_p = failedpaths->paths_h;
268 pthread_mutex_lock (failedpaths->lock);
269 memset (failedpaths->paths_h, 0, MAXPATHS * sizeof (struct path));
272 /* ask DM the failed path list */
276 while (*devmaps_p->mapname != 0x0) {
279 if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
282 if (!dm_task_set_name(dmt, devmaps_p->mapname))
285 if (!dm_task_run(dmt))
289 next = dm_get_next_target(dmt, next, &start, &length,
290 &target_type, ¶ms);
292 /* begin ugly parser */
296 /* p2 lags at the begining of the word p1 parses */
298 /* if the current word is a path */
300 /* p1 jumps to path state */
301 while (*p1 != 'A' && *p1 != 'F')
304 /* store path info */
306 path_p->checkfn = NULL;
309 memset (&word, 'O', 6 * sizeof (char));
314 path_p->major = atoi (word);
318 memset (&word, 'O', 6 * sizeof (char));
323 path_p->minor = atoi (word);
325 strcpy (path_p->mapname, devmaps_p->mapname);
328 * discard active paths
329 * don't trust the A status flag : double check
332 !select_checkfn (path_p) &&
333 checkpath (path_p)) {
334 LOG(2, "[updatepaths] discard %i:%i as valid path",
335 path_p->major, path_p->minor);
337 memset (path_p, 0, sizeof(struct path));
343 /* test vector overflow */
344 if (path_p - failedpaths->paths_h >= MAXPATHS * sizeof (struct path)) {
345 LOG (1, "[updatepaths] path_h overflow");
346 pthread_mutex_unlock (failedpaths->lock);
358 dm_task_destroy(dmt);
363 pthread_mutex_unlock (failedpaths->lock);
367 int geteventnr (char *name)
372 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
375 if (!dm_task_set_name(dmt, name))
378 if (!dm_task_run(dmt))
381 if (!dm_task_get_info(dmt, &info))
385 LOG(1, "Device %s does not exist", name);
390 dm_task_destroy(dmt);
392 return info.event_nr;
395 void *waitevent (void * et)
398 struct event_thread *waiter;
400 waiter = (struct event_thread *)et;
401 pthread_mutex_lock (waiter->waiter_lock);
403 event_nr = geteventnr (waiter->mapname);
407 if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
410 if (!dm_task_set_name(dmt, waiter->mapname))
413 if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
419 dm_task_destroy(dmt);
421 /* tell waiterloop we have an event */
422 pthread_mutex_lock (event_lock);
423 pthread_cond_signal(event);
424 pthread_mutex_unlock (event_lock);
426 /* release waiter_lock so that waiterloop knows we are gone */
427 pthread_mutex_unlock (waiter->waiter_lock);
428 pthread_exit(waiter->thread);
433 void *waiterloop (void *ap)
435 struct paths *failedpaths;
436 struct devmap *devmaps, *devmaps_p;
437 struct event_thread *waiters, *waiters_p;
441 failedpaths = (struct paths *)ap;
442 devmaps = malloc (MAXMAPS * sizeof (struct devmap));
443 waiters = malloc (MAXMAPS * sizeof (struct event_thread));
444 memset (waiters, 0, MAXMAPS * sizeof (struct event_thread));
448 /* update devmap list */
449 LOG (1, "[event thread] refresh devmaps list");
450 get_devmaps (devmaps);
452 /* update failed paths list */
453 LOG (1, "[event thread] refresh failpaths list");
454 updatepaths (devmaps, failedpaths);
456 /* start waiters on all devmaps */
457 LOG (1, "[event thread] start up event loops");
461 while (*devmaps_p->mapname != 0x0) {
463 /* find out if devmap already has a running waiter thread */
464 while (*waiters_p->mapname != 0x0) {
465 if (!strcmp (waiters_p->mapname, devmaps_p->mapname))
470 /* no event_thread struct : init it */
471 if (*waiters_p->mapname == 0x0) {
472 strcpy (waiters_p->mapname, devmaps_p->mapname);
473 waiters_p->thread = malloc (sizeof (pthread_t));
474 waiters_p->waiter_lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
475 pthread_mutex_init (waiters_p->waiter_lock, NULL);
478 /* event_thread struct found */
479 if (*waiters_p->mapname != 0x0) {
480 r = pthread_mutex_trylock (waiters_p->waiter_lock);
481 /* thread already running : out */
486 pthread_mutex_unlock (waiters_p->waiter_lock);
489 LOG (1, "[event thread] create event thread for %s", waiters_p->mapname);
490 pthread_create (waiters_p->thread, NULL, waitevent, waiters_p);
496 /* wait event condition */
497 pthread_mutex_lock (event_lock);
498 pthread_cond_wait(event, event_lock);
499 pthread_mutex_unlock (event_lock);
501 LOG (1, "[event thread] event caught");
507 void *checkerloop (void *ap)
509 struct paths *failedpaths;
511 char *cmdargs[4] = {MULTIPATH, "-D", NULL, NULL};
516 failedpaths = (struct paths *)ap;
518 LOG (1, "[checker thread] path checkers start up");
521 path_p = failedpaths->paths_h;
522 pthread_mutex_lock (failedpaths->lock);
523 LOG (2, "[checker thread] checking paths");
524 while (path_p->major != 0) {
526 if (checkpath (path_p)) {
527 LOG (1, "[checker thread] reconfigure %s\n", path_p->mapname);
528 snprintf (major, 5, "%i", path_p->major);
529 snprintf (minor, 5, "%i", path_p->minor);
533 execve (cmdargs[0], cmdargs, NULL);
536 /* MULTIPATH will ask for failedpaths refresh (SIGHUP) */
541 /* test vector overflow */
542 if (path_p - failedpaths->paths_h >= MAXPATHS * sizeof (struct path)) {
543 LOG (1, "[checker thread] path_h overflow");
544 pthread_mutex_unlock (failedpaths->lock);
548 pthread_mutex_unlock (failedpaths->lock);
555 struct paths *initpaths (void)
557 struct paths *failedpaths;
559 failedpaths = malloc (sizeof (struct paths));
560 failedpaths->paths_h = malloc (MAXPATHS * sizeof (struct path));
561 failedpaths->lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
562 pthread_mutex_init (failedpaths->lock, NULL);
563 event = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
564 pthread_cond_init (event, NULL);
565 event_lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
566 pthread_mutex_init (event_lock, NULL);
568 return (failedpaths);
571 void pidfile (pid_t pid)
576 buf = malloc (sizeof (struct stat));
578 if (!stat (PIDFILE, buf)) {
579 LOG(1, "[master thread] already running : out");
588 LOG(1, "[master thread] setsid() error");
592 file = fopen (PIDFILE, "w");
593 fprintf (file, "%d\n", pid);
599 signal_set(int signo, void (*func) (int))
602 struct sigaction sig;
603 struct sigaction osig;
605 sig.sa_handler = func;
606 sigemptyset(&sig.sa_mask);
609 r = sigaction(signo, &sig, &osig);
614 return (osig.sa_handler);
617 void sighup (int sig)
619 LOG (1, "[master thread] SIGHUP caught : refresh devmap list");
621 /* ask for failedpaths refresh */
622 pthread_mutex_lock (event_lock);
623 pthread_cond_signal(event);
624 pthread_mutex_unlock (event_lock);
627 void sigend (int sig)
629 LOG (1, "[master thread] unlink pidfile");
631 LOG (1, "[master thread] --------shut down-------");
635 void signal_init(void)
637 signal_set(SIGHUP, sighup);
638 signal_set(SIGINT, sigend);
639 signal_set(SIGTERM, sigend);
640 signal_set(SIGKILL, sigend);
643 int main (int argc, char *argv[])
645 pthread_t wait, check;
646 struct paths *failedpaths;
655 /* let the parent die happy */
660 openlog (argv[0], 0, LOG_DAEMON);
661 LOG (1, "[master thread] --------start up--------");
666 failedpaths = initpaths ();
668 pthread_create (&wait, NULL, waiterloop, failedpaths);
669 pthread_create (&check, NULL, checkerloop, failedpaths);
670 pthread_join (wait, NULL);
671 pthread_join (check, NULL);