9d648dce创建于 2024年2月7日历史提交
From 2ba871e4f8cf132e60b03794413a35441df5abdb Mon Sep 17 00:00:00 2001
From: chenminhua <chenminhua1@huawei.com>
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