[SCSI] iscsi class, qla4xxx: fix sess/conn refcounting when find fns are used
[cascardo/linux.git] / drivers / scsi / scsi_transport_iscsi.c
index ce06e87..133926b 100644 (file)
@@ -1019,8 +1019,7 @@ exit_match_index:
 /**
  * iscsi_get_flashnode_by_index -finds flashnode session entry by index
  * @shost: pointer to host data
- * @data: pointer to data containing value to use for comparison
- * @fn: function pointer that does actual comparison
+ * @idx: index to match
  *
  * Finds the flashnode session object for the passed index
  *
@@ -1029,13 +1028,13 @@ exit_match_index:
  *  %NULL on failure
  */
 static struct iscsi_bus_flash_session *
-iscsi_get_flashnode_by_index(struct Scsi_Host *shost, void *data,
-                            int (*fn)(struct device *dev, void *data))
+iscsi_get_flashnode_by_index(struct Scsi_Host *shost, uint32_t idx)
 {
        struct iscsi_bus_flash_session *fnode_sess = NULL;
        struct device *dev;
 
-       dev = device_find_child(&shost->shost_gendev, data, fn);
+       dev = device_find_child(&shost->shost_gendev, &idx,
+                               flashnode_match_index);
        if (dev)
                fnode_sess = iscsi_dev_to_flash_session(dev);
 
@@ -1059,18 +1058,13 @@ struct device *
 iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
                          int (*fn)(struct device *dev, void *data))
 {
-       struct device *dev;
-
-       dev = device_find_child(&shost->shost_gendev, data, fn);
-       return dev;
+       return device_find_child(&shost->shost_gendev, data, fn);
 }
 EXPORT_SYMBOL_GPL(iscsi_find_flashnode_sess);
 
 /**
  * iscsi_find_flashnode_conn - finds flashnode connection entry
  * @fnode_sess: pointer to parent flashnode session entry
- * @data: pointer to data containing value to use for comparison
- * @fn: function pointer that does actual comparison
  *
  * Finds the flashnode connection object comparing the data passed using logic
  * defined in passed function pointer
@@ -1080,14 +1074,10 @@ EXPORT_SYMBOL_GPL(iscsi_find_flashnode_sess);
  *  %NULL on failure
  */
 struct device *
-iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess,
-                         void *data,
-                         int (*fn)(struct device *dev, void *data))
+iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess)
 {
-       struct device *dev;
-
-       dev = device_find_child(&fnode_sess->dev, data, fn);
-       return dev;
+       return device_find_child(&fnode_sess->dev, NULL,
+                                iscsi_is_flashnode_conn_dev);
 }
 EXPORT_SYMBOL_GPL(iscsi_find_flashnode_conn);
 
@@ -2028,8 +2018,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_uevent *ev;
        char *pdu;
        struct iscsi_internal *priv;
-       int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
-                             data_size);
+       int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
+                                  data_size);
 
        priv = iscsi_if_transport_lookup(conn->transport);
        if (!priv)
