Blame SOURCES/open-iscsi-2.0.873-125-iscsid-safe-session-logout.patch

6cc97b
From 46ba8eed79fa13b32947b5c5b1bf0bc133b14c41 Mon Sep 17 00:00:00 2001
6cc97b
From: Chris Leech <cleech@redhat.com>
6cc97b
Date: Tue, 3 Feb 2015 16:28:15 -0800
6cc97b
Subject: [PATCH] iscsid safe session logout
6cc97b
6cc97b
Implement a safe logout option, which uses libmount from util-linux to
6cc97b
check for active mounts (and swaps) over devices, their partitions, and
6cc97b
any holders (like LVM and multipath device maps).  When enabled iscsid
6cc97b
will refuse to logout of sessions actively being used for mounts,
6cc97b
returning a status of EBUSY to the ipc request.
6cc97b
6cc97b
I've made it a configuration option (iscsid.safe_logout) that defaults
6cc97b
to "No" to preserve the existing behavior as the default, while making
6cc97b
it available for users that prefer a safety check.
6cc97b
6cc97b
This does add a new dependency on libmount.
6cc97b
6cc97b
Signed-off-by: Chris Leech <cleech@redhat.com>
6cc97b
---
6cc97b
 etc/iscsid.conf |   3 +
6cc97b
 usr/Makefile    |   4 +-
6cc97b
 usr/initiator.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6cc97b
 usr/sysfs.c     |  40 ++++++++++++
6cc97b
 usr/sysfs.h     |   4 ++
6cc97b
 5 files changed, 248 insertions(+), 2 deletions(-)
6cc97b
6cc97b
diff --git a/etc/iscsid.conf b/etc/iscsid.conf
6cc97b
index ef76dc0..6d9a5c0 100644
6cc97b
--- a/etc/iscsid.conf
6cc97b
+++ b/etc/iscsid.conf
6cc97b
@@ -22,6 +22,9 @@
6cc97b
 # Default for upstream open-iscsi scripts (uncomment to activate).
6cc97b
 iscsid.startup = /sbin/iscsid
6cc97b
 
6cc97b
+# Check for active mounts on devices reachable through a session
6cc97b
+# and refuse to logout if there are any.  Defaults to "No".
6cc97b
+# iscsid.safe_logout = Yes
6cc97b
 
6cc97b
 #############################
6cc97b
 # NIC/HBA and driver settings
6cc97b
diff --git a/usr/Makefile b/usr/Makefile
6cc97b
index 3d8ee22..b2c1504 100644
6cc97b
--- a/usr/Makefile
6cc97b
+++ b/usr/Makefile
6cc97b
@@ -55,14 +55,14 @@ all: $(PROGRAMS)
6cc97b
 
6cc97b
 iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \
6cc97b
 	iscsid.o session_mgmt.o discoveryd.o
6cc97b
-	$(CC) $(CFLAGS) $^ -o $@  -L../utils/open-isns -lisns
6cc97b
+	$(CC) $(CFLAGS) $^ -o $@  -L../utils/open-isns -lisns -lmount
6cc97b
 
6cc97b
 iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o
6cc97b
 	$(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns
6cc97b
 
6cc97b
 iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
6cc97b
 		iscsistart.o statics.o
6cc97b
-	$(CC) $(CFLAGS) -static $^ -o $@
6cc97b
+	$(CC) $(CFLAGS) -static $^ -o $@ -lmount
6cc97b
 clean:
6cc97b
 	rm -f *.o $(PROGRAMS) .depend $(LIBSYS)
6cc97b
 
6cc97b
diff --git a/usr/initiator.c b/usr/initiator.c
6cc97b
index 9d02f47..ac1a3ac 100644
6cc97b
--- a/usr/initiator.c
6cc97b
+++ b/usr/initiator.c
6cc97b
@@ -30,6 +30,7 @@
6cc97b
 #include <errno.h>
6cc97b
 #include <dirent.h>
6cc97b
 #include <fcntl.h>
6cc97b
+#include <libmount/libmount.h>
6cc97b
 
6cc97b
 #include "initiator.h"
6cc97b
 #include "transport.h"
6cc97b
@@ -2140,11 +2141,200 @@ static int session_unbind(struct iscsi_session *session)
6cc97b
 	return err;
6cc97b
 }
