summaryrefslogtreecommitdiff
path: root/usr/netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/netlink.c')
-rw-r--r--usr/netlink.c120
1 files changed, 87 insertions, 33 deletions
diff --git a/usr/netlink.c b/usr/netlink.c
index 06f3d42..e70602d 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -33,7 +33,6 @@
#include "types.h"
#include "iscsi_if.h"
-#include "iscsid.h"
#include "log.h"
#include "iscsi_ipc.h"
#include "initiator.h"
@@ -50,6 +49,7 @@ static void *nlm_sendbuf;
static void *nlm_recvbuf;
static void *pdu_sendbuf;
static void *setparam_buf;
+static struct iscsi_ipc_ev_clbk *ipc_ev_clbk;
static int ctldev_handle(void);
@@ -66,7 +66,8 @@ static int ctldev_handle(void);
static int
kread(char *data, int count)
{
- log_debug(7, "in %s", __FUNCTION__);
+ log_debug(7, "in %s %u %u %p %p", __FUNCTION__, recvlen, count,
+ data, recvbuf);
memcpy(data, recvbuf + recvlen, count);
recvlen += count;
@@ -716,18 +717,34 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
static int
krecv_pdu_begin(struct iscsi_conn *conn)
{
+ int rc;
+
log_debug(7, "in %s", __FUNCTION__);
if (recvbuf) {
log_error("recv's begin state machine bug?");
return -EIO;
}
+
+ if (!conn->recv_context) {
+ rc = ipc->ctldev_handle();
+ if (rc == -ENXIO)
+ /* event for some other conn */
+ return -EAGAIN;
+ else if (rc < 0)
+ /* fatal handling error or conn error */
+ return rc;
+ /*
+ * Session create/destroy event for another conn
+ */
+ if (!conn->recv_context)
+ return -EAGAIN;
+ }
+
recvbuf = conn->recv_context->data + sizeof(struct iscsi_uevent);
recvlen = 0;
- log_debug(3, "recv PDU began, pdu handle 0x%p",
- recvbuf);
-
+ log_debug(3, "recv PDU began, pdu handle %p", recvbuf);
return 0;
}
@@ -744,7 +761,7 @@ krecv_pdu_end(struct iscsi_conn *conn)
log_debug(3, "recv PDU finished for pdu handle 0x%p",
recvbuf);
- iscsi_conn_context_put(conn->recv_context);
+ ipc_ev_clbk->put_ev_context(conn->recv_context);
conn->recv_context = NULL;
recvbuf = NULL;
return 0;
@@ -891,10 +908,23 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid,
static void drop_data(struct nlmsghdr *nlh)
{
- int ev_size;
-
- ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
- nlpayload_read(ctrl_fd, setparam_buf, ev_size, 0);
+ int ev_size, read, curr_total;
+
+ curr_total = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ while (curr_total > 0) {
+ ev_size = curr_total;
+ if (ev_size > NLM_BUF_DEFAULT_MAX)
+ ev_size = NLM_BUF_DEFAULT_MAX;
+
+ /* sendbuf will not be used here, so dump data to it */
+ read = nlpayload_read(ctrl_fd, nlm_sendbuf, ev_size, 0);
+ if (read < 0) {
+ log_error("Could not drop %d bytes of data.\n",
+ read);
+ } else if (!read)
+ break;
+ curr_total -= read;
+ }
}
static int ctldev_handle(void)
@@ -905,7 +935,7 @@ static int ctldev_handle(void)
iscsi_conn_t *conn = NULL;
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
struct nlmsghdr *nlh;
- struct iscsi_conn_context *conn_context;
+ struct iscsi_ev_context *ev_context;
uint32_t sid = 0, cid = 0;
log_debug(7, "in %s", __FUNCTION__);
@@ -925,13 +955,15 @@ static int ctldev_handle(void)
/* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */
case ISCSI_UEVENT_CREATE_SESSION:
drop_data(nlh);
- iscsi_async_session_creation(ev->r.c_session_ret.host_no,
- ev->r.c_session_ret.sid);
+ 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);
- iscsi_async_session_destruction(ev->r.d_session.host_no,
- ev->r.d_session.sid);
+ 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;
@@ -947,16 +979,30 @@ static int ctldev_handle(void)
cid = 0;
break;
default:
- log_error("Unknown kernel event %d. You may want to upgrade "
- "your iscsi tools.", ev->type);
+ 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 unknwon event %d. Dropping.",
+ ev->type);
drop_data(nlh);
- return -EINVAL;
+ return 0;
}
/* verify connection */
session = session_find_by_sid(sid);
if (!session) {
- log_error("Could not verify connection %d:%d. Dropping "
+ /*
+ * this can happen normally when other apps are using the
+ * nl interface.
+ */
+ log_debug(1, "Could not verify connection %d:%d. Dropping "
"event.\n", sid, cid);
drop_data(nlh);
return -ENXIO;
@@ -964,19 +1010,20 @@ static int ctldev_handle(void)
conn = &session->conn[0];
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
- conn_context = iscsi_conn_context_get(conn, ev_size);
- if (!conn_context) {
+
+ ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size);
+ if (!ev_context) {
/* retry later */
log_error("Can not allocate memory for receive context.");
return -ENOMEM;
}
log_debug(6, "message real length is %d bytes, recv_handle %p",
- nlh->nlmsg_len, conn_context->data);
+ nlh->nlmsg_len, ev_context->data);
- if ((rc = nlpayload_read(ctrl_fd, conn_context->data,
+ if ((rc = nlpayload_read(ctrl_fd, ev_context->data,
ev_size, 0)) < 0) {
- iscsi_conn_context_put(conn_context);
+ ipc_ev_clbk->put_ev_context(ev_context);
log_error("can not read from NL socket, error %d", rc);
/* retry later */
return rc;
@@ -988,26 +1035,28 @@ static int ctldev_handle(void)
*/
switch (ev->type) {
case ISCSI_KEVENT_RECV_PDU:
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_RECV_PDU);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_RECV_PDU);
break;
case ISCSI_KEVENT_CONN_ERROR:
- memcpy(conn_context->data, &ev->r.connerror.error,
+ memcpy(ev_context->data, &ev->r.connerror.error,
sizeof(ev->r.connerror.error));
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_ERROR);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_ERROR);
break;
case ISCSI_KEVENT_UNBIND_SESSION:
- iscsi_sched_conn_context(conn_context, conn, 0,
- EV_CONN_STOP);
+ rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+ EV_CONN_STOP);
break;
default:
- iscsi_conn_context_put(conn_context);
+ ipc_ev_clbk->put_ev_context(ev_context);
log_error("unknown kernel event %d", ev->type);
return -EEXIST;
}
- return 0;
+ if (rc)
+ ipc_ev_clbk->put_ev_context(ev_context);
+ return rc;
}
static int
@@ -1116,3 +1165,8 @@ struct iscsi_ipc nl_ipc = {
.recv_pdu_end = krecv_pdu_end,
};
struct iscsi_ipc *ipc = &nl_ipc;
+
+void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ev_clbk)
+{
+ ipc_ev_clbk = ev_clbk;
+}