X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fmultipath%2Fmain.c;h=dfaa6867dda84ed34a56504fa83d1a21ddd74499;hb=e41016d3547ef704c0785ba197d36ef69de51260;hp=f62e0f99547b406155b192b2dc497da64634a1e0;hpb=01ff79f58925dd26a717ae78f201d739053b5477;p=elogind.git diff --git a/extras/multipath/main.c b/extras/multipath/main.c index f62e0f995..dfaa6867d 100644 --- a/extras/multipath/main.c +++ b/extras/multipath/main.c @@ -25,153 +25,10 @@ #include #include #include -#include +#include #include "libdevmapper/libdevmapper.h" #include "main.h" - -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; -} - -static void -sprint_wwid(char * buff, const char * str) -{ - int i; - const char *p; - char *cursor; - unsigned char c; - - p = str; - cursor = buff; - for (i = 0; i <= WWID_SIZE / 2 - 1; i++) { - c = *p++; - sprintf(cursor, "%.2x", (int) (unsigned char) c); - cursor += 2; - } - buff[WWID_SIZE - 1] = '\0'; -} - -static void -basename(char * str1, char * str2) -{ - char *p = str1 + (strlen(str1) - 1); - - while (*--p != '/') - continue; - strcpy(str2, ++p); -} - -static int -get_lun_strings(struct env * conf, struct path * mypath) -{ - int fd; - char buff[36]; - char attr_path[FILE_NAME_SIZE]; - char basedev[FILE_NAME_SIZE]; - - if(conf->with_sysfs) { - /* sysfs style */ - basename(mypath->sg_dev, basedev); - - sprintf(attr_path, "%s/block/%s/device/vendor", - conf->sysfs_path, basedev); - if (0 > sysfs_read_attribute_value(attr_path, - mypath->vendor_id, 8)) return 0; - - sprintf(attr_path, "%s/block/%s/device/model", - conf->sysfs_path, basedev); - if (0 > sysfs_read_attribute_value(attr_path, - mypath->product_id, 16)) return 0; - - sprintf(attr_path, "%s/block/%s/device/rev", - conf->sysfs_path, basedev); - if (0 > sysfs_read_attribute_value(attr_path, - mypath->rev, 4)) return 0; - } else { - /* ioctl style */ - if ((fd = open(mypath->sg_dev, O_RDONLY)) < 0) - return 0; - if (0 != do_inq(fd, 0, 0, 0, buff, 36, 1)) - return 0; - memcpy(mypath->vendor_id, &buff[8], 8); - memcpy(mypath->product_id, &buff[16], 16); - memcpy(mypath->rev, &buff[32], 4); - close(fd); - return 1; - } - return 0; -} - -/* hardware vendor specifics : add support for new models below */ - -/* this one get EVPD page 0x83 off 8 */ -/* tested ok with StorageWorks */ -static int -get_evpd_wwid(struct path * mypath) -{ - int fd; - char buff[64]; - - if ((fd = open(mypath->sg_dev, O_RDONLY)) < 0) - return 0; - - if (0 == do_inq(fd, 0, 1, 0x83, buff, sizeof (buff), 1)) { - sprint_wwid(mypath->wwid, &buff[8]); - close(fd); - return 1; /* success */ - } - close(fd); - return 0; /* not good */ -} +#include "devinfo.h" /* White list switch */ static int @@ -182,13 +39,13 @@ get_unique_id(struct path * mypath) char * vendor; char * product; int iopolicy; - int (*getuid) (struct path *); + int (*getuid) (char *, char *); } wlist[] = { - {"COMPAQ ", "HSV110 (C)COMPAQ", MULTIBUS, &get_evpd_wwid}, - {"COMPAQ ", "MSA1000 ", MULTIBUS, &get_evpd_wwid}, - {"COMPAQ ", "MSA1000 VOLUME ", MULTIBUS, &get_evpd_wwid}, - {"DEC ", "HSG80 ", MULTIBUS, &get_evpd_wwid}, - {"HP ", "HSV100 ", MULTIBUS, &get_evpd_wwid}, + {"COMPAQ ", "HSV110 (C)COMPAQ", GROUP_BY_SERIAL, &get_evpd_wwid}, + {"COMPAQ ", "MSA1000 ", GROUP_BY_SERIAL, &get_evpd_wwid}, + {"COMPAQ ", "MSA1000 VOLUME ", GROUP_BY_SERIAL, &get_evpd_wwid}, + {"DEC ", "HSG80 ", GROUP_BY_SERIAL, &get_evpd_wwid}, + {"HP ", "HSV100 ", GROUP_BY_SERIAL, &get_evpd_wwid}, {"HP ", "A6189A ", MULTIBUS, &get_evpd_wwid}, {"HP ", "OPEN- ", MULTIBUS, &get_evpd_wwid}, {"DDN ", "SAN DataDirector", MULTIBUS, &get_evpd_wwid}, @@ -208,7 +65,7 @@ get_unique_id(struct path * mypath) if (strncmp(mypath->vendor_id, wlist[i].vendor, 8) == 0 && strncmp(mypath->product_id, wlist[i].product, 16) == 0) { mypath->iopolicy = wlist[i].iopolicy; - if (!wlist[i].getuid(mypath)) + if (!wlist[i].getuid(mypath->sg_dev, mypath->wwid)) return 0; } } @@ -253,7 +110,7 @@ get_all_paths_sysfs(struct env * conf, struct path * all_paths) char path[FILE_NAME_SIZE]; struct path curpath; - /* if called from hotplug, only consider the paths that relate to */ + /* if called from hotplug, only consider the paths that relate */ /* to the device pointed by conf.hotplugdev */ memset(empty_buff, 0, WWID_SIZE); memset(refwwid, 0, WWID_SIZE); @@ -261,11 +118,19 @@ get_all_paths_sysfs(struct env * conf, struct path * all_paths) sprintf(buff, "%s%s/block", conf->sysfs_path, conf->hotplugdev); memset(conf->hotplugdev, 0, FILE_NAME_SIZE); - readlink(buff, conf->hotplugdev, FILE_NAME_SIZE); + + /* if called from hotplug but with no block, leave */ + if (0 > readlink(buff, conf->hotplugdev, FILE_NAME_SIZE)) + return 0; + basename(conf->hotplugdev, buff); sprintf(curpath.sg_dev, "/dev/%s", buff); - get_lun_strings(conf, &curpath); + get_lun_strings(curpath.vendor_id, + curpath.product_id, + curpath.rev, + curpath.sg_dev); + get_serial(curpath.serial, curpath.sg_dev); if (!get_unique_id(&curpath)) return 0; strcpy(refwwid, curpath.wwid); @@ -297,7 +162,11 @@ get_all_paths_sysfs(struct env * conf, struct path * all_paths) basename(devp->path, buff); sprintf(curpath.sg_dev, "/dev/%s", buff); - get_lun_strings(conf, &curpath); + get_lun_strings(curpath.vendor_id, + curpath.product_id, + curpath.rev, + curpath.sg_dev); + get_serial(curpath.serial, curpath.sg_dev); if(!get_unique_id(&curpath)) { memset(&curpath, 0, sizeof(path)); continue; @@ -345,7 +214,11 @@ get_all_paths_nosysfs(struct env * conf, struct path * all_paths, strncat(file_name, buff, FILE_NAME_SIZE); strcpy(all_paths[k].sg_dev, file_name); - get_lun_strings(conf, &all_paths[k]); + get_lun_strings(all_paths[k].vendor_id, + all_paths[k].product_id, + all_paths[k].rev, + all_paths[k].sg_dev); + get_serial(all_paths[k].serial, all_paths[k].sg_dev); if (!get_unique_id(&all_paths[k])) continue; @@ -480,32 +353,6 @@ print_all_mp(struct path * all_paths, struct multipath * mp, int nmp) } } -static long -get_disk_size (struct env * conf, char * dev) { - long size; - int fd; - char attr_path[FILE_NAME_SIZE]; - char buff[FILE_NAME_SIZE]; - char basedev[FILE_NAME_SIZE]; - - if(conf->with_sysfs) { - basename(dev, basedev); - sprintf(attr_path, "%s/block/%s/size", - conf->sysfs_path, basedev); - if (0 > sysfs_read_attribute_value(attr_path, buff, - FILE_NAME_SIZE * sizeof(char))) - return -1; - size = atoi(buff); - return size; - } else { - if ((fd = open(dev, O_RDONLY)) < 0) - return -1; - if(!ioctl(fd, BLKGETSIZE, &size)) - return size; - } - return -1; -} - static int coalesce_paths(struct env * conf, struct multipath * mp, struct path * all_paths) @@ -524,7 +371,7 @@ coalesce_paths(struct env * conf, struct multipath * mp, if (memcmp(empty_buff, all_paths[k].wwid, WWID_SIZE) == 0) continue; - /* 2. mp with this uid already instanciated */ + /* 2. if mp with this uid already instanciated */ for (i = 0; i <= nmp; i++) { if (0 == strcmp(mp[i].wwid, all_paths[k].wwid)) already_done = 1; @@ -541,7 +388,7 @@ coalesce_paths(struct env * conf, struct multipath * mp, PINDEX(nmp,np) = k; if (mp[nmp].size == 0) - mp[nmp].size = get_disk_size(conf, all_paths[k].dev); + mp[nmp].size = get_disk_size(all_paths[k].dev); for (i = k + 1; i < conf->max_devs; i++) { if (0 == strcmp(all_paths[k].wwid, all_paths[i].wwid)) { @@ -554,44 +401,48 @@ coalesce_paths(struct env * conf, struct multipath * mp, return nmp; } -static int -make_dm_node(char * str) -{ - int r = 0; - char buff[FILE_NAME_SIZE]; - struct dm_names * names; - unsigned next = 0; - struct dm_task *dmt; - - if (!(dmt = dm_task_create(DM_DEVICE_LIST))) - return 0; +static void +group_by_serial(struct multipath * mp, struct path * all_paths, char * str) { + int path_count, pg_count = 0; + int i, k; + int * bitmap; + char path_buff[FILE_NAME_SIZE]; + char pg_buff[FILE_NAME_SIZE]; + char * path_buff_p = &path_buff[0]; + char * pg_buff_p = &pg_buff[0]; + + /* init the bitmap */ + bitmap = malloc((mp->npaths + 1) * sizeof(int)); + memset(bitmap, 0, (mp->npaths + 1) * sizeof(int)); + + for (i = 0; i <= mp->npaths; i++) { + if (bitmap[i]) + continue; - if (!dm_task_run(dmt)) - goto out; + /* here, we really got a new pg */ + pg_count++; + path_count = 1; + memset(&path_buff, 0, FILE_NAME_SIZE * sizeof(char)); + path_buff_p = &path_buff[0]; - if (!(names = dm_task_get_names(dmt))) - goto out; + path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[i]].dev); + bitmap[i] = 1; - if (!names->dev) { - r = 1; - goto out; + for (k = i + 1; k <= mp->npaths; k++) { + if (bitmap[k]) + continue; + if (0 == strcmp(all_paths[mp->pindex[i]].serial, + all_paths[mp->pindex[k]].serial)) { + path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[k]].dev); + bitmap[k] = 1; + path_count++; + } + } + pg_buff_p += sprintf(pg_buff_p, " 1 round-robin %i 0%s", + path_count, path_buff); } - - do { - if (0 == strcmp(names->name, str)) - break; - next = names->next; - names = (void *) names + next; - } while (next); - - sprintf(buff, "/dev/mapper/%s", str); - unlink(buff); - mknod(buff, 0600 | S_IFBLK, names->dev); - - out: - dm_task_destroy(dmt); - return r; - + sprintf(str, " %i%s", pg_count, pg_buff); + free(bitmap); } static int @@ -657,11 +508,9 @@ setup_map(struct env * conf, struct path * all_paths, if (np < 1) return 0; - params_p += sprintf(params_p, "%i", conf->dm_path_test_int); - - if (all_paths[PINDEX(index,0)].iopolicy == MULTIBUS && - !conf->forcedfailover ) { - params_p += sprintf(params_p, " %i %s %i %i", + if ((all_paths[PINDEX(index,0)].iopolicy == MULTIBUS && + conf->iopolicy == -1) || conf->iopolicy == MULTIBUS) { + params_p += sprintf(params_p, " 1 %i %s %i %i", dm_pg_prio, dm_ps_name, np, dm_ps_nr_args); for (i=0; i<=mp[index].npaths; i++) { @@ -672,8 +521,9 @@ setup_map(struct env * conf, struct path * all_paths, } } - if (all_paths[PINDEX(index,0)].iopolicy == FAILOVER || - conf->forcedfailover) { + if ((all_paths[PINDEX(index,0)].iopolicy == FAILOVER && + conf->iopolicy == -1) || conf->iopolicy == FAILOVER) { + params_p += sprintf(params_p, " %i", mp[index].npaths + 1); for (i=0; i<=mp[index].npaths; i++) { if (0 != all_paths[PINDEX(index,i)].sg_id.scsi_type) continue; @@ -686,6 +536,11 @@ setup_map(struct env * conf, struct path * all_paths, } } + if ((all_paths[PINDEX(index,0)].iopolicy == GROUP_BY_SERIAL && + conf->iopolicy == -1) || conf->iopolicy == GROUP_BY_SERIAL) { + group_by_serial(&mp[index], all_paths, params_p); + } + if (mp[index].size < 0) return 0; @@ -706,7 +561,6 @@ setup_map(struct env * conf, struct path * all_paths, if (op == DM_DEVICE_RELOAD) dm_simplecmd(DM_DEVICE_RESUME, mp[index].wwid); - make_dm_node(mp[index].wwid); return 1; } @@ -747,14 +601,19 @@ static void usage(char * progname) { fprintf(stderr, VERSION_STRING); - fprintf(stderr, "Usage: %s [-v|-q] [-d] [-i int] [-m max_devs]\n", + fprintf(stderr, "Usage: %s [-v|-q] [-d] [-m max_devs]", progname); + fprintf(stderr, "[-p failover|multibus|group_by_serial] [device]\n"); + fprintf(stderr, "\t-v\t\tverbose, print all paths and multipaths\n"); + fprintf(stderr, "\t-q\t\tquiet, no output at all\n"); fprintf(stderr, "\t-d\t\tdry run, do not create or update devmaps\n"); - fprintf(stderr, "\t-f\t\tforce maps to failover mode (1 path/pg)\n"); - fprintf(stderr, "\t-i\t\tmultipath target param : polling interval\n"); fprintf(stderr, "\t-m max_devs\tscan {max_devs} devices at most\n"); - fprintf(stderr, "\t-q\t\tquiet, no output at all\n"); - fprintf(stderr, "\t-v\t\tverbose, print all paths and multipaths\n"); + fprintf(stderr, "\t-p policy\tforce maps to specified policy :\n"); + fprintf(stderr, "\t failover\t\t- 1 path per priority group\n"); + fprintf(stderr, "\t multibus\t\t- all paths in 1 priority group\n"); + fprintf(stderr, "\t group_by_serial\t- 1 priority group per serial\n"); + fprintf(stderr, "\tdevice\t\tlimit scope to the device's multipath\n"); + fprintf(stderr, "\t\t\t(hotplug-style $DEVPATH reference)\n"); exit(1); } @@ -772,12 +631,7 @@ main(int argc, char *argv[]) conf.dry_run = 0; /* 1 == Do not Create/Update devmaps */ conf.verbose = 0; /* 1 == Print all_paths and mp */ conf.quiet = 0; /* 1 == Do not even print devmaps */ - conf.with_sysfs = 0; /* Default to compat / suboptimal behaviour */ - conf.dm_path_test_int = 10; - - /* kindly provided by libsysfs */ - if (0 == sysfs_get_mnt_path(conf.sysfs_path, FILE_NAME_SIZE)) - conf.with_sysfs = 1; + conf.iopolicy = -1; /* Apply the defaults in get_unique_id() */ for (i = 1; i < argc; ++i) { if (0 == strcmp("-v", argv[i])) { @@ -794,20 +648,19 @@ main(int argc, char *argv[]) conf.quiet = 1; } else if (0 == strcmp("-d", argv[i])) conf.dry_run = 1; - else if (0 == strcmp("-f", argv[i])) - conf.forcedfailover = 1; - else if (0 == strcmp("-i", argv[i])) - conf.dm_path_test_int = atoi(argv[++i]); - else if (0 == strcmp("scsi", argv[i])) - strcpy(conf.hotplugdev, argv[++i]); - else if (*argv[i] == '-') { + else if (0 == strcmp("-p", argv[i])) { + i++; + if (!strcmp(argv[i], "failover")) + conf.iopolicy = FAILOVER; + if (!strcmp(argv[i], "multibus")) + conf.iopolicy = MULTIBUS; + if (!strcmp(argv[i], "group_by_serial")) + conf.iopolicy = GROUP_BY_SERIAL; + } else if (*argv[i] == '-') { fprintf(stderr, "Unknown switch: %s\n", argv[i]); usage(argv[0]); - } else if (*argv[i] != '-') { - fprintf(stderr, "Unknown argument\n"); - usage(argv[0]); - } - + } else + strncpy(conf.hotplugdev, argv[i], FILE_NAME_SIZE); } /* dynamic allocations */ @@ -817,7 +670,7 @@ main(int argc, char *argv[]) if (mp == NULL || all_paths == NULL || all_scsi_ids == NULL) exit(1); - if (!conf.with_sysfs) { + if (sysfs_get_mnt_path(conf.sysfs_path, FILE_NAME_SIZE)) { get_all_scsi_ids(&conf, all_scsi_ids); get_all_paths_nosysfs(&conf, all_paths, all_scsi_ids); } else {