@@ -2044,7 +2034,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        memset(ev, 0, sizeof(*ev));
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_RECV_PDU;
@@ -2065,7 +2055,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        struct iscsi_uevent *ev;
-       int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+       int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
        skb = alloc_skb(len, GFP_ATOMIC);
        if (!skb) {
@@ -2074,7 +2064,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        memset(ev, 0, sizeof(*ev));
        ev->type = type;
        ev->transport_handle = iscsi_handle(transport);
@@ -2099,7 +2089,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
        struct sk_buff  *skb;
        struct iscsi_uevent *ev;
        struct iscsi_internal *priv;
-       int len = NLMSG_SPACE(sizeof(*ev));
+       int len = nlmsg_total_size(sizeof(*ev));
 
        priv = iscsi_if_transport_lookup(conn->transport);
        if (!priv)
@@ -2113,7 +2103,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_CONN_ERROR;
        ev->r.connerror.error = error;
@@ -2134,7 +2124,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
        struct sk_buff  *skb;
        struct iscsi_uevent *ev;
        struct iscsi_internal *priv;
-       int len = NLMSG_SPACE(sizeof(*ev));
+       int len = nlmsg_total_size(sizeof(*ev));
 
        priv = iscsi_if_transport_lookup(conn->transport);
        if (!priv)
@@ -2148,7 +2138,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_CONN_LOGIN_STATE;
        ev->r.conn_login.state = state;
@@ -2168,7 +2158,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        struct iscsi_uevent *ev;
-       int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+       int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
        skb = alloc_skb(len, GFP_NOIO);
        if (!skb) {
@@ -2178,7 +2168,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        ev->transport_handle = iscsi_handle(transport);
        ev->type = ISCSI_KEVENT_HOST_EVENT;
        ev->r.host_event.host_no = host_no;
@@ -2199,7 +2189,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        struct iscsi_uevent *ev;
-       int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+       int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
        skb = alloc_skb(len, GFP_NOIO);
        if (!skb) {
@@ -2208,7 +2198,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        ev->transport_handle = iscsi_handle(transport);
        ev->type = ISCSI_KEVENT_PING_COMP;
        ev->r.ping_comp.host_no = host_no;
@@ -2227,7 +2217,7 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
 {
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
-       int len = NLMSG_SPACE(size);
+       int len = nlmsg_total_size(size);
        int flags = multi ? NLM_F_MULTI : 0;
        int t = done ? NLMSG_DONE : type;
 
@@ -2239,24 +2229,24 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
 
        nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
        nlh->nlmsg_flags = flags;
-       memcpy(NLMSG_DATA(nlh), payload, size);
+       memcpy(nlmsg_data(nlh), payload, size);
        return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
 }
 
 static int
 iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 {
-       struct iscsi_uevent *ev = NLMSG_DATA(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 len = nlmsg_total_size(sizeof(*ev) +
+                                  sizeof(struct iscsi_stats) +
+                                  sizeof(struct iscsi_stats_custom) *
+                                  ISCSI_STATS_CUSTOM_MAX);
        int err = 0;
 
        priv = iscsi_if_transport_lookup(transport);
@@ -2279,7 +2269,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 
                nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
                                      (len - sizeof(*nlhstat)), 0);
-               evstat = NLMSG_DATA(nlhstat);
+               evstat = nlmsg_data(nlhstat);
                memset(evstat, 0, sizeof(*evstat));
                evstat->transport_handle = iscsi_handle(conn->transport);
                evstat->type = nlh->nlmsg_type;
@@ -2292,12 +2282,12 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                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 = nlmsg_total_size(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);
+               actual_size = nlmsg_msg_size(actual_size);
                skb_trim(skbstat, NLMSG_ALIGN(actual_size));
                nlhstat->nlmsg_len = actual_size;
 
@@ -2321,7 +2311,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
        struct iscsi_uevent *ev;
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
-       int rc, len = NLMSG_SPACE(sizeof(*ev));
+       int rc, len = nlmsg_total_size(sizeof(*ev));
 
        priv = iscsi_if_transport_lookup(session->transport);
        if (!priv)
@@ -2337,7 +2327,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
        }
 
        nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
+       ev = nlmsg_data(nlh);
        ev->transport_handle = iscsi_handle(session->transport);
 
        ev->type = event;
@@ -2689,7 +2679,7 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 static int
 iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 {
-       struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+       struct iscsi_uevent *ev = nlmsg_data(nlh);
        struct Scsi_Host *shost = NULL;
        struct iscsi_chap_rec *chap_rec;
        struct iscsi_internal *priv;
@@ -2708,7 +2698,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                return -EINVAL;
 
        chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
-       len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+       len = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
 
        shost = scsi_host_lookup(ev->u.get_chap.host_no);
        if (!shost) {
@@ -2729,7 +2719,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 
                nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
                                      (len - sizeof(*nlhchap)), 0);
-               evchap = NLMSG_DATA(nlhchap);
+               evchap = nlmsg_data(nlhchap);
                memset(evchap, 0, sizeof(*evchap));
                evchap->transport_handle = iscsi_handle(transport);
                evchap->type = nlh->nlmsg_type;
@@ -2742,7 +2732,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
                                    &evchap->u.get_chap.num_entries, buf);
 
-               actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+               actual_size = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
                skb_trim(skbchap, NLMSG_ALIGN(actual_size));
                nlhchap->nlmsg_len = actual_size;
 
@@ -2808,7 +2798,7 @@ static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
        struct iscsi_bus_flash_session *fnode_sess;
        struct iscsi_bus_flash_conn *fnode_conn;
        struct device *dev;
-       uint32_t *idx;
+       uint32_t idx;
        int err = 0;
 
        if (!transport->set_flashnode_param) {
@@ -2824,25 +2814,27 @@ static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
                goto put_host;
        }
 
-       idx = &ev->u.set_flashnode.flashnode_idx;
-       fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
-                                                 flashnode_match_index);
+       idx = ev->u.set_flashnode.flashnode_idx;
+       fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
        if (!fnode_sess) {
                pr_err("%s could not find flashnode %u for host no %u\n",
-                      __func__, *idx, ev->u.set_flashnode.host_no);
+                      __func__, idx, ev->u.set_flashnode.host_no);
                err = -ENODEV;
                goto put_host;
        }
 
-       dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
-                                       iscsi_is_flashnode_conn_dev);
+       dev = iscsi_find_flashnode_conn(fnode_sess);
        if (!dev) {
                err = -ENODEV;
-               goto put_host;
+               goto put_sess;
        }
 
        fnode_conn = iscsi_dev_to_flash_conn(dev);
        err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
+       put_device(dev);
+
+put_sess:
+       put_device(&fnode_sess->dev);
 
 put_host:
        scsi_host_put(shost);
