From: DongHun Kwak Date: Fri, 14 Jan 2022 04:50:19 +0000 (+0900) Subject: Imported Upstream version 0.8.1 X-Git-Tag: upstream/0.8.1^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7fc32cb096e12e3c01da350906c66161030d5683;p=platform%2Fupstream%2Fmultipath-tools.git Imported Upstream version 0.8.1 --- diff --git a/Makefile.inc b/Makefile.inc index fc728ca..56c3eda 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -36,8 +36,13 @@ ifndef RUN endif ifndef SYSTEMD - ifeq ($(shell systemctl --version > /dev/null 2>&1 && echo 1), 1) - SYSTEMD = $(shell systemctl --version 2> /dev/null | sed -n 's/systemd \([0-9]*\)/\1/p') + ifeq ($(shell pkg-config --modversion libsystemd >/dev/null 2>&1 && echo 1), 1) + SYSTEMD = $(shell pkg-config --modversion libsystemd) + else + ifeq ($(shell systemctl --version >/dev/null 2>&1 && echo 1), 1) + SYSTEMD = $(shell systemctl --version 2> /dev/null | \ + sed -n 's/systemd \([0-9]*\).*/\1/p') + endif endif endif diff --git a/libmultipath/config.c b/libmultipath/config.c index 24d71ae..141f092 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c @@ -715,7 +715,6 @@ load_config (char * file) conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES; conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; - conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS; conf->remove_retries = 0; conf->ghost_delay = DEFAULT_GHOST_DELAY; conf->all_tg_pt = DEFAULT_ALL_TG_PT; diff --git a/libmultipath/config.h b/libmultipath/config.h index b938c26..f5bf5b1 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -182,7 +182,6 @@ struct config { int delayed_reconfig; int uev_wait_timeout; int skip_kpartx; - int disable_changed_wwids; int remove_retries; int max_sectors_kb; int ghost_delay; diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index 3294bd4..2e79667 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -746,7 +746,7 @@ out_task: dm_task_destroy(dmt); out: if (r < 0) - condlog(2, "%s: dm command failed in %s", name, __FUNCTION__); + condlog(3, "%s: dm command failed in %s: %s", name, __FUNCTION__, strerror(errno)); return r; } diff --git a/libmultipath/dict.c b/libmultipath/dict.c index eaad4f1..96815f8 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -156,6 +156,12 @@ out: return len; } +static int +print_ignored (char *buff, int len) +{ + return snprintf(buff, len, "ignored"); +} + static int print_yes_no (char *buff, int len, long v) { @@ -548,9 +554,15 @@ declare_hw_handler(skip_kpartx, set_yes_no_undef) declare_hw_snprint(skip_kpartx, print_yes_no_undef) declare_mp_handler(skip_kpartx, set_yes_no_undef) declare_mp_snprint(skip_kpartx, print_yes_no_undef) - -declare_def_handler(disable_changed_wwids, set_yes_no) -declare_def_snprint(disable_changed_wwids, print_yes_no) +static int def_disable_changed_wwids_handler(struct config *conf, vector strvec) +{ + return 0; +} +static int snprint_def_disable_changed_wwids(struct config *conf, char *buff, + int len, const void *data) +{ + return print_ignored(buff, len); +} declare_def_handler(remove_retries, set_int) declare_def_snprint(remove_retries, print_int) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 10bd8cd..00ffd06 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -218,12 +218,11 @@ declare_sysfs_get_str(vendor); declare_sysfs_get_str(model); declare_sysfs_get_str(rev); -ssize_t -sysfs_get_vpd (struct udev_device * udev, int pg, - unsigned char * buff, size_t len) +static ssize_t +sysfs_get_binary (struct udev_device * udev, const char *attrname, + unsigned char *buff, size_t len) { ssize_t attr_len; - char attrname[9]; const char * devname; if (!udev) { @@ -232,7 +231,6 @@ sysfs_get_vpd (struct udev_device * udev, int pg, } devname = udev_device_get_sysname(udev); - sprintf(attrname, "vpd_pg%02x", pg); attr_len = sysfs_bin_attr_get_value(udev, attrname, buff, len); if (attr_len < 0) { condlog(3, "%s: attribute %s not found in sysfs", @@ -242,8 +240,23 @@ sysfs_get_vpd (struct udev_device * udev, int pg, return attr_len; } +ssize_t sysfs_get_vpd(struct udev_device * udev, unsigned char pg, + unsigned char *buff, size_t len) +{ + char attrname[9]; + + snprintf(attrname, sizeof(attrname), "vpd_pg%02x", pg); + return sysfs_get_binary(udev, attrname, buff, len); +} + +ssize_t sysfs_get_inquiry(struct udev_device * udev, + unsigned char *buff, size_t len) +{ + return sysfs_get_binary(udev, "inquiry", buff, len); +} + int -sysfs_get_timeout(struct path *pp, unsigned int *timeout) +sysfs_get_timeout(const struct path *pp, unsigned int *timeout) { const char *attr = NULL; const char *subsys; @@ -820,24 +833,34 @@ get_serial (char * str, int maxlen, int fd) } static void -detect_alua(struct path * pp, struct config *conf) +detect_alua(struct path * pp) { int ret; int tpgs; - unsigned int timeout = conf->checker_timeout; + unsigned int timeout; - if ((tpgs = get_target_port_group_support(pp->fd, timeout)) <= 0) { + if (sysfs_get_timeout(pp, &timeout) <= 0) + timeout = DEF_TIMEOUT; + + if ((tpgs = get_target_port_group_support(pp, timeout)) <= 0) { pp->tpgs = TPGS_NONE; return; } ret = get_target_port_group(pp, timeout); - if (ret < 0 || get_asymmetric_access_state(pp->fd, ret, timeout) < 0) { + if (ret < 0 || get_asymmetric_access_state(pp, ret, timeout) < 0) { pp->tpgs = TPGS_NONE; return; } pp->tpgs = tpgs; } +int path_get_tpgs(struct path *pp) +{ + if (pp->tpgs == TPGS_UNDEF) + detect_alua(pp); + return pp->tpgs; +} + #define DEFAULT_SGIO_LEN 254 /* Query VPD page @pg. Returns number of INQUIRY bytes @@ -1505,9 +1528,6 @@ scsi_ioctl_pathinfo (struct path * pp, struct config *conf, int mask) struct udev_device *parent; const char *attr_path = NULL; - if (pp->tpgs == TPGS_UNDEF) - detect_alua(pp, conf); - if (!(mask & DI_SERIAL)) return; @@ -1754,21 +1774,15 @@ get_vpd_uid(struct path * pp) return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE); } -static ssize_t scsi_uid_fallback(struct path *pp, int path_state, - const char **origin) +static ssize_t uid_fallback(struct path *pp, int path_state, + const char **origin) { - ssize_t len = 0; - int retrigger; - struct config *conf; + ssize_t len = -1; - conf = get_multipath_config(); - retrigger = conf->retrigger_tries; - put_multipath_config(conf); - if (pp->retriggers >= retrigger && + if (pp->bus == SYSFS_BUS_SCSI && !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { len = get_vpd_uid(pp); *origin = "sysfs"; - pp->uid_attribute = NULL; if (len < 0 && path_state == PATH_UP) { condlog(1, "%s: failed to get sysfs uid: %s", pp->dev, strerror(-len)); @@ -1776,17 +1790,42 @@ static ssize_t scsi_uid_fallback(struct path *pp, int path_state, WWID_SIZE); *origin = "sgio"; } + } else if (pp->bus == SYSFS_BUS_NVME) { + char value[256]; + len = sysfs_attr_get_value(pp->udev, "wwid", value, + sizeof(value)); + if (len <= 0) + return -1; + len = strlcpy(pp->wwid, value, WWID_SIZE); + if (len >= WWID_SIZE) { + len = fix_broken_nvme_wwid(pp, value, + WWID_SIZE); + if (len > 0) + return len; + condlog(0, "%s: wwid overflow", pp->dev); + len = WWID_SIZE; + } + *origin = "sysfs"; } return len; } +static int has_uid_fallback(struct path *pp) +{ + return ((pp->bus == SYSFS_BUS_SCSI && + !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) || + pp->bus == SYSFS_BUS_NVME); +} + int -get_uid (struct path * pp, int path_state, struct udev_device *udev) +get_uid (struct path * pp, int path_state, struct udev_device *udev, + int allow_fallback) { char *c; const char *origin = "unknown"; ssize_t len = 0; struct config *conf; + int used_fallback = 0; if (!pp->uid_attribute && !pp->getuid) { conf = get_multipath_config(); @@ -1827,8 +1866,10 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) len = get_vpd_uid(pp); origin = "sysfs"; } - if (len <= 0 && pp->bus == SYSFS_BUS_SCSI) - len = scsi_uid_fallback(pp, path_state, &origin); + if (len <= 0 && allow_fallback && has_uid_fallback(pp)) { + used_fallback = 1; + len = uid_fallback(pp, path_state, &origin); + } } if ( len < 0 ) { condlog(1, "%s: failed to get %s uid: %s", @@ -1844,7 +1885,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) c--; } } - condlog(3, "%s: uid = %s (%s)", pp->dev, + condlog((used_fallback)? 1 : 3, "%s: uid = %s (%s)", pp->dev, *pp->wwid == '\0' ? "" : pp->wwid, origin); return 0; } @@ -1914,11 +1955,12 @@ int pathinfo(struct path *pp, struct config *conf, int mask) if (path_state == PATH_REMOVED) goto blank; else if (mask & DI_NOIO) { - /* - * Avoid any IO on the device itself. - * Behave like DI_CHECKER in the "path unavailable" case. - */ - pp->chkrstate = pp->state = path_state; + if (mask & DI_CHECKER) + /* + * Avoid any IO on the device itself. + * simply use the path_offline() return as its state + */ + pp->chkrstate = pp->state = path_state; return PATHINFO_OK; } @@ -1945,8 +1987,11 @@ int pathinfo(struct path *pp, struct config *conf, int mask) if (mask & DI_CHECKER) { if (path_state == PATH_UP) { - pp->chkrstate = pp->state = get_state(pp, conf, 0, - path_state); + int newstate = get_state(pp, conf, 0, path_state); + if (newstate != PATH_PENDING || + pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + pp->chkrstate = pp->state = newstate; if (pp->state == PATH_TIMEOUT) pp->state = PATH_DOWN; if (pp->state == PATH_UP && !pp->size) { @@ -1964,7 +2009,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask) } if ((mask & DI_WWID) && !strlen(pp->wwid)) { - get_uid(pp, path_state, pp->udev); + get_uid(pp, path_state, pp->udev, + (pp->retriggers >= conf->retrigger_tries)); if (!strlen(pp->wwid)) { if (pp->bus == SYSFS_BUS_UNDEF) return PATHINFO_SKIPPED; diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h index 9aacf75..8d04c2a 100644 --- a/libmultipath/discovery.h +++ b/libmultipath/discovery.h @@ -31,7 +31,7 @@ struct config; int path_discovery (vector pathvec, int flag); - +int path_get_tpgs(struct path *pp); /* This function never returns TPGS_UNDEF */ int do_tur (char *); int path_offline (struct path *); int get_state (struct path * pp, struct config * conf, int daemon, int state); @@ -43,16 +43,19 @@ int store_pathinfo (vector pathvec, struct config *conf, struct udev_device *udevice, int flag, struct path **pp_ptr); int sysfs_set_scsi_tmo (struct multipath *mpp, int checkint); -int sysfs_get_timeout(struct path *pp, unsigned int *timeout); +int sysfs_get_timeout(const struct path *pp, unsigned int *timeout); int sysfs_get_host_pci_name(const struct path *pp, char *pci_name); int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address); int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name); -ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff, - size_t len); +ssize_t sysfs_get_vpd (struct udev_device *udev, unsigned char pg, + unsigned char *buff, size_t len); +ssize_t sysfs_get_inquiry(struct udev_device *udev, + unsigned char *buff, size_t len); int sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen); -int get_uid(struct path * pp, int path_state, struct udev_device *udev); +int get_uid(struct path * pp, int path_state, struct udev_device *udev, + int allow_fallback); /* * discovery bitmask diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index d3a8d9b..1d96433 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -604,7 +604,7 @@ static struct hwentry default_hw[] = { .pgpolicy = MULTIBUS, }, { - /* Storwize family / SAN Volume Controller / Flex System V7000 / FlashSystem V840/V9000 */ + /* Storwize family / SAN Volume Controller / Flex System V7000 / FlashSystem V840/V9000/9100 */ .vendor = "IBM", .product = "^2145", .no_path_retry = NO_PATH_RETRY_QUEUE, @@ -701,6 +701,26 @@ static struct hwentry default_hw[] = { .no_path_retry = (300 / DEFAULT_CHECKINT), .prio_name = PRIO_ALUA, }, + /* + * Lenovo + */ + { + /* + * DE Series + * + * Maintainer: ng-eseries-upstream-maintainers@netapp.com + */ + .vendor = "LENOVO", + .product = "DE_Series", + .bl_product = "Universal Xport", + .pgpolicy = GROUP_BY_PRIO, + .checker_name = RDAC, + .features = "2 pg_init_retries 50", + .hwhandler = "1 rdac", + .prio_name = PRIO_RDAC, + .pgfailback = -FAILBACK_IMMEDIATE, + .no_path_retry = 30, + }, /* * NetApp */ @@ -719,6 +739,7 @@ static struct hwentry default_hw[] = { .flush_on_last_del = FLUSH_ENABLED, .dev_loss = MAX_DEV_LOSS_TMO, .prio_name = PRIO_ONTAP, + .user_friendly_names = USER_FRIENDLY_NAMES_OFF, }, { /* @@ -1099,31 +1120,7 @@ static struct hwentry default_hw[] = { .no_path_retry = 30, }, /* - * Xiotech - */ - { - /* Intelligent Storage Elements family */ - .vendor = "(XIOTECH|XIOtech)", - .product = "ISE", - .pgpolicy = MULTIBUS, - .no_path_retry = 12, - }, - { - /* iglu blaze family */ - .vendor = "(XIOTECH|XIOtech)", - .product = "IGLU DISK", - .pgpolicy = MULTIBUS, - .no_path_retry = 30, - }, - { - /* Magnitude family */ - .vendor = "(XIOTECH|XIOtech)", - .product = "Magnitude", - .pgpolicy = MULTIBUS, - .no_path_retry = 30, - }, - /* - * Violin Memory + * Violin Systems */ { /* 3000 / 6000 Series */ @@ -1148,6 +1145,28 @@ static struct hwentry default_hw[] = { .product = "CONCERTO ARRAY", .pgpolicy = MULTIBUS, .no_path_retry = 30, + }, + /* Xiotech */ + { + /* Intelligent Storage Elements family */ + .vendor = "(XIOTECH|XIOtech)", + .product = "ISE", + .pgpolicy = MULTIBUS, + .no_path_retry = 12, + }, + { + /* iglu blaze family */ + .vendor = "(XIOTECH|XIOtech)", + .product = "IGLU DISK", + .pgpolicy = MULTIBUS, + .no_path_retry = 30, + }, + { + /* Magnitude family */ + .vendor = "(XIOTECH|XIOtech)", + .product = "Magnitude", + .pgpolicy = MULTIBUS, + .no_path_retry = 30, }, /* * Promise Technology diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c index 02b1453..554b777 100644 --- a/libmultipath/io_err_stat.c +++ b/libmultipath/io_err_stat.c @@ -41,7 +41,7 @@ #define CONCUR_NR_EVENT 32 #define PATH_IO_ERR_IN_CHECKING -1 -#define PATH_IO_ERR_IN_POLLING_RECHECK -2 +#define PATH_IO_ERR_WAITING_TO_CHECK -2 #define io_err_stat_log(prio, fmt, args...) \ condlog(prio, "io error statistic: " fmt, ##args) @@ -254,7 +254,6 @@ static void free_io_err_pathvec(struct io_err_stat_pathvec *p) * return value * 0: enqueue OK * 1: fails because of internal error - * 2: fails because of existing already */ static int enqueue_io_err_stat_by_path(struct path *path) { @@ -264,7 +263,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) p = find_err_path_by_dev(paths->pathvec, path->dev); if (p) { pthread_mutex_unlock(&paths->mutex); - return 2; + return 0; } pthread_mutex_unlock(&paths->mutex); @@ -284,24 +283,6 @@ static int enqueue_io_err_stat_by_path(struct path *path) vector_set_slot(paths->pathvec, p); pthread_mutex_unlock(&paths->mutex); - if (!path->io_err_disable_reinstate) { - /* - *fail the path in the kernel for the time of the to make - *the test more reliable - */ - io_err_stat_log(3, "%s: fail dm path %s before checking", - path->mpp->alias, path->dev); - path->io_err_disable_reinstate = 1; - dm_fail_path(path->mpp->alias, path->dev_t); - update_queue_mode_del_path(path->mpp); - - /* - * schedule path check as soon as possible to - * update path state to delayed state - */ - path->tick = 1; - - } io_err_stat_log(2, "%s: enqueue path %s to check", path->mpp->alias, path->dev); return 0; @@ -318,7 +299,6 @@ free_ioerr_path: int io_err_stat_handle_pathfail(struct path *path) { struct timespec curr_time; - int res; if (uatomic_read(&io_err_thread_running) == 0) return 1; @@ -333,8 +313,6 @@ int io_err_stat_handle_pathfail(struct path *path) if (!path->mpp) return 1; - if (path->mpp->nr_active <= 1) - return 1; if (path->mpp->marginal_path_double_failed_time <= 0 || path->mpp->marginal_path_err_sample_time <= 0 || path->mpp->marginal_path_err_recheck_gap_time <= 0 || @@ -372,17 +350,33 @@ int io_err_stat_handle_pathfail(struct path *path) } path->io_err_pathfail_cnt++; if (path->io_err_pathfail_cnt >= FLAKY_PATHFAIL_THRESHOLD) { - res = enqueue_io_err_stat_by_path(path); - if (!res) - path->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; - else - path->io_err_pathfail_cnt = 0; + path->io_err_disable_reinstate = 1; + path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; + /* enqueue path as soon as it comes up */ + path->io_err_dis_reinstate_time = 0; + if (path->state != PATH_DOWN) { + struct config *conf; + int oldstate = path->state; + int checkint; + + conf = get_multipath_config(); + checkint = conf->checkint; + put_multipath_config(conf); + io_err_stat_log(2, "%s: mark as failed", path->dev); + path->mpp->stat_path_failures++; + path->state = PATH_DOWN; + path->dmstate = PSTATE_FAILED; + if (oldstate == PATH_UP || oldstate == PATH_GHOST) + update_queue_mode_del_path(path->mpp); + if (path->tick > checkint) + path->tick = checkint; + } } return 0; } -int hit_io_err_recheck_time(struct path *pp) +int need_io_err_check(struct path *pp) { struct timespec curr_time; int r; @@ -393,7 +387,7 @@ int hit_io_err_recheck_time(struct path *pp) io_err_stat_log(2, "%s: recover path early", pp->dev); goto recover; } - if (pp->io_err_pathfail_cnt != PATH_IO_ERR_IN_POLLING_RECHECK) + if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) return 1; if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 || (curr_time.tv_sec - pp->io_err_dis_reinstate_time) > @@ -401,13 +395,6 @@ int hit_io_err_recheck_time(struct path *pp) io_err_stat_log(4, "%s: reschedule checking after %d seconds", pp->dev, pp->mpp->marginal_path_err_recheck_gap_time); - /* - * to reschedule io error checking again - * if the path is good enough, we claim it is good - * and can be reinsated as soon as possible in the - * check_path routine. - */ - pp->io_err_dis_reinstate_time = curr_time.tv_sec; r = enqueue_io_err_stat_by_path(pp); /* * Enqueue fails because of internal error. @@ -418,9 +405,8 @@ int hit_io_err_recheck_time(struct path *pp) io_err_stat_log(3, "%s: enqueue fails, to recover", pp->dev); goto recover; - } else if (!r) { + } else pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; - } } return 1; @@ -428,7 +414,6 @@ int hit_io_err_recheck_time(struct path *pp) recover: pp->io_err_pathfail_cnt = 0; pp->io_err_disable_reinstate = 0; - pp->tick = 1; return 0; } @@ -496,10 +481,10 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) */ path->tick = 1; - } else if (path->mpp && path->mpp->nr_active > 1) { + } else if (path->mpp && path->mpp->nr_active > 0) { io_err_stat_log(3, "%s: keep failing the dm path %s", path->mpp->alias, path->dev); - path->io_err_pathfail_cnt = PATH_IO_ERR_IN_POLLING_RECHECK; + path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; path->io_err_disable_reinstate = 1; path->io_err_dis_reinstate_time = currtime.tv_sec; io_err_stat_log(3, "%s: disable reinstating of %s", diff --git a/libmultipath/io_err_stat.h b/libmultipath/io_err_stat.h index bbf31b4..53d6d7d 100644 --- a/libmultipath/io_err_stat.h +++ b/libmultipath/io_err_stat.h @@ -10,6 +10,6 @@ extern pthread_attr_t io_err_stat_attr; int start_io_err_stat_thread(void *data); void stop_io_err_stat_thread(void); int io_err_stat_handle_pathfail(struct path *path); -int hit_io_err_recheck_time(struct path *pp); +int need_io_err_check(struct path *pp); #endif /* _IO_ERR_STAT_H */ diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile index 4d80c20..9d0fe03 100644 --- a/libmultipath/prioritizers/Makefile +++ b/libmultipath/prioritizers/Makefile @@ -28,9 +28,6 @@ endif all: $(LIBS) -libprioalua.so: alua.o alua_rtpg.o - $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ - libpriopath_latency.so: path_latency.o ../checkers/libsg.o $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm diff --git a/libmultipath/prioritizers/alua.c b/libmultipath/prioritizers/alua.c index b24e2d4..0ab06e2 100644 --- a/libmultipath/prioritizers/alua.c +++ b/libmultipath/prioritizers/alua.c @@ -58,7 +58,7 @@ get_alua_info(struct path * pp, unsigned int timeout) tpg = get_target_port_group(pp, timeout); if (tpg < 0) { - rc = get_target_port_group_support(pp->fd, timeout); + rc = get_target_port_group_support(pp, timeout); if (rc < 0) return -ALUA_PRIO_TPGS_FAILED; if (rc == TPGS_NONE) @@ -66,7 +66,7 @@ get_alua_info(struct path * pp, unsigned int timeout) return -ALUA_PRIO_RTPG_FAILED; } condlog(3, "%s: reported target port group is %i", pp->dev, tpg); - rc = get_asymmetric_access_state(pp->fd, tpg, timeout); + rc = get_asymmetric_access_state(pp, tpg, timeout); if (rc < 0) { condlog(2, "%s: get_asymmetric_access_state returned %d", __func__, rc); diff --git a/libmultipath/prioritizers/alua_rtpg.c b/libmultipath/prioritizers/alua_rtpg.c index 811ce7a..271a019 100644 --- a/libmultipath/prioritizers/alua_rtpg.c +++ b/libmultipath/prioritizers/alua_rtpg.c @@ -135,9 +135,9 @@ scsi_error(struct sg_io_hdr *hdr, int opcode) /* * Helper function to setup and run a SCSI inquiry command. */ -int -do_inquiry(int fd, int evpd, unsigned int codepage, - void *resp, int resplen, unsigned int timeout) +static int +do_inquiry_sg(int fd, int evpd, unsigned int codepage, + void *resp, int resplen, unsigned int timeout) { struct inquiry_command cmd; struct sg_io_hdr hdr; @@ -185,18 +185,41 @@ retry: return 0; } +int do_inquiry(const struct path *pp, int evpd, unsigned int codepage, + void *resp, int resplen, unsigned int timeout) +{ + struct udev_device *ud; + + ud = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", + "scsi_device"); + if (ud != NULL) { + int rc; + + if (!evpd) + rc = sysfs_get_inquiry(ud, resp, resplen); + else + rc = sysfs_get_vpd(ud, codepage, resp, resplen); + + if (rc >= 0) { + PRINT_HEX((unsigned char *) resp, resplen); + return 0; + } + } + return do_inquiry_sg(pp->fd, evpd, codepage, resp, resplen, timeout); +} + /* * This function returns the support for target port groups by evaluating the * data returned by the standard inquiry command. */ int -get_target_port_group_support(int fd, unsigned int timeout) +get_target_port_group_support(const struct path *pp, unsigned int timeout) { struct inquiry_data inq; int rc; memset((unsigned char *)&inq, 0, sizeof(inq)); - rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq), timeout); + rc = do_inquiry(pp, 0, 0x00, &inq, sizeof(inq), timeout); if (!rc) { rc = inquiry_data_get_tpgs(&inq); } @@ -205,7 +228,7 @@ get_target_port_group_support(int fd, unsigned int timeout) } static int -get_sysfs_pg83(struct path *pp, unsigned char *buff, int buflen) +get_sysfs_pg83(const struct path *pp, unsigned char *buff, int buflen) { struct udev_device *parent = pp->udev; @@ -224,7 +247,7 @@ get_sysfs_pg83(struct path *pp, unsigned char *buff, int buflen) } int -get_target_port_group(struct path * pp, unsigned int timeout) +get_target_port_group(const struct path * pp, unsigned int timeout) { unsigned char *buf; struct vpd83_data * vpd83; @@ -245,7 +268,7 @@ get_target_port_group(struct path * pp, unsigned int timeout) rc = get_sysfs_pg83(pp, buf, buflen); if (rc < 0) { - rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen, timeout); + rc = do_inquiry(pp, 1, 0x83, buf, buflen, timeout); if (rc < 0) goto out; @@ -263,7 +286,7 @@ get_target_port_group(struct path * pp, unsigned int timeout) } buflen = scsi_buflen; memset(buf, 0, buflen); - rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen, timeout); + rc = do_inquiry(pp, 1, 0x83, buf, buflen, timeout); if (rc < 0) goto out; } @@ -341,7 +364,8 @@ retry: } int -get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout) +get_asymmetric_access_state(const struct path *pp, unsigned int tpg, + unsigned int timeout) { unsigned char *buf; struct rtpg_data * tpgd; @@ -349,6 +373,7 @@ get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout) int rc; int buflen; uint64_t scsi_buflen; + int fd = pp->fd; buflen = 4096; buf = (unsigned char *)malloc(buflen); diff --git a/libmultipath/prioritizers/alua_rtpg.h b/libmultipath/prioritizers/alua_rtpg.h index 35cffaf..675709f 100644 --- a/libmultipath/prioritizers/alua_rtpg.h +++ b/libmultipath/prioritizers/alua_rtpg.h @@ -22,8 +22,9 @@ #define RTPG_RTPG_FAILED 3 #define RTPG_TPG_NOT_FOUND 4 -int get_target_port_group_support(int fd, unsigned int timeout); -int get_target_port_group(struct path * pp, unsigned int timeout); -int get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout); +int get_target_port_group_support(const struct path *pp, unsigned int timeout); +int get_target_port_group(const struct path *pp, unsigned int timeout); +int get_asymmetric_access_state(const struct path *pp, + unsigned int tpg, unsigned int timeout); #endif /* __RTPG_H__ */ diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index 98068f3..e6263e9 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -45,22 +45,30 @@ do { \ } \ } while(0) -#define do_set_from_vec(type, var, src, dest, msg) \ -do { \ +#define __do_set_from_vec(type, var, src, dest) \ +({ \ type *_p; \ + bool _found = false; \ int i; \ \ vector_foreach_slot(src, _p, i) { \ if (_p->var) { \ dest = _p->var; \ - origin = msg; \ - goto out; \ + _found = true; \ + break; \ } \ } \ -} while (0) + _found; \ +}) -#define do_set_from_hwe(var, src, dest, msg) \ - do_set_from_vec(struct hwentry, var, src->hwe, dest, msg) +#define __do_set_from_hwe(var, src, dest) \ + __do_set_from_vec(struct hwentry, var, (src)->hwe, dest) + +#define do_set_from_hwe(var, src, dest, msg) \ + if (__do_set_from_hwe(var, src, dest)) { \ + origin = msg; \ + goto out; \ + } static const char default_origin[] = "(setting: multipath internal)"; static const char hwe_origin[] = @@ -425,7 +433,7 @@ int select_hwhandler(struct config *conf, struct multipath *mp) dh_state = &handler[2]; vector_foreach_slot(mp->paths, pp, i) - all_tpgs = all_tpgs && (pp->tpgs > 0); + all_tpgs = all_tpgs && (path_get_tpgs(pp) > 0); if (mp->retain_hwhandler != RETAIN_HWHANDLER_OFF) { vector_foreach_slot(mp->paths, pp, i) { if (get_dh_state(pp, dh_state, sizeof(handler) - 2) > 0 @@ -470,9 +478,14 @@ check_rdac(struct path * pp) { int len; char buff[44]; + const char *checker_name; if (pp->bus != SYSFS_BUS_SCSI) return 0; + /* Avoid ioctl if this is likely not an RDAC array */ + if (__do_set_from_hwe(checker_name, pp, checker_name) && + strcmp(checker_name, RDAC)) + return 0; len = get_vpd_sgio(pp->fd, 0xC9, buff, 44); if (len <= 0) return 0; @@ -490,7 +503,7 @@ int select_checker(struct config *conf, struct path *pp) if (check_rdac(pp)) { ckr_name = RDAC; goto out; - } else if (pp->tpgs > 0) { + } else if (path_get_tpgs(pp) != TPGS_NONE) { ckr_name = TUR; goto out; } @@ -552,6 +565,7 @@ detect_prio(struct config *conf, struct path * pp) struct prio *p = &pp->prio; char buff[512]; char *default_prio; + int tpgs; switch(pp->bus) { case SYSFS_BUS_NVME: @@ -560,9 +574,10 @@ detect_prio(struct config *conf, struct path * pp) default_prio = PRIO_ANA; break; case SYSFS_BUS_SCSI: - if (pp->tpgs <= 0) + tpgs = path_get_tpgs(pp); + if (tpgs == TPGS_NONE) return; - if ((pp->tpgs == 2 || !check_rdac(pp)) && + if ((tpgs == TPGS_EXPLICIT || !check_rdac(pp)) && sysfs_get_asymmetric_access_state(pp, buff, 512) >= 0) default_prio = PRIO_SYSFS; else @@ -607,6 +622,7 @@ int select_prio(struct config *conf, struct path *pp) const char *origin; struct mpentry * mpe; struct prio * p = &pp->prio; + int log_prio = 3; if (pp->detect_prio == DETECT_PRIO_ON) { detect_prio(conf, pp); @@ -628,14 +644,16 @@ out: * fetch tpgs mode for alua, if its not already obtained */ if (!strncmp(prio_name(p), PRIO_ALUA, PRIO_NAME_LEN)) { - int tpgs = 0; - unsigned int timeout = conf->checker_timeout; + int tpgs = path_get_tpgs(pp); - if(!pp->tpgs && - (tpgs = get_target_port_group_support(pp->fd, timeout)) >= 0) - pp->tpgs = tpgs; + if (tpgs == TPGS_NONE) { + prio_get(conf->multipath_dir, + p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS); + origin = "(setting: emergency fallback - alua failed)"; + log_prio = 1; + } } - condlog(3, "%s: prio = %s %s", pp->dev, prio_name(p), origin); + condlog(log_prio, "%s: prio = %s %s", pp->dev, prio_name(p), origin); condlog(3, "%s: prio args = \"%s\" %s", pp->dev, prio_args(p), origin); return 0; } diff --git a/libmultipath/structs.h b/libmultipath/structs.h index b794b0d..7879d76 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -280,7 +280,6 @@ struct path { int fd; int initialized; int retriggers; - int wwid_changed; unsigned int path_failures; time_t dis_reinstate_time; int disable_reinstate; diff --git a/libmultipath/version.h b/libmultipath/version.h index f3c7a51..1edd65f 100644 --- a/libmultipath/version.h +++ b/libmultipath/version.h @@ -20,8 +20,8 @@ #ifndef _VERSION_H #define _VERSION_H -#define VERSION_CODE 0x000800 -#define DATE_CODE 0x020e13 +#define VERSION_CODE 0x000801 +#define DATE_CODE 0x041213 #define PROG "multipath-tools" diff --git a/multipath/main.c b/multipath/main.c index 5abb118..69141db 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -356,7 +356,7 @@ static int check_usable_paths(struct config *conf, pp->udev = get_udev_device(pp->dev_t, DEV_DEVT); if (pp->udev == NULL) continue; - if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK) + if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO|DI_CHECKER) != PATHINFO_OK) continue; if (pp->state == PATH_UP && diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 index 0fe8461..6f08980 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 @@ -260,11 +260,11 @@ The default is: \fB\fR The udev attribute providing a unique path identifier. .RS .TP -The default is: for SCSI devices \fBID_SERIAL\fR +The default is: \fBID_SERIAL\fR, for SCSI devices .TP -The default is: for DASD devices \fBID_UID\fR +The default is: \fBID_UID\fR, for DASD devices .TP -The default is: for NVME devices \fBID_WWN\fR +The default is: \fBID_WWN\fR, for NVMe devices .RE . . @@ -670,7 +670,7 @@ This should be smaller than dev_loss_tmo. Setting this to will disable the timeout. .RS .TP -The default is: in \fB5\fR +The default is: \fB5\fR .RE . . @@ -718,7 +718,7 @@ track of the persistent reservation key used for a specific WWID, when \fIreservation_key\fR is set to \fBfile\fR. .RS .TP -The default is \fB/etc/multipath/prkeys\fR +The default is: \fB/etc/multipath/prkeys\fR .RE . . @@ -1148,12 +1148,8 @@ The default is: \fBno\fR . .TP .B disable_changed_wwids -If set to \fIyes\fR, multipathd will check the path wwid on change events, and -if it has changed from the wwid of the multipath device, multipathd will -disable access to the path until the wwid changes back. -.RS -.TP -The default is: \fBno\fR +This option is deprecated and ignored. If the WWID of a path suddenly changes, +multipathd handles it as if it was removed and then added again. .RE . . @@ -1186,7 +1182,7 @@ to switch the ghost paths to active ones. Setting this to \fI0\fR or \fIon\fR makes multipath immediately mark a device with only ghost paths as ready. .RS .TP -The default is \fBno\fR +The default is: \fBno\fR .RE . . @@ -1468,6 +1464,8 @@ section: .TP .B uid_attribute .TP +.B getuid_callout +.TP .B path_selector .TP .B path_checker @@ -1494,6 +1492,8 @@ section: .TP .B flush_on_last_del .TP +.B user_friendly_names +.TP .B retain_attached_hw_handler .TP .B detect_prio @@ -1525,6 +1525,8 @@ section: .B max_sectors_kb .TP .B ghost_delay +.TP +.B all_tg_pt .RE .PD .LP @@ -1604,7 +1606,11 @@ the values are taken from the \fIdevices\fR or \fIdefaults\fR sections: .TP .B skip_kpartx .TP +.B max_sectors_kb +.TP .B ghost_delay +.TP +.B all_tg_pt .RE .PD .LP diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index f95813e..60e17d6 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -877,7 +877,7 @@ cli_reload(void *v, char **reply, int *len, void *data) return 1; } - return reload_map(vecs, mpp, 0, 1); + return update_path_groups(mpp, vecs, 0); } int resize_map(struct multipath *mpp, unsigned long long size, diff --git a/multipathd/main.c b/multipathd/main.c index fb520b6..f203d77 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -127,11 +127,22 @@ int poll_dmevents = 0; #else int poll_dmevents = 1; #endif +/* Don't access this variable without holding config_lock */ enum daemon_status running_state = DAEMON_INIT; pid_t daemon_pid; pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t config_cond; +static inline enum daemon_status get_running_state(void) +{ + enum daemon_status st; + + pthread_mutex_lock(&config_lock); + st = running_state; + pthread_mutex_unlock(&config_lock); + return st; +} + /* * global copy of vecs for use in sig handlers */ @@ -149,7 +160,7 @@ static volatile sig_atomic_t log_reset_sig; const char * daemon_status(void) { - switch (running_state) { + switch (get_running_state()) { case DAEMON_INIT: return "init"; case DAEMON_START: @@ -169,10 +180,10 @@ daemon_status(void) /* * I love you too, systemd ... */ -const char * -sd_notify_status(void) +static const char * +sd_notify_status(enum daemon_status state) { - switch (running_state) { + switch (state) { case DAEMON_INIT: return "STATUS=init"; case DAEMON_START: @@ -189,17 +200,18 @@ sd_notify_status(void) } #ifdef USE_SYSTEMD -static void do_sd_notify(enum daemon_status old_state) +static void do_sd_notify(enum daemon_status old_state, + enum daemon_status new_state) { /* * Checkerloop switches back and forth between idle and running state. * No need to tell systemd each time. * These notifications cause a lot of overhead on dbus. */ - if ((running_state == DAEMON_IDLE || running_state == DAEMON_RUNNING) && + if ((new_state == DAEMON_IDLE || new_state == DAEMON_RUNNING) && (old_state == DAEMON_IDLE || old_state == DAEMON_RUNNING)) return; - sd_notify(0, sd_notify_status()); + sd_notify(0, sd_notify_status(new_state)); } #endif @@ -208,6 +220,7 @@ static void config_cleanup(void *arg) pthread_mutex_unlock(&config_lock); } +/* must be called with config_lock held */ static void __post_config_state(enum daemon_status state) { if (state != running_state && running_state != DAEMON_SHUTDOWN) { @@ -216,7 +229,7 @@ static void __post_config_state(enum daemon_status state) running_state = state; pthread_cond_broadcast(&config_cond); #ifdef USE_SYSTEMD - do_sd_notify(old_state); + do_sd_notify(old_state, state); #endif } } @@ -249,11 +262,11 @@ int set_config_state(enum daemon_status state) &config_lock, &ts); } } - if (!rc) { + if (!rc && (running_state != DAEMON_SHUTDOWN)) { running_state = state; pthread_cond_broadcast(&config_cond); #ifdef USE_SYSTEMD - do_sd_notify(old_state); + do_sd_notify(old_state, state); #endif } } @@ -392,7 +405,8 @@ static void set_no_path_retry(struct multipath *mpp) default: if (mpp->nr_active > 0) { mpp->retry_tick = 0; - dm_queue_if_no_path(mpp->alias, 1); + if (!is_queueing) + dm_queue_if_no_path(mpp->alias, 1); } else if (is_queueing && mpp->retry_tick == 0) enter_recovery_mode(mpp); break; @@ -936,7 +950,8 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) } if (mpp && mpp->wait_for_udev && (pathcount(mpp, PATH_UP) > 0 || - (pathcount(mpp, PATH_GHOST) > 0 && pp->tpgs != TPGS_IMPLICIT && + (pathcount(mpp, PATH_GHOST) > 0 && + path_get_tpgs(pp) != TPGS_IMPLICIT && mpp->ghost_delay_tick <= 0))) { /* if wait_for_udev is set and valid paths exist */ condlog(3, "%s: delaying path addition until %s is fully initialized", @@ -1190,7 +1205,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) int ro, retval = 0, rc; struct path * pp; struct config *conf; - int disable_changed_wwids; int needs_reinit = 0; switch ((rc = change_foreign(uev->udev))) { @@ -1208,12 +1222,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) break; } - conf = get_multipath_config(); - disable_changed_wwids = conf->disable_changed_wwids; - put_multipath_config(conf); - - ro = uevent_get_disk_ro(uev); - pthread_cleanup_push(cleanup_lock, &vecs->lock); lock(&vecs->lock); pthread_testcancel(); @@ -1233,25 +1241,17 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) goto out; strcpy(wwid, pp->wwid); - get_uid(pp, pp->state, uev->udev); + rc = get_uid(pp, pp->state, uev->udev, 0); - if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { - condlog(0, "%s: path wwid changed from '%s' to '%s'. %s", - uev->kernel, wwid, pp->wwid, - (disable_changed_wwids ? "disallowing" : - "continuing")); + if (rc != 0) strcpy(pp->wwid, wwid); - if (disable_changed_wwids) { - if (!pp->wwid_changed) { - pp->wwid_changed = 1; - pp->tick = 1; - if (pp->mpp) - dm_fail_path(pp->mpp->alias, pp->dev_t); - } - goto out; - } + else if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { + condlog(0, "%s: path wwid changed from '%s' to '%s'", + uev->kernel, wwid, pp->wwid); + ev_remove_path(pp, vecs, 1); + needs_reinit = 1; + goto out; } else { - pp->wwid_changed = 0; udev_device_unref(pp->udev); pp->udev = udev_device_ref(uev->udev); conf = get_multipath_config(); @@ -1262,6 +1262,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) pthread_cleanup_pop(1); } + ro = uevent_get_disk_ro(uev); if (mpp && ro >= 0) { condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro); @@ -1270,10 +1271,13 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) else { if (ro == 1) pp->mpp->force_readonly = 1; - retval = reload_map(vecs, mpp, 0, 1); - pp->mpp->force_readonly = 0; - condlog(2, "%s: map %s reloaded (retval %d)", - uev->kernel, mpp->alias, retval); + retval = update_path_groups(mpp, vecs, 0); + if (retval == 2) + condlog(2, "%s: map removed during reload", pp->dev); + else { + pp->mpp->force_readonly = 0; + condlog(2, "%s: map %s reloaded (retval %d)", uev->kernel, mpp->alias, retval); + } } } } @@ -1407,17 +1411,20 @@ uev_trigger (struct uevent * uev, void * trigger_data) int r = 0; struct vectors * vecs; struct uevent *merge_uev, *tmp; + enum daemon_status state; vecs = (struct vectors *)trigger_data; pthread_cleanup_push(config_cleanup, NULL); pthread_mutex_lock(&config_lock); - if (running_state != DAEMON_IDLE && - running_state != DAEMON_RUNNING) + while (running_state != DAEMON_IDLE && + running_state != DAEMON_RUNNING && + running_state != DAEMON_SHUTDOWN) pthread_cond_wait(&config_cond, &config_lock); + state = running_state; pthread_cleanup_pop(1); - if (running_state == DAEMON_SHUTDOWN) + if (state == DAEMON_SHUTDOWN) return 0; /* @@ -1829,7 +1836,7 @@ int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh) dm_lib_release(); if (setup_multipath(vecs, mpp) != 0) - return 1; + return 2; sync_map_state(mpp); return 0; @@ -2011,12 +2018,6 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) if (newstate == PATH_REMOVED) newstate = PATH_DOWN; - if (pp->wwid_changed) { - condlog(2, "%s: path wwid has changed. Refusing to use", - pp->dev); - newstate = PATH_DOWN; - } - if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { condlog(2, "%s: unusable path (%s) - checker failed", pp->dev, checker_state_name(newstate)); @@ -2072,6 +2073,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) /* if update_multipath_strings orphaned the path, quit early */ if (!pp->mpp) return 0; + set_no_path_retry(pp->mpp); if ((newstate == PATH_UP || newstate == PATH_GHOST) && check_path_reinstate_state(pp)) { @@ -2079,7 +2081,8 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) return 1; } - if (pp->io_err_disable_reinstate && hit_io_err_recheck_time(pp)) { + if ((newstate == PATH_UP || newstate == PATH_GHOST) && + pp->io_err_disable_reinstate && need_io_err_check(pp)) { pp->state = PATH_SHAKY; /* * to reschedule as soon as possible,so that this path can @@ -2106,8 +2109,8 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) * paths if there are no other active paths in map. */ disable_reinstate = (newstate == PATH_GHOST && - pp->mpp->nr_active == 0 && - pp->tpgs == TPGS_IMPLICIT) ? 1 : 0; + pp->mpp->nr_active == 0 && + path_get_tpgs(pp) == TPGS_IMPLICIT) ? 1 : 0; pp->chkrstate = newstate; if (newstate != pp->state) { @@ -2769,6 +2772,7 @@ child (void * param) struct config *conf; char *envp; int queue_without_daemon; + enum daemon_status state; mlockall(MCL_CURRENT | MCL_FUTURE); signal_init(); @@ -2866,6 +2870,7 @@ child (void * param) /* Wait for uxlsnr startup */ while (running_state == DAEMON_IDLE) pthread_cond_wait(&config_cond, &config_lock); + state = running_state; } pthread_cleanup_pop(1); @@ -2873,7 +2878,7 @@ child (void * param) condlog(0, "failed to create cli listener: %d", rc); goto failed; } - else if (running_state != DAEMON_CONFIGURE) { + else if (state != DAEMON_CONFIGURE) { condlog(0, "cli listener failed to start"); goto failed; } @@ -2913,15 +2918,17 @@ child (void * param) } pthread_attr_destroy(&misc_attr); - while (running_state != DAEMON_SHUTDOWN) { + while (1) { pthread_cleanup_push(config_cleanup, NULL); pthread_mutex_lock(&config_lock); - if (running_state != DAEMON_CONFIGURE && - running_state != DAEMON_SHUTDOWN) { + while (running_state != DAEMON_CONFIGURE && + running_state != DAEMON_SHUTDOWN) pthread_cond_wait(&config_cond, &config_lock); - } + state = running_state; pthread_cleanup_pop(1); - if (running_state == DAEMON_CONFIGURE) { + if (state == DAEMON_SHUTDOWN) + break; + if (state == DAEMON_CONFIGURE) { pthread_cleanup_push(cleanup_lock, &vecs->lock); lock(&vecs->lock); pthread_testcancel(); @@ -3091,8 +3098,6 @@ main (int argc, char *argv[]) ANNOTATE_BENIGN_RACE_SIZED(&multipath_conf, sizeof(multipath_conf), "Manipulated through RCU"); - ANNOTATE_BENIGN_RACE_SIZED(&running_state, sizeof(running_state), - "Suppress complaints about unprotected running_state reads"); ANNOTATE_BENIGN_RACE_SIZED(&uxsock_timeout, sizeof(uxsock_timeout), "Suppress complaints about this scalar variable"); diff --git a/multipathd/main.h b/multipathd/main.h index 8fd426b..e5c1398 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -43,5 +43,7 @@ int __setup_multipath (struct vectors * vecs, struct multipath * mpp, int reset); #define setup_multipath(vecs, mpp) __setup_multipath(vecs, mpp, 1) int update_multipath (struct vectors *vecs, char *mapname, int reset); +int update_path_groups(struct multipath *mpp, struct vectors *vecs, + int refresh); #endif /* MAIN_H */