[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#679055: istgt: Add support to reload the istgt.conf file.



Package: istgt
Version: 0.4~20111008-2
Severity: wishlist

Dear Maintainer,

istgt currently has no method to load new Logical Units other than restarting
the daemon. This is a bit cruel, in that it interrupts folks that have
mounted LUNs from the running istgt.

The attached patch, ported from FreeBSD, adds a refresh command to
istgtcontrol to allow telling istgt to reload istgt.conf and update
the running configuration, all without restarting the daemon.

I've also updated the provided init.d file to have a reload target.

Cheers,
Andrew

-- System Information:
Debian Release: wheezy/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: kfreebsd-amd64 (x86_64)

Kernel: kFreeBSD 9.0-1-amd64
Locale: LANG=en_NZ.UTF-8, LC_CTYPE=en_NZ.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages istgt depends on:
ii  libbsd0      0.4.0-1
ii  libc0.1      2.13-33
ii  libcam6      9.0+ds1-3
ii  libssl1.0.0  1.0.1c-3
ii  lsb-base     4.1+Debian6

istgt recommends no packages.

istgt suggests no packages.

-- no debconf information
diff -urN istgt-0.4~20111008.orig/debian/init istgt-0.4~20111008/debian/init
--- istgt-0.4~20111008.orig/debian/init	2011-10-27 12:26:17.000000000 +1300
+++ istgt-0.4~20111008/debian/init	2012-06-26 14:51:03.477234205 +1200
@@ -89,8 +89,7 @@
 # Function that sends a SIGHUP to the daemon/service
 #
 do_reload() {
-	start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
-	return 0
+	istgtcontrol refresh
 }
 
 case "$1" in
@@ -110,14 +109,18 @@
 		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
 	esac
 	;;
+  reload)
+    [ "$VERBOSE" != no ] && log_daemon_msg "Reloading $DESC " "$NAME"
+    do_reload
+    case "$?" in
+		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+	esac
+  ;;
   status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
-  restart|force-reload)
-	#
-	# If the "reload" option is implemented then remove the
-	# 'force-reload' alias
-	#
+  restart)
 	log_daemon_msg "Restarting $DESC" "$NAME"
 	do_stop
 	case "$?" in
