From: Adheer Chandravanshi <[email protected]> Add support to maintain and show some host statistics in iscsid. This provides following host specific stats: iscsi_login_accept_rsps iscsi_login_other_fail_rsps iscsi_login_negotiate_fails iscsi_login_authenticate_fails iscsi_login_auth_fail_rsps iscsi_login_redirect_rsps iscsi_logout_normals iscsi_logout_others iscsi_connection_timeout_errors iscsi_session_failures
Signed-off-by: Adheer Chandravanshi <[email protected]> --- include/iscsi_if.h | 1 + usr/discovery.c | 32 +++++++++- usr/event_poll.c | 12 +++- usr/event_poll.h | 3 +- usr/host.c | 45 ++++++++++++++ usr/host.h | 14 +++++ usr/initiator.c | 100 +++++++++++++++++++++++++----- usr/initiator.h | 16 ++++- usr/initiator_common.c | 162 ++++++++++++++++++++++++++++++++++++++++++++----- usr/iscsiadm.c | 25 +++++--- usr/iscsid.c | 12 +++- usr/iscsistart.c | 10 ++- usr/mgmt_ipc.c | 19 ++++++ usr/mgmt_ipc.h | 9 +++ usr/netlink.c | 3 +- usr/transport.c | 1 + usr/transport.h | 1 + 17 files changed, 416 insertions(+), 49 deletions(-) diff --git a/include/iscsi_if.h b/include/iscsi_if.h index 9d15811..0576dfb 100644 --- a/include/iscsi_if.h +++ b/include/iscsi_if.h @@ -536,6 +536,7 @@ enum iscsi_err { ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19, ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20, ISCSI_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21, + ISCSI_ERR_NOP_TIMEDOUT = ISCSI_ERR_BASE + 22, }; /* diff --git a/usr/discovery.c b/usr/discovery.c index 593d226..4d23381 100644 --- a/usr/discovery.c +++ b/usr/discovery.c @@ -1060,6 +1060,11 @@ done: conn->socket_fd = -1; } session->id = -1; + + if (session->host) { + iscsi_host_put(session->host); + session->host = NULL; + } } static int iscsi_create_leading_conn(struct iscsi_session *session) @@ -1104,7 +1109,15 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) * if offload is used. */ session->conn[0].bind_ep = 1; - session->hostno = host_no; + /* + * some offload functions need the host so create now for + * them + */ + session->host = iscsi_host_create(host_no); + if (!session->host) { + rc = ISCSI_ERR_NOMEM; + goto close_ipc; + } } rc = iscsi_host_set_net_params(iface, session); @@ -1113,7 +1126,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) rc); if (rc != ISCSI_ERR_AGAIN) rc = ISCSI_ERR_INTERNAL; - goto close_ipc; + goto free_host; } /* create interconnect endpoint */ @@ -1121,7 +1134,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) rc = t->template->ep_connect(conn, 1); if (rc < 0) { rc = ISCSI_ERR_TRANS; - goto close_ipc; + goto free_host; } do { @@ -1150,6 +1163,15 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) rc = ISCSI_ERR_INTERNAL; goto disconnect; } + + if (!session->host) { + session->host = iscsi_host_create(host_no); + if (!session->host) { + rc = ISCSI_ERR_NOMEM; + goto disconnect; + } + } + log_debug(2, "%s discovery created session %u", __FUNCTION__, session->id); session->isid[3] = (session->id >> 16) & 0xff; @@ -1196,6 +1218,10 @@ disconnect: session->id = -1; } +free_host: + iscsi_host_put(session->host); + session->host = NULL; + close_ipc: if (conn->socket_fd >= 0) { ipc->ctldev_close(); diff --git a/usr/event_poll.c b/usr/event_poll.c index 209ee02..52391db 100644 --- a/usr/event_poll.c +++ b/usr/event_poll.c @@ -38,6 +38,7 @@ #include "actor.h" #include "initiator.h" #include "iscsi_err.h" +#include "host.h" static unsigned int reap_count; @@ -121,7 +122,8 @@ static int shutdown_wait_pids(void) #define POLL_CTRL 0 #define POLL_IPC 1 #define POLL_ALARM 2 -#define POLL_MAX 3 +#define POLL_UDEV 3 +#define POLL_MAX 4 static int event_loop_stop; static queue_task_t *shutdown_qtask; @@ -132,7 +134,8 @@ void event_loop_exit(queue_task_t *qtask) event_loop_stop = 1; } -void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) +void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, + int udev_fd) { struct pollfd poll_array[POLL_MAX]; int res, has_shutdown_children = 0; @@ -156,6 +159,8 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) poll_array[POLL_IPC].events = POLLIN; poll_array[POLL_ALARM].fd = sig_fd; poll_array[POLL_ALARM].events = POLLIN; + poll_array[POLL_UDEV].fd = udev_fd; + poll_array[POLL_UDEV].events = POLLIN; event_loop_stop = 0; while (1) { @@ -192,6 +197,9 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) log_debug(1, "Poll was woken by an alarm"); } } + + if (poll_array[POLL_UDEV].revents) + udev_event_handle(udev_fd); } else if (res < 0) { if (errno == EINTR) { log_debug(1, "event_loop interrupted"); diff --git a/usr/event_poll.h b/usr/event_poll.h index c0eed5c..0a7ed7c 100644 --- a/usr/event_poll.h +++ b/usr/event_poll.h @@ -25,7 +25,8 @@ struct queue_task; int shutdown_callback(pid_t pid); void reap_proc(void); void reap_inc(void); -void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd); +void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, + int udev_fd); void event_loop_exit(struct queue_task *qtask); #endif diff --git a/usr/host.c b/usr/host.c index f2052d3..b0dc914 100644 --- a/usr/host.c +++ b/usr/host.c @@ -35,6 +35,9 @@ #include "iface.h" #include "iscsi_err.h" #include "iscsi_netlink.h" +#include "iscsid_req.h" + +LIST_HEAD(iscsi_host); static int match_host_to_session(void *data, struct session_info *info) { @@ -424,3 +427,45 @@ int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs) return count; } + +int host_print_login_stats(int host_no) +{ + int rc; + iscsiadm_req_t req; + iscsiadm_rsp_t rsp; + struct iscsi_login_stats *stats; + + memset(&req, 0, sizeof(req)); + req.command = MGMT_IPC_HOST_STATS; + req.u.host_login_stats.host_no = host_no; + + rc = iscsid_exec_req(&req, &rsp, 1); + if (rc) + return rc; + + stats = &rsp.u.host_login_stats.stats; + + printf("Host Login Statistics:\n" + "\tiscsi_login_accept_rsps: %llu\n" + "\tiscsi_login_other_fail_rsps: %llu\n" + "\tiscsi_login_negotiate_fails: %llu\n" + "\tiscsi_login_authenticate_fails: %llu\n" + "\tiscsi_login_auth_fail_rsps: %llu\n" + "\tiscsi_login_redirect_rsps: %llu\n" + "\tiscsi_logout_normals: %llu\n" + "\tiscsi_logout_others: %llu\n" + "\tiscsi_connection_timeout_errors: %llu\n" + "\tiscsi_session_failures: %llu\n", + (unsigned long long)stats->login_accept_rsps, + (unsigned long long)stats->login_other_fail_rsps, + (unsigned long long)stats->login_negotiate_fails, + (unsigned long long)stats->login_authenticate_fails, + (unsigned long long)stats->login_auth_fail_rsps, + (unsigned long long)stats->login_redirect_rsps, + (unsigned long long)stats->logout_normals, + (unsigned long long)stats->logout_others, + (unsigned long long)stats->connection_timeout_errors, + (unsigned long long)stats->session_failures); + + return 0; +} diff --git a/usr/host.h b/usr/host.h index 149aa0d..1a16db7 100644 --- a/usr/host.h +++ b/usr/host.h @@ -16,7 +16,21 @@ struct host_info { uint32_t host_no; }; +struct iscsi_login_stats { + uint64_t login_accept_rsps; + uint64_t login_other_fail_rsps; + uint64_t login_negotiate_fails; + uint64_t login_authenticate_fails; + uint64_t login_auth_fail_rsps; + uint64_t login_redirect_rsps; + uint64_t logout_normals; + uint64_t logout_others; + uint64_t connection_timeout_errors; + uint64_t session_failures; +}; + extern int host_info_print(int info_level, uint32_t host_no); extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs); +extern int host_print_login_stats(int host_no); #endif diff --git a/usr/initiator.c b/usr/initiator.c index 8cd1896..24f9368 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -142,6 +142,7 @@ static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context) ev_context->allocated = 0; } + static void session_online_devs(int host_no, int sid) { iscsi_sysfs_for_each_device(NULL, host_no, sid, @@ -152,14 +153,18 @@ static conn_login_status_e __login_response_status(iscsi_conn_t *conn, enum iscsi_login_status login_status) { + struct iscsi_login_stats *stats = &conn->session->host->login_stats; + switch (login_status) { case LOGIN_OK: /* check the status class and detail */ return CONN_LOGIN_SUCCESS; case LOGIN_REDIRECT: + stats->login_redirect_rsps++; return CONN_LOGIN_IMM_REDIRECT_RETRY; case LOGIN_IO_ERROR: case LOGIN_REDIRECTION_FAILED: + stats->login_other_fail_rsps++; return CONN_LOGIN_RETRY; default: log_error("Login error (Login status %d) on conn %d", conn->id, @@ -175,11 +180,15 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, uint8_t status_class, uint8_t status_detail) { iscsi_conn_t *conn = &session->conn[cid]; + struct iscsi_login_stats *stats = &session->host->login_stats; switch (status_class) { case ISCSI_STATUS_CLS_SUCCESS: + stats->login_accept_rsps++; return CONN_LOGIN_SUCCESS; case ISCSI_STATUS_CLS_REDIRECT: + stats->login_redirect_rsps++; + switch (status_detail) { case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP: return CONN_LOGIN_IMM_RETRY; @@ -204,15 +213,18 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, log_error("session %d login rejected: Initiator " "failed authentication with target", session->id); + stats->login_auth_fail_rsps++; return CONN_LOGIN_AUTH_FAILED; case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN: log_error("conn %d login rejected: initiator " "failed authorization with target", conn->id); + stats->login_authenticate_fails++; return CONN_LOGIN_AUTH_FAILED; case ISCSI_LOGIN_STATUS_TGT_NOT_FOUND: log_error("conn %d login rejected: initiator " "error - target not found (%02x/%02x)", conn->id, status_class, status_detail); + stats->login_other_fail_rsps++; return CONN_LOGIN_FAILED; case ISCSI_LOGIN_STATUS_NO_VERSION: /* @@ -224,16 +236,30 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, "version (%02x/%02x), non-retryable, " "giving up", conn->id, status_class, status_detail); + stats->login_other_fail_rsps++; + return CONN_LOGIN_FAILED; + case ISCSI_LOGIN_STATUS_TGT_REMOVED: + log_error("conn %d login rejected: target removed " + "(%02x/%02x)", conn->id, status_class, + status_detail); + stats->login_negotiate_fails++; + case ISCSI_LOGIN_STATUS_MISSING_FIELDS: + log_error("conn %d login rejected: missing parameters " + "(%02x/%02x)", conn->id, status_class, + status_detail); + stats->login_negotiate_fails++; return CONN_LOGIN_FAILED; default: log_error("conn %d login rejected: initiator " - "error (%02x/%02x)", conn->id, status_class, - status_detail); + "error (%02x/%02x)", conn->id, status_class, + status_detail); + stats->login_other_fail_rsps++; return CONN_LOGIN_FAILED; } case ISCSI_STATUS_CLS_TARGET_ERR: log_error("conn %d login rejected: target error " "(%02x/%02x)", conn->id, status_class, status_detail); + stats->login_other_fail_rsps++; /* * We have no idea what the problem is. But spec says initiator * may retry later. @@ -243,6 +269,7 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, log_error("conn %d login response with unknown status " "class 0x%x, detail 0x%x", conn->id, status_class, status_detail); + stats->login_other_fail_rsps++; break; } @@ -409,7 +436,11 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc) * if offload is used. */ session->conn[0].bind_ep = 1; - session->hostno = hostno; + session->host = iscsi_host_create(hostno); + if (!session->host) { + *rc = ISCSI_ERR_NOMEM; + goto free_session; + } } else if (*rc == ISCSI_ERR_HOST_NOT_FOUND) { goto free_session; } else { @@ -447,6 +478,7 @@ static void __session_destroy(iscsi_session_t *session) { log_debug(1, "destroying session"); + iscsi_host_put(session->host); list_del(&session->list); iscsi_flush_context_pool(session); session_release(session); @@ -871,11 +903,26 @@ static void session_conn_error(void *data) iscsi_ev_context_put(ev_context); + /* + * kernel could return some errors before session and host is fully + * setup + */ + if (session->host) + session->host->login_stats.session_failures++; + switch (error) { case ISCSI_ERR_INVALID_HOST: if (session_conn_shutdown(conn, NULL, ISCSI_SUCCESS)) log_error("BUG: Could not shutdown session."); break; + case ISCSI_ERR_NOP_TIMEDOUT: + case ISCSI_ERR_SCSI_EH_SESSION_RST: + /* + * Connection/session was dropped due to scsi command, TMF, or + * Nop-as-ping timing out. + */ + session->host->login_stats.connection_timeout_errors++; + /* fall through */ default: __conn_error_handle(session, conn); } @@ -1048,7 +1095,8 @@ setup_full_feature_phase(iscsi_conn_t *conn) * don't want to re-scan it on recovery. */ if (conn->id == 0) - session_scan_host(session, session->hostno, c->qtask); + session_scan_host(session, session->host->host_no, + c->qtask); log_warning("Connection%d:%d to [target: %s, portal: %s,%d] " "through [iface: %s] is operational now", @@ -1059,7 +1107,7 @@ setup_full_feature_phase(iscsi_conn_t *conn) } else { session->notify_qtask = NULL; - session_online_devs(session->hostno, session->id); + session_online_devs(session->host->host_no, session->id); mgmt_ipc_write_rsp(c->qtask, ISCSI_SUCCESS); log_warning("connection%d:%d is operational after recovery " "(%d attempts)", session->id, conn->id, @@ -1170,6 +1218,7 @@ static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr) static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr) { struct iscsi_logout_rsp *logout_rsp = (struct iscsi_logout_rsp *)hdr; + iscsi_session_t *session = conn->session; log_debug(3, "Recv: logout response %d", logout_rsp->response); if (logout_rsp->response == 2 || logout_rsp->response == 3) { @@ -1177,6 +1226,12 @@ static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr) log_debug(4, "logout rsp returned time2wait %u", conn->session->def_time2wait); } + + if (!logout_rsp->response) + session->host->login_stats.logout_normals++; + else + session->host->login_stats.logout_others++; + /* TODO process the hdr */ __conn_error_handle(conn->session, conn); } @@ -1203,7 +1258,8 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) } if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e) - session_scan_host(session, session->hostno, NULL); + session_scan_host(session, session->host->host_no, + NULL); break; case ISCSI_ASYNC_MSG_REQUEST_LOGOUT: log_warning("Target requests logout within %u seconds for " @@ -1242,8 +1298,11 @@ static void iscsi_recv_login_rsp(struct iscsi_conn *conn) struct iscsi_session *session = conn->session; iscsi_login_context_t *c = &conn->login_context; int err = ISCSI_ERR_FATAL_LOGIN; + struct iscsi_login_stats *stats = &session->host->login_stats; - if (iscsi_login_rsp(session, c)) { + if (!iscsi_login_rsp(session, c)) { + stats->login_accept_rsps++; + } else { log_debug(1, "login_rsp ret (%d)", c->ret); switch (__login_response_status(conn, c->ret)) { @@ -1418,7 +1477,7 @@ static void session_increase_wq_priority(struct iscsi_session *session) *proc_name_end = '\0'; if (sscanf(proc_name, "iscsi_q_%u\n", &host_no) == 1) { - if (host_no == session->hostno) { + if (host_no == session->host->host_no) { if (!setpriority(PRIO_PROCESS, pid, session->nrec.session.xmit_thread_priority)) { closedir(proc_dir); @@ -1462,9 +1521,16 @@ retry_create: } if (!err) { - session->hostno = host_no; + if (!session->host) { + session->host = iscsi_host_create(host_no); + if (!session->host) { + /* caller will destroy session for us */ + return -ENOMEM; + } + } session_increase_wq_priority(session); } + return err; } @@ -1536,6 +1602,7 @@ static void session_conn_poll(void *data) iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL); return; } + ev_context->data = qtask; /* not connected yet, check later */ iscsi_sched_ev_context(ev_context, conn, 1, EV_CONN_POLL); @@ -1550,8 +1617,8 @@ static void session_conn_poll(void *data) err = ISCSI_ERR_INTERNAL; goto cleanup; } - log_debug(3, "created new iSCSI session sid %d host " - "no %u", session->id, session->hostno); + log_debug(3, "created new iSCSI session sid %d host %u", + session->id, session->host->host_no); err = ipc->create_conn(session->t->handle, session->id, conn->id, &conn->id); @@ -1656,7 +1723,7 @@ static void session_conn_process_login(void *data) * logged in */ log_debug(3, "session created sid %u host no %d", session->id, - session->hostno); + session->host->host_no); if (session->r_stage == R_STAGE_NO_CHANGE || session->r_stage == R_STAGE_SESSION_REDIRECT) { @@ -1664,7 +1731,7 @@ static void session_conn_process_login(void *data) * scan host is one-time deal. We * don't want to re-scan it on recovery. */ - session_scan_host(session, session->hostno, + session_scan_host(session, session->host->host_no, c->qtask); session->notify_qtask = NULL; @@ -1995,6 +2062,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) { iscsi_session_t *session; struct iscsi_transport *t; + uint32_t hostno; int err; t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name); @@ -2006,12 +2074,16 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) return ISCSI_ERR_LOGIN; session->id = sid; - session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err); + hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err); if (err) { log_error("Could not get hostno for session %d", sid); goto destroy_session; } + session->host = iscsi_host_create(hostno); + if (!session->host) + goto destroy_session; + session->r_stage = R_STAGE_SESSION_REOPEN; err = sync_conn(session, 0); diff --git a/usr/initiator.h b/usr/initiator.h index c11d77f..ca0a191 100644 --- a/usr/initiator.h +++ b/usr/initiator.h @@ -32,6 +32,7 @@ #include "config.h" #include "actor.h" #include "list.h" +#include "host.h" #define ISCSI_CONFIG_ROOT "/etc/iscsi/" @@ -191,6 +192,13 @@ typedef struct queue_task { void *payload; } queue_task_t; +struct iscsi_host { + struct iscsi_login_stats login_stats; + uint32_t host_no; + uint32_t ref_count; + struct list_head list; +}; + struct iscsi_transport_template; struct iscsi_transport; @@ -198,7 +206,7 @@ struct iscsi_transport; typedef struct iscsi_session { struct list_head list; uint32_t id; - uint32_t hostno; + struct iscsi_host *host; char netdev[IFNAMSIZ]; struct iscsi_transport *t; uint8_t use_ipc; @@ -359,4 +367,10 @@ extern int iscsi_set_net_config(struct iscsi_transport *t, struct iface_rec *iface); extern void iscsi_session_init_params(struct iscsi_session *session); +/* initiator host code */ +extern struct iscsi_host *iscsi_host_find_by_host_no(uint32_t host_no); +extern void iscsi_host_put(struct iscsi_host *host); +extern struct iscsi_host *iscsi_host_create(uint32_t host_no); +extern int udev_event_listen(void); +extern void udev_event_handle(int udev_fd); #endif /* INITIATOR_H */ diff --git a/usr/initiator_common.c b/usr/initiator_common.c index c02643a..e040bde 100644 --- a/usr/initiator_common.c +++ b/usr/initiator_common.c @@ -23,6 +23,10 @@ #include <stdio.h> #include <stdlib.h> #include <errno.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/socket.h> +#include <linux/netlink.h> #include "initiator.h" #include "transport.h" @@ -37,6 +41,143 @@ #include "iscsi_err.h" #include "iscsi_net_util.h" +#define UEVENT_BUFFER_SIZE 2048 + +static LIST_HEAD(iscsi_hosts); + +struct iscsi_host *iscsi_host_find_by_host_no(uint32_t host_no) +{ + struct iscsi_host *host; + + list_for_each_entry(host, &iscsi_hosts, list) { + if (host->host_no == host_no) { + log_debug(7, "Found iSCSI host %d\n", host->host_no); + return host; + } + } + + log_debug(7, "iSCSI host %d not found\n", host->host_no); + return NULL; +} + +static void iscsi_host_get(struct iscsi_host *host) +{ + host->ref_count++; +} + +#define SCSI_HOST_SUBSYS "scsi_host" +void iscsi_host_put(struct iscsi_host *host) +{ + char id[NAME_SIZE]; + char devpath[PATH_SIZE]; + + if (!host) + return; + + snprintf(id, sizeof(id), "host%u", host->host_no); + + /* For sotware iSCSI if all sessions are logout, sysfs host will be + * destroyed and we will not get devpath */ + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + SCSI_HOST_SUBSYS, id)) { + log_error("Could not lookup devpath for %s.\n", id); + goto free_host; + } + + /* If we have valid host path, its offload iSCSI do not destroy host */ + return; +free_host: + host->ref_count--; + if (!host->ref_count) { + log_debug(1, "free %s\n", id); + list_del(&host->list); + free(host); + } +} + +void iscsi_offload_host_put(uint32_t host_no) +{ + struct iscsi_host *host = iscsi_host_find_by_host_no(host_no); + + if (!host) + return; + + log_debug(1, "free host%u\n", host->host_no); + list_del(&host->list); + free(host); +} + +struct iscsi_host *iscsi_host_create(uint32_t host_no) +{ + struct iscsi_host *host = iscsi_host_find_by_host_no(host_no); + + if (!host) { + host = calloc(1, sizeof(*host)); + if (!host) + return NULL; + host->host_no = host_no; + INIT_LIST_HEAD(&host->list); + list_add_tail(&host->list, &iscsi_hosts); + } + + iscsi_host_get(host); + return host; +} + +int udev_event_listen(void) +{ + int udev_fd = -1; + int ret = -1; + struct sockaddr_nl snl; + + bzero(&snl, sizeof(struct sockaddr_nl)); + snl.nl_family = AF_NETLINK; + snl.nl_pid = getpid(); + snl.nl_groups = 1; + + udev_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (udev_fd < 0) { + log_error("Can not create udev event socket\n"); + return udev_fd; + } + + ret = bind(udev_fd, (struct sockaddr *)&snl, + sizeof(struct sockaddr_nl)); + if (ret < 0) { + log_error("Can not bind udev event socket\n"); + close(udev_fd); + return ret; + } + + return udev_fd; +} + +void udev_event_handle(int udev_fd) +{ + char buf[UEVENT_BUFFER_SIZE] = {0}; + char *tmp_buf1, *tmp_buf2; + char *pos; + uint32_t host_no; + + memset(buf, 0, sizeof(buf)); + recv(udev_fd, &buf, sizeof(buf), 0); + + tmp_buf1 = strstr(buf, "remove"); + if (tmp_buf1 == NULL) + return; + + tmp_buf2 = strstr(tmp_buf1, "iscsi_host"); + if (tmp_buf2 == NULL) + return; + + pos = &tmp_buf2[strlen(tmp_buf2)]; + while (isdigit(pos[-1])) + pos--; + + host_no = atoi(pos); + iscsi_offload_host_put(host_no); +} + struct iscsi_session *session_find_by_sid(uint32_t sid) { struct iscsi_transport *t; @@ -299,7 +440,7 @@ int iscsi_host_set_params(struct iscsi_session *session) }; for (i = 0; i < MAX_HOST_PARAMS; i++) { - if (host_set_param(t, session->hostno, + if (host_set_param(t, session->host->host_no, hosttbl[i].param, hosttbl[i].value, hosttbl[i].type)) { return EPERM; @@ -631,20 +772,11 @@ int iscsi_set_net_config(struct iscsi_transport *t, iscsi_session_t *session, if (t->template->set_net_config) { /* uip needs the netdev name */ struct host_info hinfo; - int hostno, rc; - - /* this assumes that the netdev or hw address is going to be - set */ - hostno = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc); - if (rc) { - log_debug(4, "Couldn't get host no."); - return rc; - } /* uip needs the netdev name */ if (!strlen(iface->netdev)) { memset(&hinfo, 0, sizeof(hinfo)); - hinfo.host_no = hostno; + hinfo.host_no = session->host->host_no; iscsi_sysfs_get_hostinfo_by_host_no(&hinfo); strcpy(iface->netdev, hinfo.iface.netdev); } @@ -692,7 +824,7 @@ int iscsi_host_set_net_params(struct iface_rec *iface, netdev = iface->netdev; else { memset(&hinfo, 0, sizeof(hinfo)); - hinfo.host_no = session->hostno; + hinfo.host_no = session->host->host_no; iscsi_sysfs_get_hostinfo_by_host_no(&hinfo); netdev = hinfo.iface.netdev; @@ -706,14 +838,14 @@ int iscsi_host_set_net_params(struct iface_rec *iface, if (rc != 0) return rc; - rc = host_set_param(t, session->hostno, + rc = host_set_param(t, session->host->host_no, ISCSI_HOST_PARAM_IPADDRESS, iface->ipaddress, ISCSI_STRING); if (rc) return rc; if (iface_is_bound_by_netdev(iface)) { - rc = host_set_param(t, session->hostno, + rc = host_set_param(t, session->host->host_no, ISCSI_HOST_PARAM_NETDEV_NAME, iface->netdev, ISCSI_STRING); if (rc) @@ -721,7 +853,7 @@ int iscsi_host_set_net_params(struct iface_rec *iface, } if (iface_is_bound_by_hwaddr(iface)) { - rc = host_set_param(t, session->hostno, + rc = host_set_param(t, session->host->host_no, ISCSI_HOST_PARAM_HWADDRESS, iface->hwaddress, ISCSI_STRING); if (rc) diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c index c6705bd..e06d8ef 100644 --- a/usr/iscsiadm.c +++ b/usr/iscsiadm.c @@ -2215,43 +2215,49 @@ static int exec_host_stats_op(int op, int info_level, uint32_t host_no) int rc = ISCSI_SUCCESS; int fd = 0, buf_size = 0; + /* ignore error incase iscsid is not up */ + host_print_login_stats(host_no); + t = iscsi_sysfs_get_transport_by_hba(host_no); if (!t) { log_error("Could not match hostno %u to transport.", host_no); rc = ISCSI_ERR_TRANS_NOT_FOUND; - goto exit_host_stats; + goto done; } + if (!t->template->offload_host_stats) + goto done; + buf_size = sizeof(struct iscsi_offload_host_stats) + sizeof(struct iscsi_uevent); req_buf = calloc(1, buf_size); if (!req_buf) { log_error("Could not allocate memory for host stats request."); rc = ISCSI_ERR_NOMEM; - goto exit_host_stats; + goto done; } fd = ipc->ctldev_open(); if (fd < 0) { rc = ISCSI_ERR_INTERNAL; log_error("Netlink open failed."); - goto exit_host_stats; + goto free_buf; } rc = ipc->get_host_stats(t->handle, host_no, req_buf); if (rc < 0) { - log_error("get_host_stats failed. errno=%d", errno); + log_debug(7, "get_host_stats failed. errno=%d", errno); rc = ISCSI_ERR; - goto exit_host_stats; + } else { + print_host_stats((struct iscsi_offload_host_stats *)(req_buf + + sizeof(struct iscsi_uevent))); } - print_host_stats((struct iscsi_offload_host_stats *)(req_buf + - sizeof(struct iscsi_uevent))); - ipc->ctldev_close(); -exit_host_stats: +free_buf: free(req_buf); +done: return rc; } @@ -3063,6 +3069,7 @@ static uint64_t parse_host_info(char *optarg, int *rc) *rc = ISCSI_ERR_INVAL; } } else { + errno = 0; host_no = strtoull(optarg, NULL, 10); if (errno || (host_no > MAX_HOST_NO)) { if (host_no > MAX_HOST_NO) diff --git a/usr/iscsid.c b/usr/iscsid.c index f8ffd23..abbe16a 100644 --- a/usr/iscsid.c +++ b/usr/iscsid.c @@ -52,6 +52,7 @@ #include "discoveryd.h" #include "iscsid_req.h" #include "iscsi_err.h" +#include "host.h" /* global config info */ struct iscsi_daemon_config daemon_config; @@ -347,6 +348,7 @@ int main(int argc, char *argv[]) struct sigaction sa_old; struct sigaction sa_new; int control_fd; + int udev_fd; pid_t pid; while ((ch = getopt_long(argc, argv, "c:i:fd:nu:g:p:vh", long_options, @@ -413,6 +415,7 @@ int main(int argc, char *argv[]) mgmt_ipc_fd = -1; control_fd = -1; + udev_fd = -1; daemon_config.initiator_name = NULL; daemon_config.initiator_alias = NULL; @@ -421,6 +424,12 @@ int main(int argc, char *argv[]) exit(ISCSI_ERR); } + udev_fd = udev_event_listen(); + if (udev_fd < 0) { + log_close(log_pid); + exit(ISCSI_ERR); + } + if (daemonize) { char buf[64]; int fd = -1; @@ -554,12 +563,13 @@ int main(int argc, char *argv[]) exit(ISCSI_ERR); } - event_loop(ipc, control_fd, mgmt_ipc_fd); + event_loop(ipc, control_fd, mgmt_ipc_fd, udev_fd); idbm_terminate(); sysfs_cleanup(); ipc->ctldev_close(); mgmt_ipc_close(mgmt_ipc_fd); + close(udev_fd); if (daemon_config.initiator_name) free(daemon_config.initiator_name); if (daemon_config.initiator_alias) diff --git a/usr/iscsistart.c b/usr/iscsistart.c index 7ff2236..18a75d5 100644 --- a/usr/iscsistart.c +++ b/usr/iscsistart.c @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) struct boot_context *context, boot_context; struct sigaction sa_old; struct sigaction sa_new; - int control_fd, mgmt_ipc_fd, err; + int control_fd, mgmt_ipc_fd, udev_fd, err; pid_t pid; idbm_node_setup_defaults(&config_rec); @@ -476,6 +476,12 @@ int main(int argc, char *argv[]) exit(ISCSI_ERR_NOMEM); } + udev_fd = udev_event_listen(); + if (udev_fd < 0) { + log_error("Could not setup udev socket\n"); + exit(ISCSI_ERR_NOMEM); + } + control_fd = ipc->ctldev_open(); if (control_fd < 0) exit(ISCSI_ERR_NOMEM); @@ -509,7 +515,7 @@ int main(int argc, char *argv[]) * Start Main Event Loop */ iscsi_initiator_init(); - event_loop(ipc, control_fd, mgmt_ipc_fd); + event_loop(ipc, control_fd, mgmt_ipc_fd, udev_fd); ipc->ctldev_close(); mgmt_ipc_close(mgmt_ipc_fd); free_initiator(); diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c index c16bce9..692e8ad 100644 --- a/usr/mgmt_ipc.c +++ b/usr/mgmt_ipc.c @@ -37,6 +37,7 @@ #include "iscsi_ipc.h" #include "iscsi_err.h" #include "iscsi_util.h" +#include "host.h" #define PEERUSER_MAX 64 #define EXTMSG_MAX (64 * 1024) @@ -347,6 +348,23 @@ mgmt_ipc_notify_del_portal(queue_task_t *qtask) } static int +mgmt_ipc_host_get_login_stats(queue_task_t *qtask) +{ + uint32_t host_no = qtask->req.u.host_login_stats.host_no; + struct iscsi_host *host = iscsi_host_find_by_host_no(host_no); + + if (host == NULL) + return ISCSI_ERR; + + qtask->rsp.u.host_login_stats.host_no = host->host_no; + memcpy(&qtask->rsp.u.host_login_stats.stats, &host->login_stats, + sizeof(struct iscsi_login_stats)); + mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS); + + return ISCSI_SUCCESS; +} + +static int mgmt_peeruser(int sock, char *user) { #if defined(SO_PEERCRED) @@ -530,6 +548,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_HOST_STATS] = mgmt_ipc_host_get_login_stats, }; void mgmt_ipc_handle(int accept_fd) diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h index 55972ed..0423f56 100644 --- a/usr/mgmt_ipc.h +++ b/usr/mgmt_ipc.h @@ -22,6 +22,7 @@ #include "types.h" #include "iscsi_if.h" #include "config.h" +#include "host.h" #define ISCSIADM_NAMESPACE "ISCSIADM_ABSTRACT_NAMESPACE" #define PEERUSER_MAX 64 @@ -46,6 +47,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_HOST_STATS = 20, __MGMT_IPC_MAX_COMMAND } iscsiadm_cmd_e; @@ -77,6 +79,9 @@ typedef struct iscsiadm_req { char value[IFNAMSIZ + 1]; } set_host_param; + struct ipc_msg_host_login_stats { + int host_no; + } host_login_stats; } u; } iscsiadm_req_t; @@ -103,6 +108,10 @@ typedef struct iscsiadm_rsp { int session_state; int conn_state; } session_state; + struct ipc_msg_get_host_login_stats { + int host_no; + struct iscsi_login_stats stats; + } host_login_stats; } u; } iscsiadm_rsp_t; diff --git a/usr/netlink.c b/usr/netlink.c index 2b85efe..d74f723 100644 --- a/usr/netlink.c +++ b/usr/netlink.c @@ -862,7 +862,8 @@ ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking) if (conn->bind_ep) { ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST; ev->u.ep_connect_through_host.non_blocking = non_blocking; - ev->u.ep_connect_through_host.host_no = conn->session->hostno; + ev->u.ep_connect_through_host.host_no = + conn->session->host->host_no; } else { ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT; ev->u.ep_connect.non_blocking = non_blocking; diff --git a/usr/transport.c b/usr/transport.c index 18b7704..4797641 100644 --- a/usr/transport.c +++ b/usr/transport.c @@ -101,6 +101,7 @@ struct iscsi_transport_template qla4xxx = { .name = "qla4xxx", .set_host_ip = SET_HOST_IP_NOT_REQ, .bind_ep_required = 1, + .offload_host_stats = 1, .ep_connect = ktransport_ep_connect, .ep_poll = ktransport_ep_poll, .ep_disconnect = ktransport_ep_disconnect, diff --git a/usr/transport.h b/usr/transport.h index 4d3bdbf..42bc3a5 100644 --- a/usr/transport.h +++ b/usr/transport.h @@ -39,6 +39,7 @@ struct iscsi_transport_template { uint8_t set_host_ip; uint8_t use_boot_info; uint8_t bind_ep_required; + uint8_t offload_host_stats; int (*ep_connect) (struct iscsi_conn *conn, int non_blocking); int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms); void (*ep_disconnect) (struct iscsi_conn *conn); -- 1.8.5.2 -- 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.