6cc97b
 
6cc97b
+static struct libmnt_table *mtab, *swaps;
6cc97b
+
6cc97b
+static void libmount_cleanup(void)
6cc97b
+{
6cc97b
+	mnt_free_table(mtab);
6cc97b
+	mnt_free_table(swaps);
6cc97b
+	mtab = swaps = NULL;
6cc97b
+}
6cc97b
+
6cc97b
+static int libmount_init(void)
6cc97b
+{
6cc97b
+	mnt_init_debug(0);
6cc97b
+	mtab = mnt_new_table();
6cc97b
+	swaps = mnt_new_table();
6cc97b
+	if (!mtab || !swaps) {
6cc97b
+		libmount_cleanup();
6cc97b
+		return -ENOMEM;
6cc97b
+	}
6cc97b
+	mnt_table_parse_mtab(mtab, NULL);
6cc97b
+	mnt_table_parse_swaps(swaps, NULL);
6cc97b
+	return 0;
6cc97b
+}
6cc97b
+
6cc97b
+static int trans_filter(const struct dirent *d)
6cc97b
+{
6cc97b
+	if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name))
6cc97b
+		return 0;
6cc97b
+	return 1;
6cc97b
+}
6cc97b
+
6cc97b
+static int subdir_filter(const struct dirent *d)
6cc97b
+{
6cc97b
+	if (!(d->d_type & DT_DIR))
6cc97b
+		return 0;
6cc97b
+	return trans_filter(d);
6cc97b
+}
6cc97b
+
6cc97b
+static int is_partition(const char *path)
6cc97b
+{
6cc97b
+	char *devtype;
6cc97b
+	int rc = 0;
6cc97b
+
6cc97b
+	devtype = sysfs_get_uevent_devtype(path);
6cc97b
+	if (!devtype)
6cc97b
+		return 0;
6cc97b
+	if (strcmp(devtype, "partition") == 0)
6cc97b
+		rc = 1;
6cc97b
+	free(devtype);
6cc97b
+	return rc;
6cc97b
+}
6cc97b
+
6cc97b
+static int blockdev_check_mnts(char *syspath)
6cc97b
+{
6cc97b
+	struct libmnt_fs *fs;
6cc97b
+	char *devname = NULL;
6cc97b
+	char *_devname = NULL;
6cc97b
+	int rc = 0;
6cc97b
+
6cc97b
+	devname = sysfs_get_uevent_devname(syspath);
6cc97b
+	if (!devname)
6cc97b
+		goto out;
6cc97b
+
6cc97b
+	_devname = calloc(1, PATH_MAX);
6cc97b
+	if (!_devname)
6cc97b
+		goto out;
6cc97b
+	snprintf(_devname, PATH_MAX, "/dev/%s", devname);
6cc97b
+
6cc97b
+	fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD);
6cc97b
+	if (fs) {
6cc97b
+		rc = 1;
6cc97b
+		goto out;
6cc97b
+	}
6cc97b
+	fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD);
6cc97b
+	if (fs)
6cc97b
+		rc = 1;
6cc97b
+out:
6cc97b
+	free(devname);
6cc97b
+	free(_devname);
6cc97b
+	return rc;
6cc97b
+}
6cc97b
+
6cc97b
+static int count_device_users(char *syspath);
6cc97b
+
6cc97b
+static int blockdev_get_partitions(char *syspath)
6cc97b
+{
6cc97b
+	struct dirent **parts = NULL;
6cc97b
+	int n, i;
6cc97b
+	int count = 0;
6cc97b
+
6cc97b
+	n = scandir(syspath, &parts, subdir_filter, alphasort);
6cc97b
+	for (i = 0; i < n; i++) {
6cc97b
+		char *newpath;
6cc97b
+
6cc97b
+		newpath = calloc(1, PATH_MAX);
6cc97b
+		if (!newpath)
6cc97b
+			continue;
6cc97b
+		snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name);
6cc97b
+		free(parts[i]);
6cc97b
+		if (is_partition(newpath)) {
6cc97b
+			count += count_device_users(newpath);
6cc97b
+		}
6cc97b
+		free(newpath);
6cc97b
+	}
6cc97b
+	free(parts);
6cc97b
+	return count;
6cc97b
+}
6cc97b
+
6cc97b
+static int blockdev_get_holders(char *syspath)
6cc97b
+{
6cc97b
+	char *path = NULL;
6cc97b
+	struct dirent **holds = NULL;
6cc97b
+	int n, i;
6cc97b
+	int count = 0;
6cc97b
+
6cc97b
+	path = calloc(1, PATH_MAX);
6cc97b
+	if (!path)
6cc97b
+		return 0;
6cc97b
+	snprintf(path, PATH_MAX, "%s/holders", syspath);
6cc97b
+
6cc97b
+	n = scandir(path, &holds, trans_filter, alphasort);
6cc97b
+	for (i = 0; i < n; i++) {
6cc97b
+		char *newpath;
6cc97b
+		char *rp;
6cc97b
+
6cc97b
+		newpath = calloc(1, PATH_MAX);
6cc97b
+		if (!newpath)
6cc97b
+			continue;
6cc97b
+		snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name);
6cc97b
+
6cc97b
+		free(holds[i]);
6cc97b
+		rp = realpath(newpath, NULL);
6cc97b
+		if (rp)
6cc97b
+			count += count_device_users(rp);
6cc97b
+		free(newpath);
6cc97b
+		free(rp);
6cc97b
+	}
6cc97b
+	free(path);
6cc97b
+	free(holds);
6cc97b
+	return count;
6cc97b
+}
6cc97b
+
6cc97b
+static int count_device_users(char *syspath)
6cc97b
+{
6cc97b
+	int count = 0;
6cc97b
+	count += blockdev_check_mnts(syspath);
6cc97b
+	count += blockdev_get_partitions(syspath);
6cc97b
+	count += blockdev_get_holders(syspath);
6cc97b
+	return count;
6cc97b
+};
6cc97b
+
6cc97b
+static void device_in_use(void *data, int host_no, int target, int lun)
6cc97b
+{
6cc97b
+	char *syspath = NULL;
6cc97b
+	char *devname = NULL;
6cc97b
+	int *count = data;
6cc97b
+
6cc97b
+	devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun);
6cc97b
+	if (!devname)
6cc97b
+		goto out;
6cc97b
+	syspath = calloc(1, PATH_MAX);
6cc97b
+	if (!syspath)
6cc97b
+		goto out;
6cc97b
+	snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname);
6cc97b
+	*count += count_device_users(syspath);
6cc97b
+out:
6cc97b
+	free(syspath);
6cc97b
+	free(devname);
6cc97b
+}
6cc97b
+
6cc97b
+static int session_in_use(int sid)
6cc97b
+{
6cc97b
+	int host_no = -1, err = 0;
6cc97b
+	int count = 0;
6cc97b
+
6cc97b
+	if (libmount_init()) {
6cc97b
+		log_error("Failed to initialize libmount, "
6cc97b
+			  "not checking for active mounts on session [%d].\n", sid);
6cc97b
+		return 0;
6cc97b
+	}
6cc97b
+
6cc97b
+	host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err;;
6cc97b
+	if (!err)
6cc97b
+		iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use);
6cc97b
+
6cc97b
+	libmount_cleanup();
6cc97b
+	return count;
6cc97b
+}
6cc97b
+
6cc97b
 int session_logout_task(int sid, queue_task_t *qtask)
