void handle_iscsi_events(int fd) { struct session *session; struct iet_event event; int res; retry: if ((res = nl_read(fd, &event, sizeof(event))) < 0) { if (errno == EAGAIN) return; if (errno == EINTR) goto retry; log_error("read netlink fd (%d)", errno); exit(1); } log_debug(1, "conn %u session %llu target %u, state %u", event.cid, event.sid, event.tid, event.state); switch (event.state) { case E_CONN_CLOSE: if (!(session = session_find_id(event.tid, event.sid))) { log_warning("session %llu not found?", event.sid); goto retry; } if (--session->conn_cnt <= 0) session_remove(session); break; default: log_error("%s(%d) %u\n", __FUNCTION__, __LINE__, event.state); exit(-1); break; } }
static int kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid, char *statsbuf, int statsbuf_max) { int rc; int ev_size; struct iscsi_uevent ev; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; struct nlmsghdr *nlh; struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); memset(&ev, 0, sizeof(struct iscsi_uevent)); ev.type = ISCSI_UEVENT_GET_STATS; ev.transport_handle = transport_handle; ev.u.get_stats.sid = sid; ev.u.get_stats.cid = cid; iov[1].iov_base = &ev; iov[1].iov_len = sizeof(ev); rc = __kipc_call(iov, 2); if (rc < 0) return rc; if ((rc = nl_read(ctrl_fd, nlm_ev, NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) { log_error("can not read nlm_ev, error %d", rc); return rc; } nlh = (struct nlmsghdr *)nlm_ev; ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); log_debug(6, "message real length is %d bytes", nlh->nlmsg_len); if (ev_size > statsbuf_max) { log_error("destanation buffer for statistics is " "not big enough to fit %d bytes", statsbuf_max); ev_size = statsbuf_max; } if ((rc = nlpayload_read(ctrl_fd, (void*)statsbuf, ev_size, 0)) < 0) { log_error("can not read from NL socket, error %d", rc); return rc; } return 0; }
static int kget_chap(uint64_t transport_handle, uint32_t host_no, uint16_t chap_tbl_idx, uint32_t num_entries, char *chap_buf, uint32_t *valid_chap_entries) { int rc = 0; int ev_size; struct iscsi_uevent ev; struct iovec iov[2]; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; struct nlmsghdr *nlh; memset(&ev, 0, sizeof(struct iscsi_uevent)); ev.type = ISCSI_UEVENT_GET_CHAP; ev.transport_handle = transport_handle; ev.u.get_chap.host_no = host_no; ev.u.get_chap.chap_tbl_idx = chap_tbl_idx; ev.u.get_chap.num_entries = num_entries; iov[1].iov_base = &ev; iov[1].iov_len = sizeof(ev); rc = __kipc_call(iov, 2); if (rc < 0) return rc; if ((rc = nl_read(ctrl_fd, nlm_ev, NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) { log_error("can not read nlm_ev, error %d", rc); return rc; } nlh = (struct nlmsghdr *)nlm_ev; ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); if ((rc = nlpayload_read(ctrl_fd, (void *)chap_buf, ev_size, 0)) < 0) { log_error("can not read from NL socket, error %d", rc); return rc; } *valid_chap_entries = ev.u.get_chap.num_entries; return rc; }
static int kget_host_stats(uint64_t transport_handle, uint32_t host_no, char *host_stats) { int rc = 0; int ev_size; struct iscsi_uevent ev; struct iovec iov[2]; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; struct nlmsghdr *nlh; memset(&ev, 0, sizeof(struct iscsi_uevent)); ev.type = ISCSI_UEVENT_GET_HOST_STATS; ev.transport_handle = transport_handle; ev.u.get_host_stats.host_no = host_no; iov[1].iov_base = &ev; iov[1].iov_len = sizeof(ev); rc = __kipc_call(iov, 2); if (rc < 0) return rc; if ((rc = nl_read(ctrl_fd, nlm_ev, NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) { log_error("can not read nlm_ev, error %d", rc); return rc; } nlh = (struct nlmsghdr *)nlm_ev; ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); if ((rc = nlpayload_read(ctrl_fd, (void *)host_stats, ev_size, 0)) < 0) { log_error("can not read from NL socket, error %d", rc); return rc; } return rc; }
/* query external help program for s. num < 0 [keyword] or chapter number */ static void external_help(const char *s, int num) { long nbli = term_height()-3, li = 0; char buf[256], *str; const char *opt = "", *ar = "", *cdir = ""; char *t, *help = GP_DATA->help; pariFILE *z; FILE *f; if (!has_ext_help()) pari_err(e_MISC,"no external help program"); t = filter_quotes(s); if (num < 0) opt = "-k"; else if (t[strlen(t)-1] != '@') ar = stack_sprintf("@%d",num); #ifdef _WIN32 if (*help=='@') { const char *basedir = win32_basedir(); help++; cdir = stack_sprintf("%c:& cd %s & ", *basedir, basedir); } #endif str=stack_sprintf("%s%s -fromgp %s %c%s%s%c",cdir,help,opt, SHELL_Q,t,ar,SHELL_Q); z = try_pipe(str,0); f = z->file; pari_free(t); while (fgets(buf, numberof(buf), f)) { if (!strncmp("ugly_kludge_done",buf,16)) break; pari_puts(buf); if (nl_read(buf) && ++li > nbli) { pari_hit_return(); li = 0; } } pari_fclose(z); }
static int ctldev_handle(void) { int rc, ev_size; struct iscsi_uevent *ev; iscsi_session_t *session = NULL; iscsi_conn_t *conn = NULL; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; struct nlmsghdr *nlh; struct iscsi_ev_context *ev_context; uint32_t sid = 0, cid = 0; log_debug(7, "in %s", __FUNCTION__); if ((rc = nl_read(ctrl_fd, nlm_ev, NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) { log_error("can not read nlm_ev, error %d", rc); return rc; } nlh = (struct nlmsghdr *)nlm_ev; ev = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev); log_debug(7, "%s got event type %u", __FUNCTION__, ev->type); /* drivers like qla4xxx can be inserted after iscsid is started */ switch (ev->type) { case ISCSI_KEVENT_CREATE_SESSION: /* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */ case ISCSI_UEVENT_CREATE_SESSION: drop_data(nlh); if (!ipc_ev_clbk) return 0; if (ipc_ev_clbk->create_session) ipc_ev_clbk->create_session(ev->r.c_session_ret.host_no, ev->r.c_session_ret.sid); return 0; case ISCSI_KEVENT_DESTROY_SESSION: drop_data(nlh); if (!ipc_ev_clbk) return 0; if (ipc_ev_clbk->destroy_session) ipc_ev_clbk->destroy_session(ev->r.d_session.host_no, ev->r.d_session.sid); return 0; case ISCSI_KEVENT_RECV_PDU: sid = ev->r.recv_req.sid; cid = ev->r.recv_req.cid; break; case ISCSI_KEVENT_CONN_ERROR: sid = ev->r.connerror.sid; cid = ev->r.connerror.cid; break; case ISCSI_KEVENT_CONN_LOGIN_STATE: sid = ev->r.conn_login.sid; cid = ev->r.conn_login.cid; break; case ISCSI_KEVENT_UNBIND_SESSION: sid = ev->r.unbind_session.sid; /* session wide event so cid is 0 */ cid = 0; break; case ISCSI_KEVENT_HOST_EVENT: switch (ev->r.host_event.code) { case ISCSI_EVENT_LINKUP: log_warning("Host%u: Link Up.", ev->r.host_event.host_no); break; case ISCSI_EVENT_LINKDOWN: log_warning("Host%u: Link Down.", ev->r.host_event.host_no); break; default: log_debug(7, "Host%u: Unknown host event: %u.", ev->r.host_event.host_no, ev->r.host_event.code); } drop_data(nlh); return 0; case ISCSI_KEVENT_PING_COMP: ping_event.host_no = ev->r.ping_comp.host_no; ping_event.pid = ev->r.ping_comp.pid; ping_event.status = ev->r.ping_comp.status; ping_event.active = 1; drop_data(nlh); return 0; default: if ((ev->type > ISCSI_UEVENT_MAX && ev->type < KEVENT_BASE) || (ev->type > ISCSI_KEVENT_MAX)) log_error("Unknown kernel event %d. You may want to " " upgrade your iscsi tools.", ev->type); else /* * If another app is using the interface we might * see their * stuff. Just drop it. */ log_debug(7, "Got unknown event %d. Dropping.", ev->type); drop_data(nlh); return 0; } /* verify connection */ session = session_find_by_sid(sid); if (!session) { /* * this can happen normally when other apps are using the * nl interface. */ log_debug(1, "Could not verify connection %d:%d. Dropping " "event.", sid, cid); drop_data(nlh); return -ENXIO; } conn = &session->conn[0]; ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size); if (!ev_context) { log_error("Can not allocate memory for receive context."); drop_data(nlh); return -ENOMEM; } log_debug(6, "message real length is %d bytes, recv_handle %p", nlh->nlmsg_len, ev_context->data); if ((rc = nlpayload_read(ctrl_fd, ev_context->data, ev_size, 0)) < 0) { ipc_ev_clbk->put_ev_context(ev_context); log_error("can not read from NL socket, error %d", rc); /* retry later */ return rc; } /* * we sched these events because the handlers could call back * into ctldev_handle */ switch (ev->type) { case ISCSI_KEVENT_RECV_PDU: rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0, EV_CONN_RECV_PDU); break; case ISCSI_KEVENT_CONN_ERROR: memcpy(ev_context->data, &ev->r.connerror.error, sizeof(ev->r.connerror.error)); rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0, EV_CONN_ERROR); break; case ISCSI_KEVENT_CONN_LOGIN_STATE: memcpy(ev_context->data, &ev->r.conn_login.state, sizeof(ev->r.conn_login.state)); rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0, EV_CONN_LOGIN); break; case ISCSI_KEVENT_UNBIND_SESSION: rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0, EV_CONN_STOP); break; default: ipc_ev_clbk->put_ev_context(ev_context); log_error("unknown kernel event %d", ev->type); return -EEXIST; } if (rc) ipc_ev_clbk->put_ev_context(ev_context); return rc; }
int ctldev_handle(int ctrl_fd) { int rc; struct iscsi_uevent *ev; struct qelem *item; uiscsi_session_t *session = NULL; uiscsi_conn_t *conn = NULL; unsigned long recv_handle; struct nlmsghdr nlh; int ev_size; if ((rc = nl_read(ctrl_fd, &nlh, MSG_PEEK)) < 0) { log_error("can not read nlmsghdr, error %d", rc); return rc; } ev_size = nlh.nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); recv_handle = (unsigned long)calloc(1, ev_size); if (!recv_handle) { log_error("can not allocate memory for receive handle"); return -ENOMEM; } log_debug(6, "message real length is %d bytes, recv_handle %p", nlh.nlmsg_len, (void*)recv_handle); if ((rc = nlpayload_read(ctrl_fd, (void*)recv_handle, ev_size, 0)) < 0) { log_error("can not read from NL socket, error %d", rc); return rc; } ev = (struct iscsi_uevent *)recv_handle; /* verify connection */ item = provider[0].sessions.q_forw; while (item != &provider[0].sessions) { int i; session = (uiscsi_session_t *)item; for (i=0; i<ISCSI_CNX_MAX; i++) { if (&session->cnx[i] == (uiscsi_conn_t*) iscsi_ptr(ev->r.recv_req.cnx_handle) || &session->cnx[i] == (uiscsi_conn_t*) iscsi_ptr(ev->r.cnxerror.cnx_handle)) { conn = &session->cnx[i]; break; } } item = item->q_forw; } if (ev->type == ISCSI_KEVENT_RECV_PDU) { if (conn == NULL) { log_error("could not verify connection 0x%p for " "event RECV_PDU", conn); return -ENXIO; } /* produce an event, so session manager will handle */ queue_produce(session->queue, EV_CNX_RECV_PDU, conn, sizeof(unsigned long), &recv_handle); actor_schedule(&session->mainloop); } else if (ev->type == ISCSI_KEVENT_CNX_ERROR) { if (conn == NULL) { log_error("could not verify connection 0x%p for " "event CNX_ERR", conn); return -ENXIO; } /* produce an event, so session manager will handle */ queue_produce(session->queue, EV_CNX_ERROR, conn, sizeof(unsigned long), (void*)&ev->r.cnxerror.error); actor_schedule(&session->mainloop); } else { log_error("unknown kernel event %d", ev->type); return -EEXIST; } return 0; }