From 2ba871e4f8cf132e60b03794413a35441df5abdb Mon Sep 17 00:00:00 2001 From: chenminhua Date: Mon, 2 Apr 2018 04:01:04 -0400 Subject: [PATCH] remove local disk from pathvec Here we provide a multipath_private.conf to enable remove_local_disk. When enable remove_local_disk, the multipath devices are only created on fc or iscsi devices. [Changelog]:add upgrade path [Author]:chenminhua --- libmultipath/discovery.c | 137 ++++++++++++++++++++++++++++-- libmultipath/discovery.h | 1 + libmultipath/libmultipath.version | 1 + multipathd/main.c | 4 + 4 files changed, 137 insertions(+), 6 deletions(-) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 6865cd9..83c8ee6 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -37,6 +37,112 @@ #define VPD_BUFLEN 4096 +const char *conf_file = "/etc/multipath_private.conf"; +static int conf_file_parsed = 0; +static int should_remove_local_disk = 0; + +static void parse_config() +{ + FILE *fp = NULL; + char buffer[256] = {0}; + char *str = NULL; + char *p = NULL; + + fp = fopen(conf_file, "r"); + if (fp) { + while (fgets(buffer, sizeof(buffer), fp)) { + str = buffer; + /* skip the space */ + while (isspace(*str)) + str++; + /* skip the comment line */ + if (strncmp(str, "#", 1) == 0) + continue; + /* skip line feed */ + if((p = strchr(str, '\n')) != NULL) + *p = '\0'; + if (strstr(str, "remove_local_disk") != NULL && (p = strstr(str, "=")) != NULL){ + str = p + 1; + /* skip the space */ + while (isspace(*str)) + str++; + if (strcmp(str, "1") == 0){ + should_remove_local_disk = 1; + } + break; + } + } + fclose(fp); + fp = NULL; + } + conf_file_parsed = 1; +} + +static int get_should_remove_local_disk() +{ + if (!conf_file_parsed) + parse_config(); + return should_remove_local_disk; +} + +/* Filter the local disks and remove them from pathvec. + * When bus type is SCSI and device type is (fc or scsi), + * return 0. This means the path is not local disk. + * When enable remove_local_disk, multipath only supports + * iscsi and fc device. + */ +static int +transport(int type, int h) +{ + char buff[PATH_MAX]; + int len, off; + struct stat a_stat; + + if (type != SYSFS_BUS_SCSI) { + return 1; + } + + /* FC host */ + strcpy(buff, "/sys"); + strcat(buff, "/class/fc_host/"); + len = strlen(buff); + snprintf(buff + len, PATH_MAX - len, "host%d", h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + return 0; + } + memset(buff, 0, PATH_MAX); + + /* iSCSI device */ + strcpy(buff, "/sys"); + strcat(buff, "/class/iscsi_host/"); + off = strlen(buff); + snprintf(buff + off, PATH_MAX - off, "host%d", h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + return 0; + } + return 1; +} + +int +remove_local_path (vector pathvec, struct path *pp) +{ + int i = -1; + + if(!get_should_remove_local_disk()){ + return 1; + } + + if (transport(pp->bus, pp->sg_id.host_no) == 0) { + return 1; + } + + if ((i = find_slot(pathvec, (void *)pp)) != -1) { + vector_del_slot(pathvec, i); + } + free_path(pp); + return 0; +} + struct vpd_vendor_page vpd_vendor_pages[VPD_VP_ARRAY_SIZE] = { [VPD_VP_UNDEF] = { 0x00, "undef" }, [VPD_VP_HP3PAR] = { 0xc0, "hp3par" }, @@ -128,22 +234,35 @@ path_discover (vector pathvec, struct config * conf, { struct path *pp; char devt[BLK_DEV_SIZE]; + int err = 1; dev_t devnum = udev_device_get_devnum(udevice); snprintf(devt, BLK_DEV_SIZE, "%d:%d", major(devnum), minor(devnum)); pp = find_path_by_devt(pathvec, devt); - if (!pp) - return store_pathinfo(pathvec, conf, - udevice, flag | DI_BLACKLIST, - NULL); - else + if (!pp) { + err = store_pathinfo(pathvec, conf, + udevice, flag | DI_BLACKLIST, + &pp); + if (err == 1) + return 1; + if (err == 0) + remove_local_path(pathvec, pp); + return 0; + } + else { /* * Don't use DI_BLACKLIST on paths already in pathvec. We rely * on the caller to pre-populate the pathvec with valid paths * only. */ - return pathinfo(pp, conf, flag); + err = pathinfo(pp, conf, flag); + if (err) + return err; + + remove_local_path(pathvec, pp); + return err; + } } static void cleanup_udev_enumerate_ptr(void *arg) @@ -2350,6 +2469,12 @@ int pathinfo(struct path *pp, struct config *conf, int mask) if (rc != PATHINFO_OK) return rc; + /* free local device */ + if (get_should_remove_local_disk() && transport(pp->bus, pp->sg_id.host_no)) { + condlog(3, "%s is a local device", pp->dev); + return 0; + } + if (pp->bus == SYSFS_BUS_SCSI && pp->sg_id.proto_id == SCSI_PROTOCOL_USB && !conf->allow_usb_devices) { diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h index acd5179..d8284be 100644 --- a/libmultipath/discovery.h +++ b/libmultipath/discovery.h @@ -57,6 +57,7 @@ bool has_uid_fallback(struct path *pp); int get_uid(struct path * pp, int path_state, struct udev_device *udev, int allow_fallback); bool is_vpd_page_supported(int fd, int pg); +int remove_local_path(vector pathvec, struct path *pp); /* * discovery bitmask diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version index aba1a30..ebf1482 100644 --- a/libmultipath/libmultipath.version +++ b/libmultipath/libmultipath.version @@ -147,6 +147,7 @@ global: _print_multipath_topology; reinstate_paths; remember_wwid; + remove_local_path; remove_map; remove_map_by_alias; remove_map_callback; diff --git a/multipathd/main.c b/multipathd/main.c index ebec203..2b6636d 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -1202,6 +1202,10 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) int ro; unsigned char prflag = PRFLAG_UNSET; + /* if pp is local path,remove it and return 0. */ + if (!remove_local_path(vecs->pathvec, pp)) + return 0; + /* * need path UID to go any further */ -- 2.33.0