6cc97b
 {
6cc97b
 	iscsi_session_t *session;
6cc97b
 	iscsi_conn_t *conn;
6cc97b
 	int rc = ISCSI_SUCCESS;
6cc97b
+	char *safe;
6cc97b
 
6cc97b
 	session = session_find_by_sid(sid);
6cc97b
 	if (!session) {
6cc97b
@@ -2167,6 +2357,15 @@ invalid_state:
6cc97b
 		return ISCSI_ERR_INTERNAL;
6cc97b
 	}
6cc97b
 
6cc97b
+	safe = cfg_get_string_param(dconfig->config_file, "iscsid.safe_logout");
6cc97b
+	if (safe && !strcmp(safe, "Yes") && session_in_use(sid)) {
6cc97b
+		log_error("Session is actively in use for mounted storage, "
6cc97b
+			  "and iscsid.safe_logout is configured.\n");
6cc97b
+		free(safe);
6cc97b
+		return ISCSI_ERR_BUSY;
6cc97b
+	}
6cc97b
+	free(safe);
6cc97b
+
6cc97b
 	/* FIXME: logout all active connections */
6cc97b
 	conn = &session->conn[0];
6cc97b
 	if (conn->logout_qtask)
6cc97b
diff --git a/usr/sysfs.c b/usr/sysfs.c
6cc97b
index d00c925..bbb00c0 100644
6cc97b
--- a/usr/sysfs.c
6cc97b
+++ b/usr/sysfs.c
6cc97b
@@ -709,3 +709,43 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name,
6cc97b
 	close(fd);
6cc97b
 	return rc;
6cc97b
 }
