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.
--- 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);
}