|
|
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 |
|