diff -urN istgt-0.4~20111008.orig/debian/patches/add-reload.patch istgt-0.4~20111008/debian/patches/add-reload.patch
--- istgt-0.4~20111008.orig/debian/patches/add-reload.patch	1970-01-01 12:00:00.000000000 +1200
+++ istgt-0.4~20111008/debian/patches/add-reload.patch	2012-06-26 15:45:13.751244466 +1200
@@ -0,0 +1,441 @@
+Description: Add a reload target to istgt
+ Currently istgt does not support on-the-fly reloading of its configurations,
+ which means the administrator has to restart the daemon to make new settings in
+ effect.
+ .
+ This is quite inconvenient when istgt is used in conjection with some "sensitive"
+ initiators, for instance, Xen.
+ .
+ This patch which implements the underlying functionality was written by Kun Huang,
+ sponsored by Applied Operations, LLC.
+ .
+ It was taken from the FreeBSD patch tracking sustem.
+Author: Andrew Ruthven <andrew@etc.gen.nz>
+Origin: other, http://www.freebsd.org/cgi/query-pr.cgi?pr=165844
+Forwarded: no
+Last-Update: 2012-06-26
+
+--- istgt-0.4~20111008.orig/src/istgt_lu.h
++++ istgt-0.4~20111008/src/istgt_lu.h
+@@ -236,6 +236,9 @@ typedef struct istgt_lu_t {
+ 	ISTGT_LU_TSIH tsih[MAX_LU_TSIH];
+ 	int maxmap;
+ 	ISTGT_LU_MAP map[MAX_LU_MAP];
++
++	int to_add;
++	int to_remove;
+ } ISTGT_LU;
+ typedef ISTGT_LU *ISTGT_LU_Ptr;
+ 
+--- istgt-0.4~20111008.orig/src/istgt_proto.h
++++ istgt-0.4~20111008/src/istgt_proto.h
+@@ -85,10 +85,10 @@ int istgt_lu_parse_media_flags(const cha
+ uint64_t istgt_lu_parse_media_size(const char *file, const char *size, int *flags);
+ PORTAL *istgt_lu_find_portalgroup(ISTGT_Ptr istgt, int tag);
+ INITIATOR_GROUP *istgt_lu_find_initiatorgroup(ISTGT_Ptr istgt, int tag);
+-int istgt_lu_init(ISTGT_Ptr istgt);
++int istgt_lu_init(ISTGT_Ptr istgt, int ignore_dup);
+ int istgt_lu_set_all_state(ISTGT_Ptr istgt, ISTGT_STATE state);
+-int istgt_lu_create_threads(ISTGT_Ptr istgt);
+-int istgt_lu_shutdown(ISTGT_Ptr istgt);
++int istgt_lu_create_threads(ISTGT_Ptr istgt, int new_only);
++int istgt_lu_shutdown(ISTGT_Ptr istgt, int removed_only);
+ int istgt_lu_islun2lun(uint64_t islun);
+ uint64_t istgt_lu_lun2islun(int lun, int maxlun);
+ int istgt_lu_reset(ISTGT_LU_Ptr lu, uint64_t lun);
+--- istgt-0.4~20111008.orig/src/istgt_lu_disk.c
++++ istgt-0.4~20111008/src/istgt_lu_disk.c
+@@ -794,6 +794,7 @@ istgt_lu_disk_shutdown(ISTGT_Ptr istgt,
+ 		xfree(spec);
+ 		lu->lun[i].spec = NULL;
+ 	}
++	lu->maxlun = 0;
+ 
+ 	return 0;
+ }
+--- istgt-0.4~20111008.orig/src/istgt_lu_ctl.c
++++ istgt-0.4~20111008/src/istgt_lu_ctl.c
+@@ -965,6 +965,113 @@ istgt_uctl_cmd_change(UCTL_Ptr uctl)
+ 	return UCTL_CMD_OK;
+ }
+ 
++extern const char *g_config_file;
++extern ISTGT g_istgt;
++
++static int
++istgt_uctl_cmd_refresh(UCTL_Ptr uctl)
++{
++	char *arg;
++	int rc, i, j;
++	CONFIG *config;
++	ISTGT_Ptr istgt;
++
++	arg = uctl->arg;
++	istgt = &g_istgt;
++
++	/* reload config, might add/remove LUNs */
++	/* step 1: re-read config files */
++	config = istgt_allocate_config();
++	rc = istgt_read_config(config, g_config_file);
++	if (rc < 0) {
++		fprintf(stderr, "refresh config error\n");
++		return UCTL_CMD_ERR;
++	}
++	if (config->section == NULL) {
++		fprintf(stderr, "empty config\n");
++		istgt_free_config(config);
++		return UCTL_CMD_ERR;
++	}
++	istgt_free_config(istgt->config);
++	istgt->config = config;
++
++	/* step 2: add new units, init new LUNs, tag to-add/remove LUNs */
++	rc = istgt_lu_init(istgt, 1);
++	if (rc < 0) {
++		ISTGT_ERRLOG("istgt_lu_init() failed\n");
++		istgt_free_config(config);
++		return UCTL_CMD_ERR;
++	}
++
++	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
++		ISTGT_LU_Ptr lu = istgt->logical_unit[i];
++		if (lu == NULL)
++			continue;
++		if (lu->to_add)
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "newly added LUN %s\n", lu->name);
++		if (lu->to_remove)
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "newly removed LUN %s\n", lu->name);
++	}
++
++	/* creat new threads for new LUNs, do work in luworker() */
++	/* create LUN threads for command queuing */
++	rc = istgt_lu_create_threads(istgt, 1);
++	if (rc < 0) {
++		ISTGT_ERRLOG("lu_create_threads() failed\n");
++		istgt_free_config(config);
++		return UCTL_CMD_ERR;
++	}
++	/* start taking IOs */
++	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
++		ISTGT_LU_Ptr lu = istgt->logical_unit[i];
++		if (lu == NULL)
++			continue;
++		if (lu->to_add) {
++			istgt_lu_set_state(lu, ISTGT_STATE_RUNNING);
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set newly added LUN as running %s\n", lu->name);
++		}
++	}
++
++	/* step 3: shutdown removed LUNs */
++	/* clear outstanding IOs */
++	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
++		ISTGT_LU_Ptr lu = istgt->logical_unit[i];
++		if (lu == NULL)
++			continue;
++		if (lu->to_remove) {
++			for (j = 0; j<lu->maxlun; j++)
++				istgt_lu_clear_all_task(lu, j);
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "clear newly removed LUN queue %s\n", lu
++->name);
++		}
++	}
++
++	/* sync and close LUNs */
++	istgt_lu_shutdown(istgt, 1);
++
++	/* clear tag of to_add/to_remove, get ready for next refresh */
++	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
++		ISTGT_LU_Ptr lu = istgt->logical_unit[i];
++		if (lu == NULL)
++			continue;
++		if (lu->to_add)
++			lu->to_add = 0;
++		if (lu->to_remove)
++			lu->to_remove = 0;
++	}
++
++	/* logging event */
++	ISTGT_NOTICELOG("Configuration refresh requested from %s\n",
++	    uctl->caddr);
++
++	/* refresh succeeded */
++	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
++	rc = istgt_uctl_writeline(uctl);
++	if (rc != UCTL_CMD_OK)
++		return rc;
++	return UCTL_CMD_OK;
++}
++
+ static int
+ istgt_uctl_cmd_reset(UCTL_Ptr uctl)
+ {
+@@ -1183,6 +1290,7 @@ static ISTGT_UCTL_CMD_TABLE istgt_uctl_c
+ 	{ "UNLOAD",  istgt_uctl_cmd_unload },
+ 	{ "LOAD",    istgt_uctl_cmd_load },
+ 	{ "CHANGE",  istgt_uctl_cmd_change },
++	{ "REFRESH", istgt_uctl_cmd_refresh },
+ 	{ "RESET",   istgt_uctl_cmd_reset },
+ 	{ "INFO",    istgt_uctl_cmd_info },
+ 	{ NULL,      NULL },
+--- istgt-0.4~20111008.orig/src/istgtcontrol.c
++++ istgt-0.4~20111008/src/istgtcontrol.c
+@@ -494,6 +494,36 @@ exec_change(UCTL_Ptr uctl)
+ }
+ 
+ static int
++exec_refresh(UCTL_Ptr uctl)
++{
++	const char *delim = ARGS_DELIM;
++	char *arg;
++	char *result;
++	int rc;
++
++	/* send command */
++	uctl_snprintf(uctl, "REFRESH \n");
++	rc = uctl_writeline(uctl);
++	if (rc != UCTL_CMD_OK)
++		return rc;
++
++	/* receive result */
++	rc = uctl_readline(uctl);
++	if (rc != UCTL_CMD_OK)
++		return rc;
++	arg = trim_string(uctl->recvbuf);
++	result = strsepq(&arg, delim);
++	strupr(result);
++	if (strcmp(result, "OK") != 0) {
++		if (is_err_req_auth(uctl, arg))
++			return UCTL_CMD_REQAUTH;
++		fprintf(stderr, "ERROR %s\n", arg);
++		return UCTL_CMD_ERR;
++	}
++	return UCTL_CMD_OK;
++}
++
++static int
+ exec_reset(UCTL_Ptr uctl)
+ {
+ 	const char *delim = ARGS_DELIM;
+@@ -591,6 +621,7 @@ static EXEC_TABLE exec_table[] =
+ 	{ "UNLOAD",  exec_unload,   0, 1 },
+ 	{ "LOAD",    exec_load,     0, 1 },
+ 	{ "CHANGE",  exec_change,   1, 1 },
++	{ "REFRESH", exec_refresh,  0, 0 },
+ 	{ "RESET",   exec_reset,    0, 1 },
+ 	{ "INFO",    exec_info,     0, 0 },
+ 	{ NULL,      NULL,          0, 0 },
+@@ -1054,6 +1085,7 @@ usage(void)
+ 	printf(" load       load media to specified unit\n");
+ 	printf(" unload     unload media from specified unit\n");
+ 	printf(" change     change media with <file> at specified unit\n");
++	printf(" refresh    refresh to reload target and lun configuration\n");
+ 	printf(" reset      reset specified lun of target\n");
+ 	printf(" info       show connections of target\n");
+ }
+--- istgt-0.4~20111008.orig/src/istgt_lu.c
++++ istgt-0.4~20111008/src/istgt_lu.c
+@@ -1202,7 +1202,7 @@ istgt_lu_set_local_settings(ISTGT_Ptr is
+ }
+ 
+ static int
+-istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SECTION *sp)
++istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SECTION *sp, int ignore_dup)
+ {
+ 	char buf[MAX_TMPBUF], buf2[MAX_TMPBUF];
+ 	ISTGT_LU_Ptr lu;
+@@ -1222,21 +1222,40 @@ istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SE
+ 	int i, j, k;
+ 	int rc;
+ 
+-	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add unit %d\n", sp->num);
++	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add unit %d (ignore dup = %d)\n", sp->num, ignore_dup);
+ 
+ 	if (sp->num >= MAX_LOGICAL_UNIT) {
+ 		ISTGT_ERRLOG("LU%d: over maximum unit number\n", sp->num);
+ 		return -1;
+ 	}
+-	if (istgt->logical_unit[sp->num] != NULL) {
++	if (istgt->logical_unit[sp->num] != NULL && !ignore_dup) {
+ 		ISTGT_ERRLOG("LU%d: duplicate unit\n", sp->num);
+ 		return -1;
+ 	}
++	/* existing LUNs */
++	if (istgt->logical_unit[sp->num] != NULL && ignore_dup) {
++		istgt->logical_unit[sp->num]->to_add = 0;
++		istgt->logical_unit[sp->num]->to_remove = 0;
++		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip existing unit %d\n", sp->num);
++		return 0;
++	}
++
++	/* new LUNs */
++	if (istgt->logical_unit[sp->num] == NULL && ignore_dup) {
++		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add NEW unit %d\n", sp->num);
++	}
+ 
+ 	lu = xmalloc(sizeof *lu);
+ 	memset(lu, 0, sizeof *lu);
+ 	lu->num = sp->num;
+ 	lu->istgt = istgt;
++
++	/* tag new LUNs */
++	if (ignore_dup) {
++		lu->to_add = 1;
++		lu->to_remove = 0;
++	}
++
+ 	istgt_lu_set_state(lu, ISTGT_STATE_INVALID);
+ 	nbs64 = istgt_lu_get_nbserial(istgt->nodebase);
+ #if 0
+@@ -1944,12 +1963,15 @@ istgt_lu_del_unit(ISTGT_Ptr istgt, ISTGT
+ static void *luworker(void *arg);
+ 
+ int
+-istgt_lu_init(ISTGT_Ptr istgt)
++istgt_lu_init(ISTGT_Ptr istgt, int ignore_dup)
+ {
+ 	ISTGT_LU_Ptr lu;
+ 	CF_SECTION *sp;
+ 	int rc;
+ 	int i;
++	int lun_map[MAX_LOGICAL_UNIT];
++
++	memset(lun_map, 0, sizeof(int) * MAX_LOGICAL_UNIT);
+ 
+ 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_init\n");
+ 	sp = istgt_find_cf_section(istgt->config, "Global");
+@@ -1969,11 +1991,12 @@ istgt_lu_init(ISTGT_Ptr istgt)
+ 				ISTGT_ERRLOG("tag %d is invalid\n", sp->num);
+ 				return -1;
+ 			}
+-			rc = istgt_lu_add_unit(istgt, sp);
++			rc = istgt_lu_add_unit(istgt, sp, ignore_dup);
+ 			if (rc < 0) {
+ 				ISTGT_ERRLOG("lu_add_unit() failed\n");
+ 				return -1;
+ 			}
++			lun_map[sp->num] = 1; /* in new LUN list */
+ 		}
+ 		sp = sp->next;
+ 	}
+@@ -1982,6 +2005,22 @@ istgt_lu_init(ISTGT_Ptr istgt)
+ 		lu = istgt->logical_unit[i];
+ 		if (lu == NULL)
+ 			continue;
++		/* tag to be removed LUNs */
++		if (lun_map[i] == 0) {
++			istgt->logical_unit[i]->to_add = 0;
++			istgt->logical_unit[i]->to_remove = 1;
++			continue;
++		}
++		/* only process newly added LUNs here beyond in loop */
++		if (ignore_dup &&
++		    (istgt->logical_unit[i]->to_add == 1 &&
++		     istgt->logical_unit[i]->to_remove == 0)) {
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "adding unit %d\n", i);
++		} else if (ignore_dup &&
++		    !(istgt->logical_unit[i]->to_add == 1 &&
++		      istgt->logical_unit[i]->to_remove == 0)) {
++			continue;
++		}
+ 
+ 		rc = pthread_mutex_init(&lu->mutex, NULL);
+ 		if (rc != 0) {
+@@ -2069,7 +2108,7 @@ istgt_lu_set_all_state(ISTGT_Ptr istgt,
+ }
+ 
+ int
+-istgt_lu_create_threads(ISTGT_Ptr istgt)
++istgt_lu_create_threads(ISTGT_Ptr istgt, int new_only)
+ {
+ #ifdef HAVE_PTHREAD_SET_NAME_NP
+ 	char buf[MAX_TMPBUF];
+@@ -2084,6 +2123,10 @@ istgt_lu_create_threads(ISTGT_Ptr istgt)
+ 		lu = istgt->logical_unit[i];
+ 		if (lu == NULL)
+ 			continue;
++		if (new_only && !lu->to_add) {
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip existing LUN %d\n", i);
++			continue;
++		}
+ 
+ 		if (lu->queue_depth != 0) {
+ 			/* create LU thread */
+@@ -2114,18 +2157,22 @@ istgt_lu_create_threads(ISTGT_Ptr istgt)
+ }
+ 
+ int
+-istgt_lu_shutdown(ISTGT_Ptr istgt)
++istgt_lu_shutdown(ISTGT_Ptr istgt, int removed_only)
+ {
+ 	ISTGT_LU_Ptr lu;
+ 	int rc;
+ 	int i;
+ 
+-	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_shutdown\n");
++	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_shutdown (removed_only = %d\n", removed_only);
+ 
+ 	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
+ 		lu = istgt->logical_unit[i];
+ 		if (lu == NULL)
+ 			continue;
++		if (removed_only && !lu->to_remove) {
++			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip existing LUNs %d\n", i);
++			continue;
++		}
+ 		istgt_lu_set_state(lu, ISTGT_STATE_SHUTDOWN);
+ 
+ 		switch (lu->type) {
+--- istgt-0.4~20111008.orig/src/istgt.c
++++ istgt-0.4~20111008/src/istgt.c
+@@ -71,6 +71,7 @@
+ #define PORTNUMLEN 32
+ 
+ ISTGT g_istgt;
++const char  *g_config_file;
+ 
+ #if 0
+ void
+@@ -1598,6 +1599,7 @@ main(int argc, char **argv)
+ 
+ 	/* read config files */
+ 	config = istgt_allocate_config();
++	g_config_file = config_file;
+ 	rc = istgt_read_config(config, config_file);
+ 	if (rc < 0) {
+ 		fprintf(stderr, "config error\n");
+@@ -1662,7 +1664,7 @@ main(int argc, char **argv)
+ 		istgt_free_config(config);
+ 		exit(EXIT_FAILURE);
+ 	}
+-	rc = istgt_lu_init(istgt);
++	rc = istgt_lu_init(istgt, 0);
+ 	if (rc < 0) {
+ 		ISTGT_ERRLOG("istgt_lu_init() failed\n");
+ 		goto initialize_error;
+@@ -1772,7 +1774,7 @@ main(int argc, char **argv)
+ #endif
+ 
+ 	/* create LUN threads for command queuing */
+-	rc = istgt_lu_create_threads(istgt);
++	rc = istgt_lu_create_threads(istgt, 0);
+ 	if (rc < 0) {
+ 		ISTGT_ERRLOG("lu_create_threads() failed\n");
+ 		goto initialize_error;
+@@ -1809,7 +1811,7 @@ main(int argc, char **argv)
+ 		istgt_close_portal(istgt);
+ 		istgt_close_uctl_portal(istgt);
+ 		istgt_iscsi_shutdown(istgt);
+-		istgt_lu_shutdown(istgt);
++		istgt_lu_shutdown(istgt, 0);
+ 		istgt_destory_initiator_group_array(istgt);
+ 		istgt_destroy_portal_array(istgt);
+ 		istgt_destroy_uctl_portal(istgt);
+@@ -1837,7 +1839,7 @@ main(int argc, char **argv)
+ 	istgt_close_portal(istgt);
+ 	istgt_close_uctl_portal(istgt);
+ 	istgt_iscsi_shutdown(istgt);
+-	istgt_lu_shutdown(istgt);
++	istgt_lu_shutdown(istgt, 0);
+ 	istgt_destory_initiator_group_array(istgt);
+ 	istgt_destroy_portal_array(istgt);
+ 	istgt_destroy_uctl_portal(istgt);
diff -urN istgt-0.4~20111008.orig/debian/patches/series istgt-0.4~20111008/debian/patches/series
--- istgt-0.4~20111008.orig/debian/patches/series	2012-04-01 03:18:55.000000000 +1200
+++ istgt-0.4~20111008/debian/patches/series	2012-06-26 14:51:14.232245955 +1200
@@ -2,3 +2,4 @@
 add-istgtcontrol-manpage
 fix-as-needed-build.patch
 #fix-autosize.patch
+add-reload.patch

Reply to: