6712560 iscsitgtd core dumped when to create a lun and register into isns server
authorks202890
Wed, 02 Jul 2008 20:51:06 -0700
changeset 7018 3ef7992cecec
parent 7017 131719b72ca5
child 7019 ba97ab54d044
6712560 iscsitgtd core dumped when to create a lun and register into isns server 6715033 iscsitgtd hangs when non-responsive IP address is entered for iSNS server through AR BUI 6716680 When isns is disabled accept any isns server from the cli 6717461 Double enable using bad isns servers can be problematic. 6717483 bcopy in isns_client.c can access out of boundary.
usr/src/cmd/iscsi/iscsitadm/main.c
usr/src/cmd/iscsi/iscsitgtd/isns.c
usr/src/cmd/iscsi/iscsitgtd/isns_client.c
usr/src/cmd/iscsi/iscsitgtd/isns_client.h
usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c
--- a/usr/src/cmd/iscsi/iscsitadm/main.c	Wed Jul 02 20:01:51 2008 -0700
+++ b/usr/src/cmd/iscsi/iscsitadm/main.c	Wed Jul 02 20:51:06 2008 -0700
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <zone.h>
+#include <netdb.h>
 
 #include <iscsitgt_impl.h>
 #include "cmdparse.h"
@@ -841,6 +842,13 @@
 				}
 				break;
 			case 's': /* iSNS server */
+				if (strlen(optionList->optarg) >
+				    MAXHOSTNAMELEN) {
+					(void) fprintf(stderr, "%s: %s\n",
+					    cmdName,
+					    gettext("option too long"));
+					return (1);
+				}
 				tgt_buf_add(&first_str, XML_ELEMENT_ISNS_SERV,
 				    optionList->optarg);
 				break;
--- a/usr/src/cmd/iscsi/iscsitgtd/isns.c	Wed Jul 02 20:01:51 2008 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns.c	Wed Jul 02 20:51:06 2008 -0700
@@ -42,6 +42,7 @@
 #include <libintl.h>
 #include <errno.h>
 #include <assert.h>
+#include <fcntl.h>
 #include <sys/byteorder.h>
 
 #include "isns_protocol.h"
@@ -381,6 +382,14 @@
 	size_t	sa_len;
 	int	so;
 	int	ret;
+	fd_set rfdset;
+	fd_set wfdset;
+	fd_set errfdset;
+	struct timeval timeout;
+	Boolean_t shouldsockblock = False;
+	int socket_ready = 0;
+	timeout.tv_sec = 5;   /* 5 Secs Timeout */
+	timeout.tv_usec = 0;   /* 0 uSecs Timeout */
 
 	if (server == NULL) {
 		syslog(LOG_ERR, "ISNS server ID required");
@@ -389,8 +398,9 @@
 
 	bzero(&hints, sizeof (struct addrinfo));
 	hints.ai_family = AF_UNSPEC;
-	if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
-		syslog(LOG_ALERT, "ISNS server %s not found", server);
+	if ((ret = getaddrinfo(server, NULL, NULL, &ai)) != 0) {
+		syslog(LOG_ALERT, "getaddrinfo failed on server %s: %s", server,
+		    gai_strerror(ret));
 		return (-1);
 	}
 
@@ -398,6 +408,13 @@
 	do {
 		so = socket(aip->ai_family, SOCK_STREAM, 0);
 		if (so != -1) {
+
+			/* set it to non blocking so connect wont hang */
+			if (setsocknonblocking(so) == -1) {
+				(void) close(so);
+				continue;
+			}
+
 			sa_len = aip->ai_addrlen;
 			switch (aip->ai_family) {
 				case PF_INET:
@@ -417,18 +434,69 @@
 					    htons(ISNS_DEFAULT_SERVER_PORT);
 					break;
 				default:
+					syslog(LOG_ALERT, "Bad protocol");
+					(void) close(so);
 					continue;
 			}
-			while (((ret = connect(so, sa, sa_len)) == -1) &&
-			    (errno == EINTR))
-				;
+
+			ret = connect(so, sa, sa_len);
 			if (ret == 0) {
-				freeaddrinfo(ai);
-				return (so);
-			} else {
-				syslog(LOG_ALERT, "Connect failed");
-				(void) close(so);
+				/*
+				 * connection succeeded with out
+				 * blocking
+				 */
+				shouldsockblock = True;
 			}
+
+			if (ret < 0) {
+				if (errno == EINPROGRESS) {
+					FD_ZERO(&rfdset);
+					FD_ZERO(&wfdset);
+					FD_ZERO(&errfdset);
+					FD_SET(so, &rfdset);
+					FD_SET(so, &wfdset);
+					FD_SET(so, &errfdset);
+					socket_ready =
+					    select(so + 1, &rfdset, &wfdset,
+					    &errfdset, &timeout);
+					if (socket_ready < 0) {
+						syslog(LOG_ALERT,
+						    "failed to connect with"
+						" isns, err=%d", errno);
+						(void) close(so);
+					} else if (socket_ready == 0) {
+						syslog(LOG_ALERT,
+						    "time out failed"
+						    " to connect with isns");
+						(void) close(so);
+					} else { /* Socket is ready */
+						/*
+						 * Check if socket is ready
+						 */
+						if (is_socket_ready(so,
+						    &rfdset, &wfdset,
+						    &errfdset) == True)
+							shouldsockblock = True;
+						else
+							(void) close(so);
+					}
+				} else {
+					syslog(LOG_WARNING,
+					    "Connect failed no progress");
+					(void) close(so);
+				}
+			}
+
+			if (shouldsockblock == True) {
+				if (-1 == setsockblocking(so)) {
+					(void) close(so);
+					shouldsockblock = False;
+				} else {
+					freeaddrinfo(ai);
+					return (so);
+				}
+			}
+
 		}
 	} while ((aip = aip->ai_next) != NULL);
 
@@ -437,6 +505,67 @@
 	return (-1);
 }
 
+/*
+ * According to:
+ * UNIX Network Programming Volume 1, Third Edition:
+ * The Sockets Networking APIBOOK:
+ *
+ * When the connection completes successfully, the descriptor becomes
+ * writable (p. 531 of TCPv2).
+ * When the connection establishment encounters an error, the descriptor
+ * becomes both readable and writable (p. 530 of TCPv2).
+ */
+Boolean_t
+is_socket_ready(int so, fd_set *rfdset, fd_set *wfdset,
+		    fd_set *errfdset)
+{
+	if ((FD_ISSET(so, wfdset) &&
+	    FD_ISSET(so, rfdset)) ||
+	    FD_ISSET(so, errfdset)) {
+		return (False);
+	} else {
+		return (True);
+	}
+}
+
+int
+setsocknonblocking(int so)
+{
+	int flags;
+	/* set it to non blocking */
+	if (-1 == (flags = fcntl(so, F_GETFL, 0))) {
+		syslog(LOG_WARNING,
+		    "Failed to get socket flags. Blocking..");
+		return (-1);
+	}
+
+	if (fcntl(so, F_SETFL, flags | O_NONBLOCK) == -1) {
+		syslog(LOG_WARNING,
+		    "Failed to set socket in non blocking mode");
+		return (-1);
+	}
+	return (0);
+}
+
+int
+setsockblocking(int so)
+{
+	int flags;
+	/* set it to non blocking */
+	if (-1 == (flags = fcntl(so, F_GETFL, 0))) {
+		syslog(LOG_WARNING, " Failed to get flags on socket..");
+		return (-1);
+	}
+
+	flags &= ~O_NONBLOCK;
+	if (fcntl(so, F_SETFL, flags) == -1) {
+		syslog(LOG_WARNING, " failed to set socket to blocking");
+		return (-1);
+	}
+	return (0);
+}
+
+
 void
 isns_close(int so)
 {
--- a/usr/src/cmd/iscsi/iscsitgtd/isns_client.c	Wed Jul 02 20:01:51 2008 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_client.c	Wed Jul 02 20:51:06 2008 -0700
@@ -76,6 +76,7 @@
 static	pthread_t	scn_tid = 0;
 static	pthread_t	isns_tid = 0;
 static	Boolean_t	isns_shutdown = False;
+static	Boolean_t	connection_thr_bail_out = False;
 static int ISNS_SLEEP_SECS = 20;
 Boolean_t	isns_server_connection_thr_running = False;
 target_queue_t	*mgmtq = NULL;
@@ -400,10 +401,13 @@
 static void *
 isns_server_connection_thr(void *arg)
 {
-	char *server = isns_args.server;
 	Boolean_t registered_targets = False;
+	char server[MAXHOSTNAMELEN + 1] = {0};
 
-	while (isns_shutdown == False) {
+	while (isns_shutdown == False &&
+	    connection_thr_bail_out == False) {
+		/* current server */
+		strcpy(server, isns_args.server);
 
 		if (is_isns_server_up(server) == 0) {
 			if (registered_targets == False) {
@@ -431,7 +435,8 @@
 			}
 		} else {
 			syslog(LOG_INFO,
-			    "isns server %s is not reachable", server);
+			    "isns server %s is not reachable",
+			    server);
 			registered_targets = False;
 		}
 		(void) sleep(ISNS_SLEEP_SECS);
@@ -595,8 +600,16 @@
 	tgt_node_t	*tgt = NULL;
 	char		*iname;
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_op_all: iSNS discovery is not running."
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	if ((so = isns_open(isns_args.server)) == -1) {
-		syslog(LOG_ERR, "isns_reg failed");
+		syslog(LOG_ERR, "isns_op_all: failed to open isns server %s",
+		    isns_args.server);
 		return (-1);
 	}
 
@@ -673,7 +686,7 @@
 			    "Detected a new isns server, deregistering"
 			    " %s", isns_args.server);
 			(void) isns_dereg_all();
-			bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN);
+			strcpy(isns_args.server, isns_srv);
 			/* Register with the new server */
 			if (isns_reg_all() == 0) {
 				/* scn register all targets */
@@ -686,7 +699,7 @@
 			}
 		}
 	} else {
-		bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN);
+		strcpy(isns_args.server, isns_srv);
 	}
 	free(isns_srv);
 	return (retcode);
@@ -709,9 +722,11 @@
 	/* get local hostname for entity usage */
 	if ((gethostname(isns_args.entity, MAXHOSTNAMELEN) < 0) ||
 	    (get_ip_addr(isns_args.entity, &eid_ip) < 0)) {
-			syslog(LOG_ERR, "ISNS fails to get ENTITY properties");
-			return (-1);
+		syslog(LOG_ERR, "isns_init: failed to get host name or host ip"
+		    " address for ENTITY properties");
+		return (-1);
 	}
+
 	(void) isns_populate_and_update_server_info(False);
 	if (pthread_create(&scn_tid, NULL,
 	    esi_scn_thr, (void *)&isns_args) !=
@@ -747,8 +762,11 @@
 	 */
 	if (isns_server_connection_thr_running == False) {
 		if (is_isns_enabled == True) {
-			(void) isns_init(NULL);
-			return (0);
+			if (isns_init(NULL) != 0) {
+				return (-1);
+			} else {
+				return (0);
+			}
 		} else {
 			syslog(LOG_INFO,
 			    "isns_update: isns is disabled");
@@ -765,6 +783,14 @@
 			isns_server_connection_thr_running = False;
 		} else {
 			/*
+			 * Incase the original thread is still running
+			 * we should reap it
+			 */
+			connection_thr_bail_out = True;
+			pthread_join(isns_tid, NULL);
+			connection_thr_bail_out = False;
+
+			/*
 			 * Read the configuration file incase the server
 			 * has changed.
 			 */
@@ -796,9 +822,11 @@
 static int
 get_addr_family(char *node) {
 	struct addrinfo		*ai = NULL;
+	int ret;
 
-	if (getaddrinfo(node, NULL, NULL, &ai) != 0) {
-		syslog(LOG_ALERT, "get_addr_family: server %s not found", node);
+	if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) {
+		syslog(LOG_ALERT, "get_addr_family: server %s not found : %s",
+		    node, gai_strerror(ret));
 		return (-1);
 	}
 	return (ai->ai_family);
@@ -810,9 +838,11 @@
 	struct addrinfo		*ai = NULL, *aip;
 	struct sockaddr_in	*sin;
 	struct sockaddr_in6	*sin6;
+	int	ret;
 
-	if (getaddrinfo(node, NULL, NULL, &ai) != 0) {
-		syslog(LOG_ALERT, "get_ip_addr: server %s not found", node);
+	if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) {
+		syslog(LOG_ALERT, "get_ip_addr: %s not found : %s",
+		    node, gai_strerror(ret));
 		return (-1);
 	}
 
@@ -926,7 +956,15 @@
 
 	/* process response */
 	if (process_rsp(cmd, rsp) == 0) {
-		num_reg--;
+		/*
+		 * Keep the num_reg to a non-negative number.
+		 * num_reg is used to keep track of whether there was
+		 * any registration occurred or not. Deregstration should
+		 * be followed by registration but in case dereg occurs
+		 * and somehow it is succeeded keeping num_reg to 0 prevent
+		 * any negative effect on subsequent registration.
+		 */
+		if (num_reg > 0) num_reg--;
 		ret = 0;
 	}
 
@@ -987,6 +1025,7 @@
 			}
 			if (tgt == src) {
 				free(src_nm);
+				src_nm = NULL;
 				continue;
 			} else {
 				found = True;
@@ -1349,6 +1388,13 @@
 	tgt_node_t	*tgt;
 	char		*iqn;
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_reg: iSNS discovery is not running."
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	if ((so = isns_open(isns_args.server)) == -1) {
 		syslog(LOG_ERR, "isns_reg failed with server: %s",
 		    isns_args.server);
@@ -1383,8 +1429,8 @@
 {
 	int so;
 	uint32_t	flags = ISNS_FLAG_REPLACE_REG;
-	isns_pdu_t	*cmd;
-	isns_rsp_t	*rsp;
+	isns_pdu_t	*cmd = NULL;
+	isns_rsp_t	*rsp = NULL;
 	char		*n = NULL;
 	char		*a = NULL;
 	char		alias[MAXNAMELEN];
@@ -1393,6 +1439,13 @@
 	int		ret = -1;
 	int		tgt_cnt = 0;
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_reg_all: iSNS discovery is not running."
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	/*
 	 * get the 1st target and use it for the source attribute
 	 */
@@ -1568,6 +1621,13 @@
 	int so;
 	int ret;
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_dereg: iSNS discovery is not running."
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	if ((so = isns_open(isns_args.server)) == -1) {
 		return (-1);
 	}
@@ -1597,6 +1657,13 @@
 	if (mods == 0)
 		return (0);
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_dev_update: iSNS discovery is not running."
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	if ((tgt = find_tgt_by_name(targ, &iname)) != NULL) {
 		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &dummy) ==
 		    True) {
@@ -1714,6 +1781,13 @@
 	int so;
 	int ret;
 
+	if (isns_server_connection_thr_running == False) {
+		syslog(LOG_ERR,
+		    "isns_qry_initiator: iSNS discovery is not running"
+		    " Check the previous iSNS initialization error.");
+		return (-1);
+	}
+
 	if ((so = isns_open(isns_args.server)) == -1) {
 		syslog(LOG_ERR, "isns_qry failed");
 		return (-1);
--- a/usr/src/cmd/iscsi/iscsitgtd/isns_client.h	Wed Jul 02 20:01:51 2008 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_client.h	Wed Jul 02 20:51:06 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,6 +29,10 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <netdb.h>
 #include "queue.h"
 
@@ -94,8 +98,8 @@
 #define	STRLEN(x)	(strlen(x) + 1)
 
 typedef struct esi_scn_arg {
-	char		entity[MAXHOSTNAMELEN];	/* iscsi target entity */
-	char		server[MAXHOSTNAMELEN];	/* isns server */
+	char		entity[MAXHOSTNAMELEN + 1]; /* iscsi target entity */
+	char		server[MAXHOSTNAMELEN + 1]; /* isns server */
 	int		isns_port;		/* isns server port */
 } esi_scn_arg_t;
 
@@ -163,5 +167,13 @@
 void		print_ntoh_tlv(isns_tlv_t *);
 void		print_attr(isns_tlv_t *attr, void *pval, uint32_t ival);
 void		print_isns_hdr(isns_hdr_t *);
+int		setsocknonblocking(int so);
+int		setsockblocking(int so);
+Boolean_t	is_socket_ready(int so,
+		    fd_set *rfdset, fd_set *wfdset, fd_set *errfdset);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif	/* _ISNS_CLIENT_H */
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c	Wed Jul 02 20:01:51 2008 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c	Wed Jul 02 20:51:06 2008 -0700
@@ -40,6 +40,7 @@
 #include <netdb.h>
 #include <libgen.h>
 #include <libzfs.h>
+#include <syslog.h>
 
 #include <iscsitgt_impl.h>
 #include "queue.h"
@@ -427,7 +428,7 @@
 		}
 		if (isns_enabled() == True) {
 			if (isns_dev_update(t->x_value, isns_mods) != 0) {
-				xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED);
+				xml_rtn_msg(&msg, ERR_ISNS_ERROR);
 				return (msg);
 			}
 		}
@@ -1107,6 +1108,11 @@
 	int		so;
 	int		port;
 
+	if (strlen(prop) > MAXHOSTNAMELEN) {
+		xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
+		return (msg);
+	}
+
 	if ((sp = strdup(prop)) == NULL) {
 		xml_rtn_msg(&msg, ERR_NO_MEM);
 		return (msg);
@@ -1122,11 +1128,16 @@
 	}
 
 	so = isns_open(sp);
-	if (so < 0)
-		xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
-	else
+	if (so < 0) {
+		if (isns_enabled() == True) {
+			xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
+		} else { /* Just print a warning and accept the server */
+			syslog(LOG_ALERT,
+			    "Check if the server:%s is valid", sp);
+		}
+	} else {
 		isns_close(so);
-
+	}
 	free(sp);
 	return (msg);
 }