@@ -2891,7 +2883,7 @@ static int iscsi_del_flashnode(struct iscsi_transport *transport,
 {
        struct Scsi_Host *shost;
        struct iscsi_bus_flash_session *fnode_sess;
-       uint32_t *idx;
+       uint32_t idx;
        int err = 0;
 
        if (!transport->del_flashnode) {
@@ -2907,17 +2899,17 @@ static int iscsi_del_flashnode(struct iscsi_transport *transport,
                goto put_host;
        }
 
-       idx = &ev->u.del_flashnode.flashnode_idx;
-       fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
-                                                 flashnode_match_index);
+       idx = ev->u.del_flashnode.flashnode_idx;
+       fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
        if (!fnode_sess) {
                pr_err("%s could not find flashnode %u for host no %u\n",
-                      __func__, *idx, ev->u.del_flashnode.host_no);
+                      __func__, idx, ev->u.del_flashnode.host_no);
                err = -ENODEV;
                goto put_host;
        }
 
        err = transport->del_flashnode(fnode_sess);
+       put_device(&fnode_sess->dev);
 
 put_host:
        scsi_host_put(shost);
@@ -2933,7 +2925,7 @@ static int iscsi_login_flashnode(struct iscsi_transport *transport,
        struct iscsi_bus_flash_session *fnode_sess;
        struct iscsi_bus_flash_conn *fnode_conn;
        struct device *dev;
-       uint32_t *idx;
+       uint32_t idx;
        int err = 0;
 
        if (!transport->login_flashnode) {
@@ -2949,25 +2941,27 @@ static int iscsi_login_flashnode(struct iscsi_transport *transport,
                goto put_host;
        }
 
-       idx = &ev->u.login_flashnode.flashnode_idx;
-       fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
-                                                 flashnode_match_index);
+       idx = ev->u.login_flashnode.flashnode_idx;
+       fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
        if (!fnode_sess) {
                pr_err("%s could not find flashnode %u for host no %u\n",
-                      __func__, *idx, ev->u.login_flashnode.host_no);
+                      __func__, idx, ev->u.login_flashnode.host_no);
                err = -ENODEV;
                goto put_host;
        }
 
-       dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
-                                       iscsi_is_flashnode_conn_dev);
+       dev = iscsi_find_flashnode_conn(fnode_sess);
        if (!dev) {
                err = -ENODEV;
-               goto put_host;
+               goto put_sess;
        }
 
        fnode_conn = iscsi_dev_to_flash_conn(dev);
        err = transport->login_flashnode(fnode_sess, fnode_conn);
+       put_device(dev);
+
+put_sess:
+       put_device(&fnode_sess->dev);
 
 put_host:
        scsi_host_put(shost);
@@ -2983,7 +2977,7 @@ static int iscsi_logout_flashnode(struct iscsi_transport *transport,
        struct iscsi_bus_flash_session *fnode_sess;
        struct iscsi_bus_flash_conn *fnode_conn;
        struct device *dev;
-       uint32_t *idx;
+       uint32_t idx;
        int err = 0;
 
        if (!transport->logout_flashnode) {
@@ -2999,26 +2993,28 @@ static int iscsi_logout_flashnode(struct iscsi_transport *transport,
                goto put_host;
        }
 
-       idx = &ev->u.logout_flashnode.flashnode_idx;
-       fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
-                                                 flashnode_match_index);
+       idx = ev->u.logout_flashnode.flashnode_idx;
+       fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
        if (!fnode_sess) {
                pr_err("%s could not find flashnode %u for host no %u\n",
-                      __func__, *idx, ev->u.logout_flashnode.host_no);
+                      __func__, idx, ev->u.logout_flashnode.host_no);
                err = -ENODEV;
                goto put_host;
        }
 
-       dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
-                                       iscsi_is_flashnode_conn_dev);
+       dev = iscsi_find_flashnode_conn(fnode_sess);
        if (!dev) {
                err = -ENODEV;
-               goto put_host;
+               goto put_sess;
        }
 
        fnode_conn = iscsi_dev_to_flash_conn(dev);
 
        err = transport->logout_flashnode(fnode_sess, fnode_conn);
+       put_device(dev);
+
+put_sess:
+       put_device(&fnode_sess->dev);
 
 put_host:
        scsi_host_put(shost);
@@ -3068,7 +3064,7 @@ static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
        int err = 0;
-       struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+       struct iscsi_uevent *ev = nlmsg_data(nlh);
        struct iscsi_transport *transport = NULL;
        struct iscsi_internal *priv;
        struct iscsi_cls_session *session;
@@ -3256,7 +3252,7 @@ static void
 iscsi_if_rx(struct sk_buff *skb)
 {
        mutex_lock(&rx_queue_mutex);
-       while (skb->len >= NLMSG_SPACE(0)) {
+       while (skb->len >= NLMSG_HDRLEN) {
                int err;
                uint32_t rlen;
                struct nlmsghdr *nlh;
@@ -3269,7 +3265,7 @@ iscsi_if_rx(struct sk_buff *skb)
                        break;
                }
 
-               ev = NLMSG_DATA(nlh);
+               ev = nlmsg_data(nlh);
                rlen = NLMSG_ALIGN(nlh->nlmsg_len);
                if (rlen > skb->len)
                        rlen = skb->len;
@@ -3985,8 +3981,10 @@ static __init int iscsi_transport_init(void)
        }
 
        iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
-       if (!iscsi_eh_timer_workq)
+       if (!iscsi_eh_timer_workq) {
+               err = -ENOMEM;
                goto release_nls;
+       }
 
        return 0;