📄 scsi_transport_iscsi.c
字号:
rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); if (rc < 0) { printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); return rc; } return 0;}int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size){ struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; char *pdu; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + data_size); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return -EINVAL; skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " "control PDU: OOM\n"); return -ENOMEM; } nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); memset(ev, 0, sizeof(*ev)); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_RECV_PDU; ev->r.recv_req.cid = conn->cid; ev->r.recv_req.sid = iscsi_conn_get_sid(conn); pdu = (char*)ev + sizeof(*ev); memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); return iscsi_unicast_skb(skb, priv->daemon_pid);}EXPORT_SYMBOL_GPL(iscsi_recv_pdu);void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error){ struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev)); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return; skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " "conn error (%d)\n", error); return; } nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_CONN_ERROR; ev->r.connerror.error = error; ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); iscsi_broadcast_skb(skb, GFP_ATOMIC); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error);}EXPORT_SYMBOL_GPL(iscsi_conn_error);static intiscsi_if_send_reply(int pid, int seq, int type, int done, int multi, void *payload, int size){ struct sk_buff *skb; struct nlmsghdr *nlh; int len = NLMSG_SPACE(size); int flags = multi ? NLM_F_MULTI : 0; int t = done ? NLMSG_DONE : type; skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "Could not allocate skb to send reply.\n"); return -ENOMEM; } nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); nlh->nlmsg_flags = flags; memcpy(NLMSG_DATA(nlh), payload, size); return iscsi_unicast_skb(skb, pid);}static intiscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh){ struct iscsi_uevent *ev = NLMSG_DATA(nlh); struct iscsi_stats *stats; struct sk_buff *skbstat; struct iscsi_cls_conn *conn; struct nlmsghdr *nlhstat; struct iscsi_uevent *evstat; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_stats) + sizeof(struct iscsi_stats_custom) * ISCSI_STATS_CUSTOM_MAX); int err = 0; priv = iscsi_if_transport_lookup(transport); if (!priv) return -EINVAL; conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid); if (!conn) return -EEXIST; do { int actual_size; skbstat = alloc_skb(len, GFP_ATOMIC); if (!skbstat) { dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " "deliver stats: OOM\n"); return -ENOMEM; } nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0, (len - sizeof(*nlhstat)), 0); evstat = NLMSG_DATA(nlhstat); memset(evstat, 0, sizeof(*evstat)); evstat->transport_handle = iscsi_handle(conn->transport); evstat->type = nlh->nlmsg_type; evstat->u.get_stats.cid = ev->u.get_stats.cid; evstat->u.get_stats.sid = ev->u.get_stats.sid; stats = (struct iscsi_stats *) ((char*)evstat + sizeof(*evstat)); memset(stats, 0, sizeof(*stats)); transport->get_stats(conn, stats); actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) + sizeof(struct iscsi_stats) + sizeof(struct iscsi_stats_custom) * stats->custom_length); actual_size -= sizeof(*nlhstat); actual_size = NLMSG_LENGTH(actual_size); skb_trim(skbstat, NLMSG_ALIGN(actual_size)); nlhstat->nlmsg_len = actual_size; err = iscsi_unicast_skb(skbstat, priv->daemon_pid); } while (err < 0 && err != -ECONNREFUSED); return err;}/** * iscsi_if_destroy_session_done - send session destr. completion event * @conn: last connection for session * * This is called by HW iscsi LLDs to notify userpsace that its HW has * removed a session. **/int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn){ struct iscsi_internal *priv; struct iscsi_cls_session *session; struct Scsi_Host *shost; struct iscsi_uevent *ev; struct sk_buff *skb; struct nlmsghdr *nlh; unsigned long flags; int rc, len = NLMSG_SPACE(sizeof(*ev)); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return -EINVAL; session = iscsi_dev_to_session(conn->dev.parent); shost = iscsi_session_to_shost(session); skb = alloc_skb(len, GFP_KERNEL); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event\n"); return -ENOMEM; } nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_DESTROY_SESSION; ev->r.d_session.host_no = shost->host_no; ev->r.d_session.sid = session->sid; /* * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session destruction event. Check iscsi daemon\n"); spin_lock_irqsave(&sesslock, flags); list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); spin_lock_irqsave(&connlock, flags); conn->active = 0; list_del(&conn->conn_list); spin_unlock_irqrestore(&connlock, flags); return rc;}EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);/** * iscsi_if_create_session_done - send session creation completion event * @conn: leading connection for session * * This is called by HW iscsi LLDs to notify userpsace that its HW has * created a session or a existing session is back in the logged in state. **/int iscsi_if_create_session_done(struct iscsi_cls_conn *conn){ struct iscsi_internal *priv; struct iscsi_cls_session *session; struct Scsi_Host *shost; struct iscsi_uevent *ev; struct sk_buff *skb; struct nlmsghdr *nlh; unsigned long flags; int rc, len = NLMSG_SPACE(sizeof(*ev)); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return -EINVAL; session = iscsi_dev_to_session(conn->dev.parent); shost = iscsi_session_to_shost(session); skb = alloc_skb(len, GFP_KERNEL); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event\n"); return -ENOMEM; } nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_UEVENT_CREATE_SESSION; ev->r.c_session_ret.host_no = shost->host_no; ev->r.c_session_ret.sid = session->sid; /* * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event. Check iscsi daemon\n"); spin_lock_irqsave(&sesslock, flags); list_add(&session->sess_list, &sesslist); spin_unlock_irqrestore(&sesslock, flags); spin_lock_irqsave(&connlock, flags); list_add(&conn->conn_list, &connlist); conn->active = 1; spin_unlock_irqrestore(&connlock, flags); return rc;}EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);static intiscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev){ struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; unsigned long flags; uint32_t hostno; session = transport->create_session(transport, &priv->t, ev->u.c_session.cmds_max, ev->u.c_session.queue_depth, ev->u.c_session.initial_cmdsn, &hostno); if (!session) return -ENOMEM; spin_lock_irqsave(&sesslock, flags); list_add(&session->sess_list, &sesslist); spin_unlock_irqrestore(&sesslock, flags); ev->r.c_session_ret.host_no = hostno; ev->r.c_session_ret.sid = session->sid; return 0;}static intiscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){ struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; unsigned long flags; session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { printk(KERN_ERR "iscsi: invalid session %d\n", ev->u.c_conn.sid); return -EINVAL; } conn = transport->create_conn(session, ev->u.c_conn.cid); if (!conn) { printk(KERN_ERR "iscsi: couldn't create a new " "connection for session %d\n", session->sid); return -ENOMEM; } ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; spin_lock_irqsave(&connlock, flags); list_add(&conn->conn_list, &connlist); conn->active = 1; spin_unlock_irqrestore(&connlock, flags); return 0;}static intiscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){ unsigned long flags; struct iscsi_cls_conn *conn; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) return -EINVAL; spin_lock_irqsave(&connlock, flags); conn->active = 0; list_del(&conn->conn_list); spin_unlock_irqrestore(&connlock, flags); if (transport->destroy_conn) transport->destroy_conn(conn); return 0;}static intiscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev){ char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; int err = 0, value = 0; session = iscsi_session_lookup(ev->u.set_param.sid); conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); if (!conn || !session) return -EINVAL; switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: sscanf(data, "%d", &value); if (value != 0) session->recovery_tmo = value; break; default: err = transport->set_param(conn, ev->u.set_param.param, data, ev->u.set_param.len); } return err;}static intiscsi_if_transport_ep(struct iscsi_transport *transport, struct iscsi_uevent *ev, int msg_type){ struct sockaddr *dst_addr; int rc = 0; switch (msg_type) { case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: if (!transport->ep_connect) return -EINVAL; dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); rc = transport->ep_connect(dst_addr, ev->u.ep_connect.non_blocking, &ev->r.ep_connect_ret.handle); break; case ISCSI_UEVENT_TRANSPORT_EP_POLL: if (!transport->ep_poll) return -EINVAL; ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, ev->u.ep_poll.timeout_ms); break; case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: if (!transport->ep_disconnect) return -EINVAL; transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); break; } return rc;}static intiscsi_tgt_dscvr(struct iscsi_transport *transport, struct iscsi_uevent *ev){ struct Scsi_Host *shost; struct sockaddr *dst_addr; int err; if (!transport->tgt_dscvr) return -EINVAL; shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no); if (IS_ERR(shost)) { printk(KERN_ERR "target discovery could not find host no %u\n", ev->u.tgt_dscvr.host_no); return -ENODEV; } dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type, ev->u.tgt_dscvr.enable, dst_addr); scsi_host_put(shost); return err;}static intiscsi_set_host_param(struct iscsi_transport *transport, struct iscsi_uevent *ev){ char *data = (char*)ev + sizeof(*ev); struct Scsi_Host *shost; int err; if (!transport->set_host_param) return -ENOSYS; shost = scsi_host_lookup(ev->u.set_host_param.host_no); if (IS_ERR(shost)) { printk(KERN_ERR "set_host_param could not find host no %u\n", ev->u.set_host_param.host_no); return -ENODEV; } err = transport->set_host_param(shost, ev->u.set_host_param.param, data, ev->u.set_host_param.len); scsi_host_put(shost); return err;}static intiscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh){ int err = 0; struct iscsi_uevent *ev = NLMSG_DATA(nlh); struct iscsi_transport *transport = NULL; struct iscsi_internal *priv; struct iscsi_cls_session *session; struct iscsi_cls_conn *conn; unsigned long flags; priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) return -EINVAL; transport = priv->iscsi_transport; if (!try_module_get(transport->owner)) return -EINVAL; priv->daemon_pid = NETLINK_CREDS(skb)->pid; switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ev); break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); if (session) { spin_lock_irqsave(&sesslock, flags); list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); transport->destroy_session(session); } else err = -EINVAL; break; case ISCSI_UEVENT_CREATE_CONN: err = iscsi_if_create_conn(transport, ev); break; case ISCSI_UEVENT_DESTROY_CONN: err = iscsi_if_destroy_conn(transport, ev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -