diff options
author | greg@kroah.com <greg@kroah.com> | 2004-03-10 22:40:39 -0800 |
---|---|---|
committer | Greg KH <gregkh@suse.de> | 2005-04-26 21:35:09 -0700 |
commit | a3b37a073d52ff01d4ef023a10f13316da4c9966 (patch) | |
tree | 349bfb87361de4b6d1990b9d5a9283d445b7ea37 /extras/multipath-tools/multipathd | |
parent | 49f9acf3844aa5c004b5794e919bd54166e53227 (diff) |
[PATCH] Added multipath-tools 0.1.1 release
Diffstat (limited to 'extras/multipath-tools/multipathd')
-rw-r--r-- | extras/multipath-tools/multipathd/Makefile | 31 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/checkers.c | 62 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/checkers.h | 2 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/devinfo.c | 82 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/devinfo.h | 15 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/main.c | 674 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/multipathd.init | 42 | ||||
-rw-r--r-- | extras/multipath-tools/multipathd/sg_include.h | 43 |
8 files changed, 951 insertions, 0 deletions
diff --git a/extras/multipath-tools/multipathd/Makefile b/extras/multipath-tools/multipathd/Makefile new file mode 100644 index 0000000000..5bfd58a837 --- /dev/null +++ b/extras/multipath-tools/multipathd/Makefile @@ -0,0 +1,31 @@ +EXEC = multipathd + +CC = gcc +GZIP = /bin/gzip -9 -c + +bindir = /usr/bin +mandir = /usr/share/man/man8 +rcdir = /etc/init.d + +CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -DDEBUG=1 +LDFLAGS = -lpthread -ldevmapper -lsysfs + +OBJS = main.o devinfo.o checkers.o + +$(EXEC): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $(EXEC) + strip $(EXEC) + +install: + install -d $(bindir) + install -m 755 $(EXEC) $(bindir) + install -d $(rcdir) + install -m 755 multipathd.init $(rcdir)/$(EXEC) + +uninstall: + rm -f $(bindir)/$(EXEC) + rm -f $(rcdir)/$(EXEC) + +clean: + rm -f core *.o $(EXEC) *.gz + diff --git a/extras/multipath-tools/multipathd/checkers.c b/extras/multipath-tools/multipathd/checkers.c new file mode 100644 index 0000000000..7ad32b04e9 --- /dev/null +++ b/extras/multipath-tools/multipathd/checkers.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#include "sg_include.h" + +#define TUR_CMD_LEN 6 + +/* + * test IO functions : add yours here + * + * returns 0 : path gone valid + * returns 1 : path still failed + */ + +int readsector0 (char *devnode) +{ + int fd, r; + char buf; + + fd = open (devnode, O_RDONLY); + if (read (fd, &buf, 1) != 1) + r = 0; + else + r = 1; + + close (fd); + + return r; +} + +int tur(char *devnode) +{ + unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; + struct sg_io_hdr io_hdr; + unsigned char sense_buffer[32]; + int fd; + + fd = open (devnode, O_RDONLY); + + memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof (turCmdBlk); + io_hdr.mx_sb_len = sizeof (sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; + io_hdr.pack_id = 0; + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + close(fd); + return 0; + } + if (io_hdr.info & SG_INFO_OK_MASK) { + return 0; + } + return 1; +} diff --git a/extras/multipath-tools/multipathd/checkers.h b/extras/multipath-tools/multipathd/checkers.h new file mode 100644 index 0000000000..057c319d1b --- /dev/null +++ b/extras/multipath-tools/multipathd/checkers.h @@ -0,0 +1,2 @@ +int readsector0 (char *); +int tur (char *); diff --git a/extras/multipath-tools/multipathd/devinfo.c b/extras/multipath-tools/multipathd/devinfo.c new file mode 100644 index 0000000000..46505470f4 --- /dev/null +++ b/extras/multipath-tools/multipathd/devinfo.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include "devinfo.h" +#include "sg_include.h" + +#define FILE_NAME_SIZE 255 + +static int +do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len, int noisy) +{ + unsigned char inqCmdBlk[INQUIRY_CMDLEN] = + { INQUIRY_CMD, 0, 0, 0, 0, 0 }; + unsigned char sense_b[SENSE_BUFF_LEN]; + struct sg_io_hdr io_hdr; + + if (cmddt) + inqCmdBlk[1] |= 2; + if (evpd) + inqCmdBlk[1] |= 1; + inqCmdBlk[2] = (unsigned char) pg_op; + inqCmdBlk[4] = (unsigned char) mx_resp_len; + memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof (inqCmdBlk); + io_hdr.mx_sb_len = sizeof (sense_b); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = mx_resp_len; + io_hdr.dxferp = resp; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_b; + io_hdr.timeout = DEF_TIMEOUT; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("SG_IO (inquiry) error"); + return -1; + } + + /* treat SG_ERR here to get rid of sg_err.[ch] */ + io_hdr.status &= 0x7e; + if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && + (0 == io_hdr.driver_status)) + return 0; + if ((SCSI_CHECK_CONDITION == io_hdr.status) || + (SCSI_COMMAND_TERMINATED == io_hdr.status) || + (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) { + if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) { + int sense_key; + unsigned char * sense_buffer = io_hdr.sbp; + if (sense_buffer[0] & 0x2) + sense_key = sense_buffer[1] & 0xf; + else + sense_key = sense_buffer[2] & 0xf; + if(RECOVERED_ERROR == sense_key) + return 0; + } + } + return -1; +} + +int +get_lun_strings(char * vendor_id, char * product_id, char * rev, char * devname) +{ + int fd; + char buff[36]; + + /* ioctl style */ + if ((fd = open(devname, O_RDONLY)) < 0) + return 1; + if (0 != do_inq(fd, 0, 0, 0, buff, 36, 1)) + return 1; + memcpy(vendor_id, &buff[8], 8); + memcpy(product_id, &buff[16], 16); + memcpy(rev, &buff[32], 4); + close(fd); + + return 0; +} diff --git a/extras/multipath-tools/multipathd/devinfo.h b/extras/multipath-tools/multipathd/devinfo.h new file mode 100644 index 0000000000..46b2894051 --- /dev/null +++ b/extras/multipath-tools/multipathd/devinfo.h @@ -0,0 +1,15 @@ +#define INQUIRY_CMDLEN 6 +#define INQUIRY_CMD 0x12 +#define SENSE_BUFF_LEN 32 +#define DEF_TIMEOUT 60000 +#define RECOVERED_ERROR 0x01 +#define MX_ALLOC_LEN 255 +#define WWID_SIZE 33 +#define BLKGETSIZE _IO(0x12,96) + +/* exerpt from "sg_err.h" */ +#define SCSI_CHECK_CONDITION 0x2 +#define SCSI_COMMAND_TERMINATED 0x22 +#define SG_ERR_DRIVER_SENSE 0x08 + +int get_lun_strings (char *, char *, char *, char *); diff --git a/extras/multipath-tools/multipathd/main.c b/extras/multipath-tools/multipathd/main.c new file mode 100644 index 0000000000..7b5ccfca23 --- /dev/null +++ b/extras/multipath-tools/multipathd/main.c @@ -0,0 +1,674 @@ +#include <string.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <libdevmapper.h> +#include <syslog.h> +#include <signal.h> +#include <wait.h> + +#include "devinfo.h" +#include "checkers.h" + +#define CHECKINT 5 +#define MAXPATHS 2048 +#define FILENAMESIZE 256 +#define MAPNAMESIZE 64 +#define TARGETTYPESIZE 16 +#define PARAMSSIZE 2048 +#define MAXMAPS 512 + +#define MULTIPATH "/sbin/multipath" +#define PIDFILE "/var/run/multipathd.pid" + +#ifndef DEBUG +#define DEBUG 1 +#endif +#define LOG(x, y, z...) if (DEBUG >= x) syslog(x, y, ##z) + +struct path +{ + int major; + int minor; + char mapname[MAPNAMESIZE]; + int (*checkfn) (char *); +}; + +struct paths +{ + pthread_mutex_t *lock; + struct path *paths_h; +}; + +struct event_thread +{ + pthread_t *thread; + pthread_mutex_t *waiter_lock; + char mapname[MAPNAMESIZE]; +}; + +struct devmap +{ + char mapname[MAPNAMESIZE]; +}; + +/* global var */ +pthread_mutex_t *event_lock; +pthread_cond_t *event; + +int makenode (char *devnode, int major, int minor) +{ + dev_t dev; + + dev = makedev (major, minor); + unlink (devnode); + + return mknod(devnode, S_IFBLK | S_IRUSR | S_IWUSR, dev); +} + +int select_checkfn(struct path *path_p) +{ + char devnode[FILENAMESIZE]; + char vendor[8]; + char product[16]; + char rev[4]; + int i, r; + + /* default checkfn */ + path_p->checkfn = &readsector0; + + sprintf (devnode, "/tmp/.select.%i.%i", path_p->major, path_p->minor); + + r = makenode (devnode, path_p->major, path_p->minor); + + if (r < 0) { + LOG(2, "[select_checkfn] can not make node %s", devnode); + return r; + } + + r = get_lun_strings(vendor, product, rev, devnode); + + if (r) { + LOG(2, "[select_checkfn] can not get strings"); + return r; + } + + r = unlink (devnode); + + if (r < 0) { + LOG(2, "[select_checkfn] can not unlink %s", devnode); + return r; + } + + static struct { + char * vendor; + char * product; + int (*checkfn) (char *); + } wlist[] = { + {"COMPAQ ", "HSV110 (C)COMPAQ", &tur}, + {"COMPAQ ", "MSA1000 ", &tur}, + {"COMPAQ ", "MSA1000 VOLUME ", &tur}, + {"DEC ", "HSG80 ", &tur}, + {"HP ", "HSV100 ", &readsector0}, + {NULL, NULL, NULL}, + }; + + for (i = 0; wlist[i].vendor; i++) { + if (strncmp(vendor, wlist[i].vendor, 8) == 0 && + strncmp(product, wlist[i].product, 16) == 0) { + path_p->checkfn = wlist[i].checkfn; + } + } + + return 0; +} + +int get_devmaps (struct devmap *devmaps) +{ + struct devmap *devmaps_p; + struct dm_task *dmt, *dmt1; + struct dm_names *names = NULL; + unsigned next = 0; + void *nexttgt; + int r = 0; + long long start, length; + char *target_type = NULL; + char *params; + + memset (devmaps, 0, MAXMAPS * sizeof (struct devmap)); + + if (!(dmt = dm_task_create(DM_DEVICE_LIST))) { + r = 1; + goto out; + } + + if (!dm_task_run(dmt)) { + r = 1; + goto out; + } + + if (!(names = dm_task_get_names(dmt))) { + r = 1; + goto out; + } + + if (!names->dev) { + LOG (1, "[get_devmaps] no devmap found"); + goto out; + } + + devmaps_p = devmaps; + + do { + /* keep only multipath maps */ + + names = (void *) names + next; + nexttgt = NULL; + LOG (3, "[get_devmaps] iterate on devmap names : %s", names->name); + + LOG (3, "[get_devmaps] dm_task_create(DM_DEVICE_STATUS)"); + if (!(dmt1 = dm_task_create(DM_DEVICE_STATUS))) + goto out1; + + LOG (3, "[get_devmaps] dm_task_set_name(dmt1, names->name)"); + if (!dm_task_set_name(dmt1, names->name)) + goto out1; + + LOG (3, "[get_devmaps] dm_task_run(dmt1)"); + if (!dm_task_run(dmt1)) + goto out1; + LOG (3, "[get_devmaps] DM_DEVICE_STATUS ioctl done"); + do { + LOG (3, "[get_devmaps] iterate on devmap's targets"); + nexttgt = dm_get_next_target(dmt1, nexttgt, + &start, + &length, + &target_type, + ¶ms); + + + LOG (3, "[get_devmaps] test target_type existence"); + if (!target_type) + goto out1; + + LOG (3, "[get_devmaps] test target_type is multipath"); + if (!strncmp (target_type, "multipath", 9)) { + strcpy (devmaps_p->mapname, names->name); + devmaps_p++; + + /* test vector overflow */ + if (devmaps_p - devmaps >= MAXMAPS * sizeof (struct devmap)) { + LOG (1, "[get_devmaps] devmaps overflow"); + dm_task_destroy(dmt1); + r = 1; + goto out; + } + } + + } while (nexttgt); + +out1: + dm_task_destroy(dmt1); + next = names->next; + + } while (next); + +out: + dm_task_destroy(dmt); + + LOG (3, "[get_devmaps] done"); + return r; +} + +int checkpath (struct path *path_p) +{ + char devnode[FILENAMESIZE]; + int r; + + LOG (2, "[checkpath] checking path %i:%i", path_p->major, path_p->minor); + sprintf (devnode, "/tmp/.checker.%i.%i", path_p->major, path_p->minor); + + if (path_p->checkfn == NULL) { + LOG (1, "[checkpath] test function not set for path %i:%i", + path_p->major, path_p->minor); + return 1; + } + + r = makenode (devnode, path_p->major, path_p->minor); + + if (r < 0) { + LOG (2, "[checkpath] can not make node for %s", devnode); + return r; + } + + r = path_p->checkfn(devnode); + unlink (devnode); + + return r; +} + +int updatepaths (struct devmap *devmaps, struct paths *failedpaths) +{ + struct path *path_p; + struct devmap *devmaps_p; + void *next; + struct dm_task *dmt; + long long start, length; + char *target_type = NULL; + char *params, *p1, *p2; + char word[6]; + int i; + + path_p = failedpaths->paths_h; + + pthread_mutex_lock (failedpaths->lock); + memset (failedpaths->paths_h, 0, MAXPATHS * sizeof (struct path)); + + /* first pass */ + /* ask DM the failed path list */ + + devmaps_p = devmaps; + + while (*devmaps_p->mapname != 0x0) { + next = NULL; + + if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) + break; + + if (!dm_task_set_name(dmt, devmaps_p->mapname)) + goto out; + + if (!dm_task_run(dmt)) + goto out; + + do { + next = dm_get_next_target(dmt, next, &start, &length, + &target_type, ¶ms); + + /* begin ugly parser */ + p1 = params; + p2 = params; + while (*p1) { + /* p2 lags at the begining of the word p1 parses */ + while (*p1 != ' ') { + /* if the current word is a path */ + if (*p1 == ':') { + /* p1 jumps to path state */ + while (*p1 != 'A' && *p1 != 'F') + p1++; + + /* store path info */ + + path_p->checkfn = NULL; + + i = 0; + memset (&word, 'O', 6 * sizeof (char)); + while (*p2 != ':') { + word[i++] = *p2; + p2++; + } + path_p->major = atoi (word); + + p2++; + i = 0; + memset (&word, 'O', 6 * sizeof (char)); + while (*p2 != ' ') { + word[i++] = *p2; + p2++; + } + path_p->minor = atoi (word); + + strcpy (path_p->mapname, devmaps_p->mapname); + + /* + * discard active paths + * don't trust the A status flag : double check + */ + if (*p1 == 'A' && + !select_checkfn (path_p) && + checkpath (path_p)) { + LOG(2, "[updatepaths] discard %i:%i as valid path", + path_p->major, path_p->minor); + p1++; + memset (path_p, 0, sizeof(struct path)); + continue; + } + + path_p++; + + /* test vector overflow */ + if (path_p - failedpaths->paths_h >= MAXPATHS * sizeof (struct path)) { + LOG (1, "[updatepaths] path_h overflow"); + pthread_mutex_unlock (failedpaths->lock); + return 1; + } + } + p1++; + } + p2 = p1; + p1++; + } + } while (next); + +out: + dm_task_destroy(dmt); + devmaps_p++; + + } + + pthread_mutex_unlock (failedpaths->lock); + return 0; +} + +int geteventnr (char *name) +{ + struct dm_task *dmt; + struct dm_info info; + + if (!(dmt = dm_task_create(DM_DEVICE_INFO))) + return 0; + + if (!dm_task_set_name(dmt, name)) + goto out; + + if (!dm_task_run(dmt)) + goto out; + + if (!dm_task_get_info(dmt, &info)) + return 0; + + if (!info.exists) { + LOG(1, "Device %s does not exist", name); + return 0; + } + +out: + dm_task_destroy(dmt); + + return info.event_nr; +} + +void *waitevent (void * et) +{ + int event_nr; + struct event_thread *waiter; + + waiter = (struct event_thread *)et; + pthread_mutex_lock (waiter->waiter_lock); + + event_nr = geteventnr (waiter->mapname); + + struct dm_task *dmt; + + if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT))) + return 0; + + if (!dm_task_set_name(dmt, waiter->mapname)) + goto out; + + if (event_nr && !dm_task_set_event_nr(dmt, event_nr)) + goto out; + + dm_task_run(dmt); + +out: + dm_task_destroy(dmt); + + /* tell waiterloop we have an event */ + pthread_mutex_lock (event_lock); + pthread_cond_signal(event); + pthread_mutex_unlock (event_lock); + + /* release waiter_lock so that waiterloop knows we are gone */ + pthread_mutex_unlock (waiter->waiter_lock); + pthread_exit(waiter->thread); + + return (NULL); +} + +void *waiterloop (void *ap) +{ + struct paths *failedpaths; + struct devmap *devmaps, *devmaps_p; + struct event_thread *waiters, *waiters_p; + int r; + + /* inits */ + failedpaths = (struct paths *)ap; + devmaps = malloc (MAXMAPS * sizeof (struct devmap)); + waiters = malloc (MAXMAPS * sizeof (struct event_thread)); + memset (waiters, 0, MAXMAPS * sizeof (struct event_thread)); + + while (1) { + + /* update devmap list */ + LOG (1, "[event thread] refresh devmaps list"); + get_devmaps (devmaps); + + /* update failed paths list */ + LOG (1, "[event thread] refresh failpaths list"); + updatepaths (devmaps, failedpaths); + + /* start waiters on all devmaps */ + LOG (1, "[event thread] start up event loops"); + waiters_p = waiters; + devmaps_p = devmaps; + + while (*devmaps_p->mapname != 0x0) { + + /* find out if devmap already has a running waiter thread */ + while (*waiters_p->mapname != 0x0) { + if (!strcmp (waiters_p->mapname, devmaps_p->mapname)) + break; + waiters_p++; + } + + /* no event_thread struct : init it */ + if (*waiters_p->mapname == 0x0) { + strcpy (waiters_p->mapname, devmaps_p->mapname); + waiters_p->thread = malloc (sizeof (pthread_t)); + waiters_p->waiter_lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t)); + pthread_mutex_init (waiters_p->waiter_lock, NULL); + } + + /* event_thread struct found */ + if (*waiters_p->mapname != 0x0) { + r = pthread_mutex_trylock (waiters_p->waiter_lock); + /* thread already running : out */ + + if (r) + goto out; + + pthread_mutex_unlock (waiters_p->waiter_lock); + } + + LOG (1, "[event thread] create event thread for %s", waiters_p->mapname); + pthread_create (waiters_p->thread, NULL, waitevent, waiters_p); +out: + waiters_p = waiters; + devmaps_p++; + } + + /* wait event condition */ + pthread_mutex_lock (event_lock); + pthread_cond_wait(event, event_lock); + pthread_mutex_unlock (event_lock); + + LOG (1, "[event thread] event caught"); + } + + return (NULL); +} + +void *checkerloop (void *ap) +{ + struct paths *failedpaths; + struct path *path_p; + char *cmdargs[4] = {MULTIPATH, "-D", NULL, NULL}; + char major[5]; + char minor[5]; + int status; + + failedpaths = (struct paths *)ap; + + LOG (1, "[checker thread] path checkers start up"); + + while (1) { + path_p = failedpaths->paths_h; + pthread_mutex_lock (failedpaths->lock); + LOG (2, "[checker thread] checking paths"); + while (path_p->major != 0) { + + if (checkpath (path_p)) { + LOG (1, "[checker thread] reconfigure %s\n", path_p->mapname); + snprintf (major, 5, "%i", path_p->major); + snprintf (minor, 5, "%i", path_p->minor); + cmdargs[2] = major; + cmdargs[3] = minor; + if (fork () == 0) + execve (cmdargs[0], cmdargs, NULL); + + wait (&status); + /* MULTIPATH will ask for failedpaths refresh (SIGHUP) */ + } + + path_p++; + + /* test vector overflow */ + if (path_p - failedpaths->paths_h >= MAXPATHS * sizeof (struct path)) { + LOG (1, "[checker thread] path_h overflow"); + pthread_mutex_unlock (failedpaths->lock); + return (NULL); + } + } + pthread_mutex_unlock (failedpaths->lock); + sleep(CHECKINT); + } + + return (NULL); +} + +struct paths *initpaths (void) +{ + struct paths *failedpaths; + + failedpaths = malloc (sizeof (struct paths)); + failedpaths->paths_h = malloc (MAXPATHS * sizeof (struct path)); + failedpaths->lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t)); + pthread_mutex_init (failedpaths->lock, NULL); + event = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + pthread_cond_init (event, NULL); + event_lock = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t)); + pthread_mutex_init (event_lock, NULL); + + return (failedpaths); +} + +void pidfile (pid_t pid) +{ + FILE *file; + struct stat *buf; + + buf = malloc (sizeof (struct stat)); + + if (!stat (PIDFILE, buf)) { + LOG(1, "[master thread] already running : out"); + free (buf); + exit (1); + } + + umask (022); + pid = setsid (); + + if (pid < -1) { + LOG(1, "[master thread] setsid() error"); + exit (1); + } + + file = fopen (PIDFILE, "w"); + fprintf (file, "%d\n", pid); + fclose (file); + free (buf); +} + +void * +signal_set(int signo, void (*func) (int)) +{ + int r; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset(&sig.sa_mask); + sig.sa_flags = 0; + + r = sigaction(signo, &sig, &osig); + + if (r < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +void sighup (int sig) +{ + LOG (1, "[master thread] SIGHUP caught : refresh devmap list"); + + /* ask for failedpaths refresh */ + pthread_mutex_lock (event_lock); + pthread_cond_signal(event); + pthread_mutex_unlock (event_lock); +} + +void sigend (int sig) +{ + LOG (1, "[master thread] unlink pidfile"); + unlink (PIDFILE); + LOG (1, "[master thread] --------shut down-------"); + exit (0); +} + +void signal_init(void) +{ + signal_set(SIGHUP, sighup); + signal_set(SIGINT, sigend); + signal_set(SIGTERM, sigend); + signal_set(SIGKILL, sigend); +} + +int main (int argc, char *argv[]) +{ + pthread_t wait, check; + struct paths *failedpaths; + pid_t pid; + + pid = fork (); + + /* can't fork */ + if (pid < 0) + exit (1); + + /* let the parent die happy */ + if (pid > 0) + exit (0); + + /* child's play */ + openlog (argv[0], 0, LOG_DAEMON); + LOG (1, "[master thread] --------start up--------"); + + pidfile (pid); + signal_init (); + + failedpaths = initpaths (); + + pthread_create (&wait, NULL, waiterloop, failedpaths); + pthread_create (&check, NULL, checkerloop, failedpaths); + pthread_join (wait, NULL); + pthread_join (check, NULL); + + return 0; +} diff --git a/extras/multipath-tools/multipathd/multipathd.init b/extras/multipath-tools/multipathd/multipathd.init new file mode 100644 index 0000000000..860b2b11db --- /dev/null +++ b/extras/multipath-tools/multipathd/multipathd.init @@ -0,0 +1,42 @@ +#!/bin/sh + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +DAEMON=/usr/bin/multipathd +PIDFILE=/var/run/multipathd.pid + +test -x $DAEMON || exit 0 + +case "$1" in + start) + echo -n "Starting multipath daemon: multipathd" + if start-stop-daemon --quiet --stop --signal 0 --pidfile $PIDFILE --name multipathd + then + echo " already running." + exit + fi + /sbin/start-stop-daemon --start --quiet --exec $DAEMON + echo "." + ;; + stop) + echo -n "Stopping multipath daemon: multipathd" + if start-stop-daemon --quiet --stop --signal 0 --pidfile $PIDFILE --name multipathd + then + PID=`cat $PIDFILE` + start-stop-daemon --quiet --stop --exec $DAEMON --pidfile $PIDFILE --name multipathd + # Now we wait for it to die + while kill -0 $PID 2>/dev/null; do sleep 1; done + echo "." + else + echo " not running."; + fi + ;; + force-reload|restart) + $0 stop + $0 start + ;; + *) + echo "Usage: /etc/init.d/multipathd {start|stop|restart|force-reload}" + exit 1 +esac + +exit 0 diff --git a/extras/multipath-tools/multipathd/sg_include.h b/extras/multipath-tools/multipathd/sg_include.h new file mode 100644 index 0000000000..460506826e --- /dev/null +++ b/extras/multipath-tools/multipathd/sg_include.h @@ -0,0 +1,43 @@ +#ifdef SG_KERNEL_INCLUDES + #define __user + typedef unsigned char u8; + #include "/usr/src/linux/include/scsi/sg.h" + #include "/usr/src/linux/include/scsi/scsi.h" +#else + #ifdef SG_TRICK_GNU_INCLUDES + #include <linux/../scsi/sg.h> + #include <linux/../scsi/scsi.h> + #else + #include <scsi/sg.h> + #endif +#endif + +/* + Getting the correct include files for the sg interface can be an ordeal. + In a perfect world, one would just write: + #include <scsi/sg.h> + #include <scsi/scsi.h> + This would include the files found in the /usr/include/scsi directory. + Those files are maintained with the GNU library which may or may not + agree with the kernel and version of sg driver that is running. Any + many cases this will not matter. However in some it might, for example + glibc 2.1's include files match the sg driver found in the lk 2.2 + series. Hence if glibc 2.1 is used with lk 2.4 then the additional + sg v3 interface will not be visible. + If this is a problem then defining SG_KERNEL_INCLUDES will access the + kernel supplied header files (assuming they are in the normal place). + The GNU library maintainers and various kernel people don't like + this approach (but it does work). + The technique selected by defining SG_TRICK_GNU_INCLUDES worked (and + was used) prior to glibc 2.2 . Prior to that version /usr/include/linux + was a symbolic link to /usr/src/linux/include/linux . + + There are other approaches if this include "mixup" causes pain. These + would involve include files being copied or symbolic links being + introduced. + + Sorry about the inconvenience. Typically neither SG_KERNEL_INCLUDES + nor SG_TRICK_GNU_INCLUDES is defined. + + dpg 20010415, 20030522 +*/ |