From: Hannes Reinecke <
ha...@suse.de>
The server might already been terminated when iscsiadm tries to
send a request to it, hence we might be waiting forever for a reply.
With this patchset we're waiting at most one minute before giving up,
avoiding a hang in iscsiadm.
Changes since v1:
* Break out of poll() loop on error
* Initialize discovery timeout
Signed-off-by: Hannes Reinecke <
ha...@suse.com>
Tested-by: Lee Duncan <
ldu...@suse.com>
---
usr/config.h | 1 +
usr/discovery.c | 16 ++++++++--------
usr/host.c | 2 +-
usr/iscsi_sysfs.c | 1 +
usr/iscsiadm.c | 12 +++++++-----
usr/iscsid.c | 2 +-
usr/iscsid_req.c | 52 ++++++++++++++++++++++++++++++++++++++++++----------
usr/iscsid_req.h | 15 +++++++++------
usr/iscsistart.c | 4 ++--
usr/session_info.c | 14 ++++++++------
usr/session_info.h | 5 +++--
11 files changed, 83 insertions(+), 41 deletions(-)
diff --git a/usr/config.h b/usr/config.h
index 2e36a0a164b6..a464cfd948d7 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -316,6 +316,7 @@ typedef struct discovery_rec {
discovery_type_e type;
char address[NI_MAXHOST];
int port;
+ int iscsid_req_tmo;
union {
struct iscsi_sendtargets_config sendtargets;
struct iscsi_slp_config slp;
diff --git a/usr/discovery.c b/usr/discovery.c
index 43c2359cdcbc..abf7a4feafde 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -64,7 +64,7 @@ static char initiator_name[TARGET_NAME_MAXLEN + 1];
static char initiator_alias[TARGET_NAME_MAXLEN + 1];
static struct iscsi_ev_context ipc_ev_context;
-static int request_initiator_name(void)
+static int request_initiator_name(int tmo)
{
int rc;
iscsiadm_req_t req;
@@ -78,7 +78,7 @@ static int request_initiator_name(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_INAME;
- rc = iscsid_exec_req(&req, &rsp, 1);
+ rc = iscsid_exec_req(&req, &rsp, 1, tmo);
if (rc)
return rc;
@@ -88,7 +88,7 @@ static int request_initiator_name(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_IALIAS;
- rc = iscsid_exec_req(&req, &rsp, 0);
+ rc = iscsid_exec_req(&req, &rsp, 0, tmo);
if (rc)
/* alias is optional so return ok */
return 0;
@@ -344,7 +344,7 @@ int discovery_isns(void *data, struct iface_rec *iface,
if (iface && strlen(iface->iname))
iname = iface->iname;
else {
- rc = request_initiator_name();
+ rc = request_initiator_name(drec->iscsid_req_tmo);
if (rc) {
log_error("Cannot perform discovery. Initiatorname "
"required.");
@@ -454,7 +454,7 @@ int discovery_offload_sendtargets(int host_no, int do_login,
* and get back the results. We should do this since it would
* allows us to then process the results like software iscsi.
*/
- rc = iscsid_exec_req(&req, &rsp, 1);
+ rc = iscsid_exec_req(&req, &rsp, 1, drec->iscsid_req_tmo);
if (rc) {
log_error("Could not offload sendtargets to %s.",
drec->address);
@@ -802,7 +802,7 @@ static void iscsi_free_session(struct iscsi_session *session)
static iscsi_session_t *
iscsi_alloc_session(struct iscsi_sendtargets_config *config,
- struct iface_rec *iface, int *rc)
+ struct iface_rec *iface, int *rc, int tmo)
{
iscsi_session_t *session;
@@ -848,7 +848,7 @@ iscsi_alloc_session(struct iscsi_sendtargets_config *config,
strcpy(initiator_name, iface->iname);
/* MNC TODO add iface alias */
} else {
- *rc = request_initiator_name();
+ *rc = request_initiator_name(tmo);
if (*rc) {
log_error("Cannot perform discovery. Initiatorname "
"required.");
@@ -1571,7 +1571,7 @@ int discovery_sendtargets(void *fndata, struct iface_rec *iface,
iscsi_timer_clear(&connection_timer);
/* allocate a new session, and initialize default values */
- session = iscsi_alloc_session(config, iface, &rc);
+ session = iscsi_alloc_session(config, iface, &rc, drec->iscsid_req_tmo);
if (rc)
return rc;
diff --git a/usr/host.c b/usr/host.c
index f2052d33be73..9b65fe0ebed8 100644
--- a/usr/host.c
+++ b/usr/host.c
@@ -251,7 +251,7 @@ static int host_info_print_tree(void *data, struct host_info *hinfo)
printf("\tSessions:\n");
printf("\t*********\n");
- session_info_print_tree(&sessions, "\t", session_info_flags, 0);
+ session_info_print_tree(&sessions, "\t", session_info_flags, 0, -1);
session_info_free_list(&sessions);
return 0;
}
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 3a37a481421f..d87250c8d4ef 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -1420,6 +1420,7 @@ int iscsi_sysfs_for_each_session(void *data, int *nr_found,
if (!info)
return ISCSI_ERR_NOMEM;
+ info->iscsid_req_tmo = -1;
n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter,
alphasort);
if (n <= 0)
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index c6705bd6c3d2..7943ff922e83 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -252,7 +252,7 @@ str_to_portal_type(char *str)
return ptype;
}
-static void kill_iscsid(int priority)
+static void kill_iscsid(int priority, int tmo)
{
iscsiadm_req_t req;
iscsiadm_rsp_t rsp;
@@ -274,7 +274,7 @@ static void kill_iscsid(int priority)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_IMMEDIATE_STOP;
- rc = iscsid_exec_req(&req, &rsp, 0);
+ rc = iscsid_exec_req(&req, &rsp, 0, tmo);
if (rc) {
iscsi_err_print_msg(rc);
log_error("Could not stop iscsid. Trying sending iscsid "
@@ -741,7 +741,7 @@ static char *get_config_file(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_CONFIG_FILE;
- rc = iscsid_exec_req(&req, &rsp, 1);
+ rc = iscsid_exec_req(&req, &rsp, 1, ISCSID_REQ_TIMEOUT);
if (rc)
return NULL;
@@ -791,7 +791,7 @@ session_stats(void *data, struct session_info *info)
req.command = MGMT_IPC_SESSION_STATS;
req.u.session.sid = info->sid;
- rc = iscsid_exec_req(&req, &rsp, 1);
+ rc = iscsid_exec_req(&req, &rsp, 1, info->iscsid_req_tmo);
if (rc)
return rc;
@@ -2933,6 +2933,7 @@ static int exec_disc_op(int disc_type, char *ip, int port,
int rc = 0;
memset(&drec, 0, sizeof(struct discovery_rec));
+ drec.iscsid_req_tmo = -1;
switch (disc_type) {
case DISCOVERY_TYPE_SENDTARGETS:
@@ -3240,6 +3241,7 @@ main(int argc, char **argv)
int packet_size=32, ping_count=1, ping_interval=0;
int do_discover = 0, sub_mode = -1;
int portal_type = -1;
+ int timeout = ISCSID_REQ_TIMEOUT;
struct sigaction sa_old;
struct sigaction sa_new;
struct list_head ifaces;
@@ -3425,7 +3427,7 @@ main(int argc, char **argv)
}
if (killiscsid >= 0) {
- kill_iscsid(killiscsid);
+ kill_iscsid(killiscsid, timeout);
goto free_ifaces;
}
diff --git a/usr/iscsid.c b/usr/iscsid.c
index f8ffd23c500f..c866432b5923 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -274,7 +274,7 @@ static int sync_session(void *data, struct session_info *info)
memcpy(&req.u.session.rec, &rec, sizeof(node_rec_t));
retry:
- rc = iscsid_exec_req(&req, &rsp, 0);
+ rc = iscsid_exec_req(&req, &rsp, 0, info->iscsid_req_tmo);
if (rc == ISCSI_ERR_ISCSID_NOTCONN && retries < 30) {
retries++;
sleep(1);
diff --git a/usr/iscsid_req.c b/usr/iscsid_req.c
index 2950d748c644..aebe1d25e90c 100644
--- a/usr/iscsid_req.c
+++ b/usr/iscsid_req.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/un.h>
+#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -33,6 +34,7 @@
#include "iscsi_util.h"
#include "config.h"
#include "iscsi_err.h"
+#include "iscsid_req.h"
#include "uip_mgmt_ipc.h"
static void iscsid_startup(void)
@@ -118,16 +120,46 @@ int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
return ISCSI_SUCCESS;
}
-int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp)
+int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp,
+ int timeout)
{
- int iscsi_err;
+ size_t len = sizeof(*rsp);
+ int iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
int err;
+ int poll_wait = 0;
- if ((err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL)) != sizeof(*rsp)) {
- log_error("got read error (%d/%d), daemon died?", err, errno);
- iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
- } else
- iscsi_err = rsp->err;
+ if (timeout == -1) {
+ timeout = ISCSID_REQ_TIMEOUT;
+ poll_wait = 1;
+ }
+ while (len) {
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ err = poll(&pfd, 1, timeout);
+ if (!err) {
+ if (poll_wait)
+ continue;
+ return ISCSI_ERR_ISCSID_NOTCONN;
+ } else if (err < 0) {
+ if (errno == EINTR)
+ continue;
+ log_error("got poll error (%d/%d), daemon died?",
+ err, errno);
+ return ISCSI_ERR_ISCSID_COMM_ERR;
+ } else if (!pfd.revents & POLLIN)
+ continue;
+ err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL);
+ if (err < 0) {
+ log_error("got read error (%d/%d), daemon died?",
+ err, errno);
+ break;
+ } else {
+ len -= err;
+ iscsi_err = rsp->err;
+ }
+ }
close(fd);
if (!iscsi_err && cmd != rsp->command)
@@ -136,7 +168,7 @@ int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp)
}
int iscsid_exec_req(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
- int start_iscsid)
+ int start_iscsid, int tmo)
{
int fd;
int err;
@@ -145,7 +177,7 @@ int iscsid_exec_req(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
if (err)
return err;
- return iscsid_response(fd, req->command, rsp);
+ return iscsid_response(fd, req->command, rsp, tmo);
}
int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
@@ -153,7 +185,7 @@ int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
iscsiadm_rsp_t rsp;
memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
- return iscsid_response(fd, cmd, &rsp);
+ return iscsid_response(fd, cmd, &rsp, -1);
}
int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
diff --git a/usr/iscsid_req.h b/usr/iscsid_req.h
index 8cb4a922f46d..67e509e4607f 100644
--- a/usr/iscsid_req.h
+++ b/usr/iscsid_req.h
@@ -21,17 +21,20 @@
#ifndef ISCSID_REQ_H_
#define ISCSID_REQ_H
+#define ISCSID_REQ_TIMEOUT 1000
+
struct iscsiadm_req;
struct iscsiadm_rsp;
struct node_rec;
extern int iscsid_exec_req(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp,
- int iscsid_start);
-extern int iscsid_req_wait(int cmd, int fd);
-extern int iscsid_req_by_rec_async(int cmd, struct node_rec *rec, int *fd);
-extern int iscsid_req_by_rec(int cmd, struct node_rec *rec);
-extern int iscsid_req_by_sid_async(int cmd, int sid, int *fd);
-extern int iscsid_req_by_sid(int cmd, int sid);
+ int iscsid_start, int tmo);
+extern int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd);
+extern int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, struct node_rec *rec,
+ int *fd);
+extern int iscsid_req_by_rec(iscsiadm_cmd_e cmd, struct node_rec *rec);
+extern int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd);
+extern int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid);
extern int uip_broadcast(void *buf, size_t buf_len, int fd_flags,
uint32_t *status);
diff --git a/usr/iscsistart.c b/usr/iscsistart.c
index 7ff2236c9c79..14b1eb5304ab 100644
--- a/usr/iscsistart.c
+++ b/usr/iscsistart.c
@@ -123,7 +123,7 @@ static int stop_event_loop(void)
memset(&req, 0, sizeof(req));
req.command = MGMT_IPC_IMMEDIATE_STOP;
- rc = iscsid_exec_req(&req, &rsp, 0);
+ rc = iscsid_exec_req(&req, &rsp, 0, -1);
if (rc) {
iscsi_err_print_msg(rc);
log_error("Could not stop event_loop");
@@ -235,7 +235,7 @@ static int login_session(struct node_rec *rec)
memcpy(&req.u.session.rec, rec, sizeof(*rec));
retry:
- rc = iscsid_exec_req(&req, &rsp, 0);
+ rc = iscsid_exec_req(&req, &rsp, 0, ISCSID_REQ_TIMEOUT);
/*
* handle race where iscsid proc is starting up while we are
* trying to connect.
diff --git a/usr/session_info.c b/usr/session_info.c
index 2f48e65402e0..9a89bfc4a138 100644
--- a/usr/session_info.c
+++ b/usr/session_info.c
@@ -93,7 +93,7 @@ static int session_info_print_flat(void *data, struct session_info *info)
return 0;
}
-static int print_iscsi_state(int sid, char *prefix)
+static int print_iscsi_state(int sid, char *prefix, int tmo)
{
iscsiadm_req_t req;
iscsiadm_rsp_t rsp;
@@ -120,7 +120,7 @@ static int print_iscsi_state(int sid, char *prefix)
req.command = MGMT_IPC_SESSION_INFO;
req.u.session.sid = sid;
- err = iscsid_exec_req(&req, &rsp, 1);
+ err = iscsid_exec_req(&req, &rsp, 1, tmo);
/*
* for drivers like qla4xxx, iscsid does not display
* anything here since it does not know about it.
@@ -236,7 +236,7 @@ static int print_scsi_state(int sid, char *prefix, unsigned int flags)
}
void session_info_print_tree(struct list_head *list, char *prefix,
- unsigned int flags, int do_show)
+ unsigned int flags, int do_show, int tmo)
{
struct session_info *curr, *prev = NULL;
@@ -289,7 +289,7 @@ void session_info_print_tree(struct list_head *list, char *prefix,
if (flags & SESSION_INFO_ISCSI_STATE) {
printf("%s\t\tSID: %d\n", prefix, curr->sid);
- print_iscsi_state(curr->sid, prefix);
+ print_iscsi_state(curr->sid, prefix, tmo);
}
if (flags & SESSION_INFO_ISCSI_TIM) {
@@ -406,7 +406,8 @@ int session_info_print(int info_level, struct session_info *info, int do_show)
if (info) {
INIT_LIST_HEAD(&info->list);
list_add_tail(&list, &info->list);
- session_info_print_tree(&list, "", flags, do_show);
+ session_info_print_tree(&list, "", flags, do_show,
+ info->iscsid_req_tmo);
num_found = 1;
break;
}
@@ -421,7 +422,8 @@ int session_info_print(int info_level, struct session_info *info, int do_show)
if (err || !num_found)
break;
- session_info_print_tree(&list, "", flags, do_show);
+ session_info_print_tree(&list, "", flags, do_show,
+ info->iscsid_req_tmo);
session_info_free_list(&list);
break;
default:
diff --git a/usr/session_info.h b/usr/session_info.h
index 726aefdce1b0..179b088d2070 100644
--- a/usr/session_info.h
+++ b/usr/session_info.h
@@ -28,6 +28,7 @@ struct session_info {
/* local info */
struct iface_rec iface;
int sid;
+ int iscsid_req_tmo;
struct session_timeout tmo;
struct session_CHAP chap;
@@ -60,8 +61,8 @@ struct session_link_info {
extern int session_info_create_list(void *data, struct session_info *info);
extern void session_info_free_list(struct list_head *list);
extern int session_info_print(int info_level, struct session_info *match_info,
- int do_show);
+ int do_show);
extern void session_info_print_tree(struct list_head *list, char *prefix,
- unsigned int flags, int do_show);
+ unsigned int flags, int do_show, int tmo);
#endif
--
1.8.5.6