6cc97b
+
6cc97b
+char *sysfs_get_uevent_field(const char *path, const char *field)
6cc97b
+{
6cc97b
+	char *uevent_path = NULL;
6cc97b
+	FILE *f = NULL;
6cc97b
+	char *line, buffer[1024];
6cc97b
+	char *ff, *d;
6cc97b
+	char *out = NULL;
6cc97b
+
6cc97b
+	uevent_path = calloc(1, PATH_MAX);
6cc97b
+	if (!uevent_path)
6cc97b
+		return NULL;
6cc97b
+	snprintf(uevent_path, PATH_MAX, "%s/uevent", path);
6cc97b
+
6cc97b
+	f = fopen(uevent_path, "r");
6cc97b
+	if (!f)
6cc97b
+		goto out;
6cc97b
+	while ((line = fgets(buffer, sizeof (buffer), f))) {
6cc97b
+		ff = strtok(line, "=");
6cc97b
+		d = strtok(NULL, "\n");
6cc97b
+		if (strcmp(ff, field))
6cc97b
+			continue;
6cc97b
+		out = strdup(d);
6cc97b
+		break;
6cc97b
+	}
6cc97b
+	fclose(f);
6cc97b
+out:
6cc97b
+	free(uevent_path);
6cc97b
+	return out;
6cc97b
+}
6cc97b
+
6cc97b
+char *sysfs_get_uevent_devtype(const char *path)
6cc97b
+{
6cc97b
+	return sysfs_get_uevent_field(path, "DEVTYPE");
6cc97b
+}
6cc97b
+
6cc97b
+char *sysfs_get_uevent_devname(const char *path)
6cc97b
+{
6cc97b
+	return sysfs_get_uevent_field(path, "DEVNAME");
6cc97b
+}
6cc97b
diff --git a/usr/sysfs.h b/usr/sysfs.h
6cc97b
index 304dbbf..462060e 100644
6cc97b
--- a/usr/sysfs.h
6cc97b
+++ b/usr/sysfs.h
6cc97b
@@ -66,4 +66,8 @@ extern int sysfs_get_uint16(char *id, char *subsys, char *param,
6cc97b
 extern int sysfs_set_param(char *id, char *subsys, char *attr_name,
6cc97b
 			   char *write_buf, ssize_t buf_size);
6cc97b
 
6cc97b
+extern char *sysfs_get_uevent_field(const char *path, const char *field);
6cc97b
+extern char *sysfs_get_uevent_devtype(const char *path);
6cc97b
+extern char *sysfs_get_uevent_devname(const char *path);
6cc97b
+
6cc97b
 #endif
6cc97b
-- 
6cc97b
2.1.0
6cc97b