From: Hannes Reinecke <[email protected]>

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 v2:
 * rework readability in new poll() code

Changes since v1:
 * Break out of poll() loop on error
 * Initialize discovery timeout

Signed-off-by: Hannes Reinecke <[email protected]>
Signed-off-by: Lee Duncan <[email protected]>
---
 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   | 51 +++++++++++++++++++++++++++++++++++++++++----------
 usr/iscsid_req.h   | 15 +++++++++------
 usr/iscsistart.c   |  4 ++--
 usr/session_info.c | 14 ++++++++------
 usr/session_info.h |  5 +++--
 11 files changed, 82 insertions(+), 41 deletions(-)

diff --git a/usr/config.h b/usr/config.h
index fd31a54d0130..5b1bb1d624c5 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -315,6 +315,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 593d22650f0d..6ee8bd915f5a 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.");
@@ -1573,7 +1573,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 63334907f2d1..7e88e5728ac3 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 84c396cbf6f9..8ca668fdb3bc 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 9602f6c331ec..4b2bd34cbb2e 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;
 
@@ -2956,6 +2956,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:
@@ -3263,6 +3264,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;
@@ -3448,7 +3450,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 8dd72a43bb0b..0c2634448d09 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..a2e6d6e39ceb 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,45 @@ 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) {
+                       err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL);
+                       if (err < 0) {
+                               log_error("read error (%d/%d), daemon died?",
+                                         err, errno);
+                               break;
+                       }
+                       len -= err;
+                       iscsi_err = rsp->err;
+               }
+       }
        close(fd);
 
        if (!iscsi_err && cmd != rsp->command)
@@ -136,7 +167,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 +176,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 +184,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 16a12efb29a7..5cf09721636b 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 89422d8e3933..9dc6e25b05fb 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) {
@@ -407,7 +407,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;
                }
@@ -422,7 +423,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
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/open-iscsi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to