diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 417b868d8735..dfc726fa34e3 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -24,6 +24,8 @@ #define ISCSI_TRANSPORT_VERSION "2.0-870" +#define ISCSI_SEND_MAX_ALLOWED 10 + #define CREATE_TRACE_POINTS #include <trace/events/iscsi.h> @@ -2091,7 +2093,12 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) "could not register session's dev\n"); goto release_ida; } - transport_register_device(&session->dev); + err = transport_register_device(&session->dev); + if (err) { + iscsi_cls_session_printk(KERN_ERR, session, + "could not register transport's dev\n"); + goto release_dev; + } spin_lock_irqsave(&sesslock, flags); list_add(&session->sess_list, &sesslist); @@ -2101,6 +2108,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n"); return 0; +release_dev: + device_del(&session->dev); release_ida: if (session->ida_used) ida_simple_remove(&iscsi_sess_ida, session->target_id); @@ -2261,7 +2270,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) "register connection's dev\n"); goto release_parent_ref; } - transport_register_device(&conn->dev); + err = transport_register_device(&conn->dev); + if (err) { + iscsi_cls_session_printk(KERN_ERR, session, "could not " + "register transport's dev\n"); + goto release_conn_ref; + } spin_lock_irqsave(&connlock, flags); list_add(&conn->conn_list, &connlist); @@ -2270,6 +2284,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n"); return conn; +release_conn_ref: + put_device(&conn->dev); release_parent_ref: put_device(&session->dev); free_conn: @@ -2945,6 +2961,24 @@ iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int iscsi_session_has_conns(int sid) +{ + struct iscsi_cls_conn *conn; + unsigned long flags; + int found = 0; + + spin_lock_irqsave(&connlock, flags); + list_for_each_entry(conn, &connlist, conn_list) { + if (iscsi_conn_get_sid(conn) == sid) { + found = 1; + break; + } + } + spin_unlock_irqrestore(&connlock, flags); + + return found; +} + static int iscsi_set_iface_params(struct iscsi_transport *transport, struct iscsi_uevent *ev, uint32_t len) @@ -3522,10 +3556,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) - transport->destroy_session(session); - else + if (!session) err = -EINVAL; + else if (iscsi_session_has_conns(ev->u.d_session.sid)) + err = -EBUSY; + else + transport->destroy_session(session); break; case ISCSI_UEVENT_UNBIND_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); @@ -3682,6 +3718,7 @@ iscsi_if_rx(struct sk_buff *skb) struct nlmsghdr *nlh; struct iscsi_uevent *ev; uint32_t group; + int retries = ISCSI_SEND_MAX_ALLOWED; nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || @@ -3712,6 +3749,10 @@ iscsi_if_rx(struct sk_buff *skb) break; err = iscsi_if_send_reply(portid, nlh->nlmsg_type, ev, sizeof(*ev)); + if (err == -EAGAIN && --retries < 0) { + printk(KERN_WARNING "Send reply failed, error %d\n", err); + break; + } } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); skb_pull(skb, rlen); } |