Add user interface for dynamic reconfiguration (USERSPACE TODO ITEM #3).

    Note1:
    Examples of the user interface in this patch is as follows. 
 
     # iscsiadm -m session -o update -n PARAM_NAME -v VALUE 
     => Update node DB and session parameter in all running sessions. 

     # iscsiadm -m session -o nonpersistent -n PARAM_NAME -v VALUE 
     => Update session parameter in all running sessions (not update node DB). 

     # iscsiadm -m session -o update -n PARAM_NAME -v VALUE -r SESSION_ID 
     => Update node DB and session parameter in a specified session. 

     # iscsiadm -m session -o nonpersistent -n PARAM_NAME -v VALUE -r 
SESSION_ID 
     => Update session parameter in a specified session (not update node DB). 


    Note2:
    This patch makes following parameters to be modifiable in running sessions.
 
     node.session.timeo.replacement_timeout
     node.session.iscsi.FastAbort
     node.session.err_timeo.abort_timeout
     node.session.err_timeo.lu_reset_timeout
     node.session.err_timeo.tgt_reset_timeout
     node.conn[0].timeo.noop_out_timeout
     node.conn[0].timeo.noop_out_interval


    v2:
    - Bug fixes and Misc cleanups.
    v3:
    - Add iscsi_session_update_params() in initiator_common.c and replace
      iscsi_session_set_params() with iscsi_session_update_params() in
      mgmt_ipc_session_update().
    - Make it possible to set node.session.timeo.replacement_timeout to "-1".

Signed-off-by: Tomoaki Nishimura <[email protected]>
---
 usr/config.h           |   3 +
 usr/initiator.h        |   2 +
 usr/initiator_common.c |  88 ++++++++++++++++++++++++++++
 usr/iscsiadm.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++--
 usr/mgmt_ipc.c         |  56 ++++++++++++++++++
 usr/mgmt_ipc.h         |   1 +
 6 files changed, 300 insertions(+), 4 deletions(-)

diff --git a/usr/config.h b/usr/config.h
index fd31a54..93a84ac 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -39,6 +39,9 @@
 /* max len of interface */
 #define ISCSI_MAX_IFACE_LEN    65
 
+/* flag of excluded session update */
+#define NO_UPDATE      -2
+
 /* the following structures store the options set in the config file.
  * a structure is defined for each logically-related group of options.
  * if you are adding a new option, first check if it should belong
diff --git a/usr/initiator.h b/usr/initiator.h
index c34625b..cefcfbc 100644
--- a/usr/initiator.h
+++ b/usr/initiator.h
@@ -359,5 +359,7 @@ extern int iscsi_set_net_config(struct iscsi_transport *t,
                                iscsi_session_t *session,
                                struct iface_rec *iface);
 extern void iscsi_session_init_params(struct iscsi_session *session);
+extern int iscsi_session_update_params(struct iscsi_conn *conn,
+                                       node_rec_t *rec);
 
 #endif /* INITIATOR_H */
diff --git a/usr/initiator_common.c b/usr/initiator_common.c
index 8ff993d..bfa1ed7 100644
--- a/usr/initiator_common.c
+++ b/usr/initiator_common.c
@@ -637,6 +637,94 @@ TODO handle this
        return 0;
 }
 
+#define MAX_UPDATE_PARAMS 7
+
+int iscsi_session_update_params(struct iscsi_conn *conn, node_rec_t *rec)
+{
+       struct iscsi_session *session = conn->session;
+       int i, rc;
+        struct connparam {
+                 int param;
+                 int type;
+                 void *value;
+                 int conn_only;
+        } conntbl[MAX_UPDATE_PARAMS] = {
+                 {
+                       .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
+                       .value = &rec->session.timeo.replacement_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+                 }, {
+                       .param = ISCSI_PARAM_FAST_ABORT,
+                       .value = &rec->session.iscsi.FastAbort,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+                 }, {
+                       .param = ISCSI_PARAM_ABORT_TMO,
+                       .value = &rec->session.err_timeo.abort_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+                 }, {
+                       .param = ISCSI_PARAM_LU_RESET_TMO,
+                       .value = &rec->session.err_timeo.lu_reset_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+                 }, {
+                       .param = ISCSI_PARAM_TGT_RESET_TMO,
+                       .value = &rec->session.err_timeo.tgt_reset_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+                 }, {
+                       .param = ISCSI_PARAM_PING_TMO,
+                       .value = &rec->conn[conn->id].timeo.noop_out_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+                 }, {
+                       .param = ISCSI_PARAM_RECV_TMO,
+                       .value = &rec->conn[conn->id].timeo.noop_out_interval,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+                 },
+        };
+
+       for (i = 0; i < MAX_UPDATE_PARAMS; i++) {
+               if (conntbl[i].type == ISCSI_INT) {
+                       if (*((int *)conntbl[i].value) == NO_UPDATE)
+                               continue;
+               }
+
+               if (!(session->param_mask & (1ULL << conntbl[i].param)))
+                       continue;
+
+               rc = ipc->set_param(session->t->handle, session->id,
+                                  conn->id, conntbl[i].param, conntbl[i].value,
+                                  conntbl[i].type);
+               if (rc && rc != -ENOSYS) {
+                       log_error("can't set operational parameter %d for "
+                                 "connection %d:%d, retcode %d (%d)",
+                                 conntbl[i].param, session->id, conn->id,
+                                 rc, errno);
+                       return -EPERM;
+               }
+
+               if (rc == -ENOSYS) {
+                       switch (conntbl[i].param) {
+                       case ISCSI_PARAM_PING_TMO:
+                               /*
+                                * older kernels may not support nops
+                                * in kernel
+                                */
+                               conn->userspace_nop = 1;
+                               break;
+                       }
+               }
+               print_param_value(conntbl[i].param, conntbl[i].value,
+                                 conntbl[i].type);
+       }
+
+       return 0;
+}
+
 int iscsi_set_net_config(struct iscsi_transport *t, iscsi_session_t *session,
                         struct iface_rec *iface)
 {
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index f886d39..c967aff 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -58,6 +58,10 @@
 static char program_name[] = "iscsiadm";
 static char config_file[TARGET_NAME_MAXLEN];
 extern struct iscsi_ipc *ipc;
+static struct iscsi_rec_params {
+       struct node_rec         *rec;
+       struct list_head        *params;
+};
 
 enum iscsiadm_mode {
        MODE_DISCOVERY,
@@ -3209,6 +3213,125 @@ ping_exit:
        return rc;
 }
 
+static int verify_session_update_params(struct list_head *params)
+{
+       int i;
+       struct user_param *param;
+       char key[NAME_MAXVAL];
+
+       list_for_each_entry(param, params, list) {
+               if (strcmp(param->name, SESSION_REPLACEMENT_TMO) == 0)
+                       continue;
+               else if (strcmp(param->name, SESSION_ABORT_TMO) == 0)
+                       continue;
+               else if (strcmp(param->name, SESSION_FAST_ABORT) == 0)
+                       continue;
+               else if (strcmp(param->name, SESSION_LU_RESET_TMO) == 0)
+                       continue;
+               else if (strcmp(param->name, SESSION_TGT_RESET_TMO) == 0)
+                       continue;
+               else {
+                       for (i = 0; i < ISCSI_CONN_MAX; i++) {
+
+                               sprintf(key, CONN_NOP_INT, i);
+                               if (strcmp(param->name, key) == 0)
+                                       continue;
+
+                               sprintf(key, CONN_NOP_TMO, i);
+                               if (strcmp(param->name, key) == 0)
+                                       continue;
+
+                               printf("%s is unsupported in session update.\n",
+                                       param->name);
+                               return ISCSI_ERR;
+                       }
+               }
+       }
+
+       return ISCSI_SUCCESS;
+}
+
+static void init_rec_for_session_update(node_rec_t *rec)
+{
+       int i;
+
+       rec->session.timeo.replacement_timeout = NO_UPDATE;
+       rec->session.err_timeo.abort_timeout = NO_UPDATE;
+       rec->session.iscsi.FastAbort = NO_UPDATE;
+       rec->session.err_timeo.lu_reset_timeout = NO_UPDATE;
+       rec->session.err_timeo.tgt_reset_timeout = NO_UPDATE;
+       for (i = 0; i < ISCSI_CONN_MAX; i++) {
+               rec->conn[i].timeo.noop_out_interval = NO_UPDATE;
+               rec->conn[i].timeo.noop_out_timeout = NO_UPDATE;
+       }
+}
+
+static int
+session_update(struct iscsi_rec_params *rec_params, struct session_info *info)
+{
+       int rc;
+       node_rec_t *node_rec;
+       struct list_head *params = rec_params->params;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+
+       if (!rec_params->rec) {
+               rec_params->rec = idbm_create_rec(info->targetname, info->tpgt,
+                                       info->persistent_address,
+                                       info->persistent_port, &info->iface, 1);
+               if (!rec_params->rec)
+                       return ISCSI_ERR_NOMEM;
+       }
+       node_rec = rec_params->rec;
+
+       rc = verify_session_update_params(params);
+       if (rc)
+               return rc;
+
+       init_rec_for_session_update(node_rec);
+
+       rc = idbm_node_set_rec_from_param(params, node_rec, 1);
+       if (rc) {
+               log_error("Set rec from params failed.\n");
+               return rc;
+       }
+
+       req.command = MGMT_IPC_SESSION_UPDATE;
+       req.u.session.sid = info->sid;
+       memcpy(&req.u.session.rec, node_rec, sizeof(node_rec_t));
+       rc = iscsid_exec_req(&req, &rsp, 1);
+       if (rc)
+               return rc;
+
+       printf("Session update [sid: %d, target: %s, portal: %s,%d]\n",
+               info->sid, info->targetname, info->persistent_address,
+               info->port);
+
+       return rc;
+}
+
+static int session_update_all(struct list_head *params)
+{
+       int rc, num_found = 0;
+       struct iscsi_rec_params rec_params;
+
+       rec_params.rec = NULL;
+       rec_params.params = params;
+
+       rc = iscsi_sysfs_for_each_session(&rec_params, &num_found,
+                                                       session_update, 0);
+       if (rc) {
+               log_error("Could not execute operation on all sessions: %s",
+                       iscsi_err_to_str(rc));
+               return rc;
+       } else if (!num_found) {
+               log_error("No session found.");
+               return ISCSI_ERR_NO_OBJS_FOUND;
+       }
+
+       return ISCSI_SUCCESS;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -3230,6 +3353,7 @@ main(int argc, char **argv)
        uint64_t index = ULLONG_MAX;
        struct user_param *param;
        struct list_head params;
+       struct iscsi_rec_params rec_params;
 
        INIT_LIST_HEAD(&params);
        INIT_LIST_HEAD(&ifaces);
@@ -3647,14 +3771,36 @@ main(int argc, char **argv)
                                rec->session.multiple = 1;
                        }
 
-                       /* drop down to node ops */
-                       rc = exec_node_op(op, do_login, do_logout, do_show,
-                                         do_rescan, do_stats, info_level,
-                                         rec, &params);
+                       if (!(op & OP_NONPERSISTENT)) {
+                               rc = exec_node_op(op, do_login, do_logout,
+                                                       do_show, do_rescan,
+                                                       do_stats, info_level,
+                                                       rec, &params);
+                               if (rc)
+                                       goto free_info;
+                       }
+                       if (op == OP_UPDATE || op == OP_NONPERSISTENT) {
+                               rec_params.rec = rec;
+                               rec_params.params = &params;
+                               rc = session_update(&rec_params, info);
+                       }
 free_info:
                        free(info);
                        goto out;
                } else {
+                       if (op == OP_UPDATE || op == OP_NONPERSISTENT) {
+                               if (!(op & OP_NONPERSISTENT)) {
+                                       rc = exec_node_op(op, do_login,
+                                                       do_logout, do_show,
+                                                       do_rescan, do_stats,
+                                                       info_level, rec,
+                                                       &params);
+                                       if (rc)
+                                               goto out;
+                               }
+                               rc = session_update_all(&params);
+                               goto out;
+                       }
                        if (op == OP_NEW) {
                                log_error("session mode: Operation 'new' only "
                                          "allowed with specific session IDs");
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
index ee037d9..034ea36 100644
--- a/usr/mgmt_ipc.c
+++ b/usr/mgmt_ipc.c
@@ -295,6 +295,61 @@ mgmt_ipc_notify_common(queue_task_t *qtask, int 
(*handler)(int, char **))
        return ISCSI_SUCCESS;
 }
 
+#define MAX_UPDATE_PARAMS 7
+
+static int mgmt_ipc_session_update(queue_task_t *qtask)
+{
+       int rc, i, sid = qtask->req.u.session.sid;
+       node_rec_t *rec = &qtask->req.u.session.rec;
+       iscsi_session_t *session;
+       struct iscsi_conn *conn;
+
+       session = session_find_by_sid(sid);
+       if (!session)
+               return ISCSI_ERR_SESS_NOT_FOUND;
+
+       for (i = 0; i < ISCSI_CONN_MAX; i++) {
+               conn = &session->conn[i];
+
+               rc = iscsi_session_update_params(conn, rec);
+               if (rc) {
+                       log_error("iscsi_session_update_params(): IPC error %d"
+                                 " session [%02d]" , rc, sid);
+                       return ISCSI_ERR_INTERNAL;
+               }
+
+               if (rec->conn[i].timeo.noop_out_timeout != NO_UPDATE)
+                       conn->noop_out_timeout =
+                               rec->conn[i].timeo.noop_out_timeout;
+
+               if (rec->conn[i].timeo.noop_out_interval != NO_UPDATE)
+                       conn->noop_out_interval =
+                               rec->conn[i].timeo.noop_out_interval;
+
+       }
+
+       if (rec->session.timeo.replacement_timeout != NO_UPDATE)
+               session->replacement_timeout =
+                               rec->session.timeo.replacement_timeout;
+
+       if (rec->session.iscsi.FastAbort != NO_UPDATE)
+               session->fast_abort = rec->session.iscsi.FastAbort;
+
+       if (rec->session.err_timeo.abort_timeout != NO_UPDATE)
+               session->abort_timeout = rec->session.err_timeo.abort_timeout;
+
+       if (rec->session.err_timeo.lu_reset_timeout != NO_UPDATE)
+               session->lu_reset_timeout =
+                               rec->session.err_timeo.lu_reset_timeout;
+
+       if (rec->session.err_timeo.tgt_reset_timeout != NO_UPDATE)
+               session->tgt_reset_timeout =
+                               rec->session.err_timeo.tgt_reset_timeout;
+
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
 /* Replace these dummies as you implement them
    elsewhere */
 static int
@@ -529,6 +584,7 @@ static mgmt_ipc_fn_t *      
mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = {
 [MGMT_IPC_NOTIFY_DEL_NODE]     = mgmt_ipc_notify_del_node,
 [MGMT_IPC_NOTIFY_ADD_PORTAL]   = mgmt_ipc_notify_add_portal,
 [MGMT_IPC_NOTIFY_DEL_PORTAL]   = mgmt_ipc_notify_del_portal,
+[MGMT_IPC_SESSION_UPDATE]      = mgmt_ipc_session_update,
 };
 
 void mgmt_ipc_handle(int accept_fd)
diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
index 55972ed..1a06403 100644
--- a/usr/mgmt_ipc.h
+++ b/usr/mgmt_ipc.h
@@ -46,6 +46,7 @@ typedef enum iscsiadm_cmd {
        MGMT_IPC_NOTIFY_DEL_NODE        = 17,
        MGMT_IPC_NOTIFY_ADD_PORTAL      = 18,
        MGMT_IPC_NOTIFY_DEL_PORTAL      = 19,
+       MGMT_IPC_SESSION_UPDATE         = 20,
 
        __MGMT_IPC_MAX_COMMAND
 } iscsiadm_cmd_e;
-- 
1.9.3

-- 
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 http://groups.google.com/group/open-iscsi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to