Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / fcoe / fcoe_ctlr.c
index 203415e02518a083120c2529ff95133881645690..34a1b1f333b4c16881ea3f6a610f29a73fc18a56 100644 (file)
@@ -160,74 +160,113 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 }
 EXPORT_SYMBOL(fcoe_ctlr_init);
 
+/**
+ * fcoe_sysfs_fcf_add() - Add a fcoe_fcf{,_device} to a fcoe_ctlr{,_device}
+ * @new: The newly discovered FCF
+ *
+ * Called with fip->ctlr_mutex held
+ */
 static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new)
 {
        struct fcoe_ctlr *fip = new->fip;
-       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
-       struct fcoe_fcf_device temp, *fcf_dev;
-       int rc = 0;
+       struct fcoe_ctlr_device *ctlr_dev;
+       struct fcoe_fcf_device *temp, *fcf_dev;
+       int rc = -ENOMEM;
 
        LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n",
                        new->fabric_name, new->fcf_mac);
 
-       mutex_lock(&ctlr_dev->lock);
-
-       temp.fabric_name = new->fabric_name;
-       temp.switch_name = new->switch_name;
-       temp.fc_map = new->fc_map;
-       temp.vfid = new->vfid;
-       memcpy(temp.mac, new->fcf_mac, ETH_ALEN);
-       temp.priority = new->pri;
-       temp.fka_period = new->fka_period;
-       temp.selected = 0; /* default to unselected */
-
-       fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp);
-       if (unlikely(!fcf_dev)) {
-               rc = -ENOMEM;
+       temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+       if (!temp)
                goto out;
-       }
+
+       temp->fabric_name = new->fabric_name;
+       temp->switch_name = new->switch_name;
+       temp->fc_map = new->fc_map;
+       temp->vfid = new->vfid;
+       memcpy(temp->mac, new->fcf_mac, ETH_ALEN);
+       temp->priority = new->pri;
+       temp->fka_period = new->fka_period;
+       temp->selected = 0; /* default to unselected */
 
        /*
-        * The fcoe_sysfs layer can return a CONNECTED fcf that
-        * has a priv (fcf was never deleted) or a CONNECTED fcf
-        * that doesn't have a priv (fcf was deleted). However,
-        * libfcoe will always delete FCFs before trying to add
-        * them. This is ensured because both recv_adv and
-        * age_fcfs are protected by the the fcoe_ctlr's mutex.
-        * This means that we should never get a FCF with a
-        * non-NULL priv pointer.
+        * If ctlr_dev doesn't exist then it means we're a libfcoe user
+        * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device.
+        * fnic would be an example of a driver with this behavior. In this
+        * case we want to add the fcoe_fcf to the fcoe_ctlr list, but we
+        * don't want to make sysfs changes.
         */
-       BUG_ON(fcf_dev->priv);
 
-       fcf_dev->priv = new;
-       new->fcf_dev = fcf_dev;
+       ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+       if (ctlr_dev) {
+               mutex_lock(&ctlr_dev->lock);
+               fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp);
+               if (unlikely(!fcf_dev)) {
+                       rc = -ENOMEM;
+                       mutex_unlock(&ctlr_dev->lock);
+                       goto out;
+               }
+
+               /*
+                * The fcoe_sysfs layer can return a CONNECTED fcf that
+                * has a priv (fcf was never deleted) or a CONNECTED fcf
+                * that doesn't have a priv (fcf was deleted). However,
+                * libfcoe will always delete FCFs before trying to add
+                * them. This is ensured because both recv_adv and
+                * age_fcfs are protected by the the fcoe_ctlr's mutex.
+                * This means that we should never get a FCF with a
+                * non-NULL priv pointer.
+                */
+               BUG_ON(fcf_dev->priv);
+
+               fcf_dev->priv = new;
+               new->fcf_dev = fcf_dev;
+               mutex_unlock(&ctlr_dev->lock);
+       }
 
        list_add(&new->list, &fip->fcfs);
        fip->fcf_count++;
+       rc = 0;
 
 out:
-       mutex_unlock(&ctlr_dev->lock);
+       kfree(temp);
        return rc;
 }
 
+/**
+ * fcoe_sysfs_fcf_del() - Remove a fcoe_fcf{,_device} to a fcoe_ctlr{,_device}
+ * @new: The FCF to be removed
+ *
+ * Called with fip->ctlr_mutex held
+ */
 static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new)
 {
        struct fcoe_ctlr *fip = new->fip;
-       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+       struct fcoe_ctlr_device *cdev;
        struct fcoe_fcf_device *fcf_dev;
 
        list_del(&new->list);
        fip->fcf_count--;
 
-       mutex_lock(&ctlr_dev->lock);
-
-       fcf_dev = fcoe_fcf_to_fcf_dev(new);
-       WARN_ON(!fcf_dev);
-       new->fcf_dev = NULL;
-       fcoe_fcf_device_delete(fcf_dev);
-       kfree(new);
-
-       mutex_unlock(&ctlr_dev->lock);
+       /*
+        * If ctlr_dev doesn't exist then it means we're a libfcoe user
+        * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device
+        * or a fcoe_fcf_device.
+        *
+        * fnic would be an example of a driver with this behavior. In this
+        * case we want to remove the fcoe_fcf from the fcoe_ctlr list (above),
+        * but we don't want to make sysfs changes.
+        */
+       cdev = fcoe_ctlr_to_ctlr_dev(fip);
+       if (cdev) {
+               mutex_lock(&cdev->lock);
+               fcf_dev = fcoe_fcf_to_fcf_dev(new);
+               WARN_ON(!fcf_dev);
+               new->fcf_dev = NULL;
+               fcoe_fcf_device_delete(fcf_dev);
+               kfree(new);
+               mutex_unlock(&cdev->lock);
+       }
 }
 
 /**
@@ -300,7 +339,7 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
        spin_unlock_bh(&fip->ctlr_lock);
        sel = fip->sel_fcf;
 
-       if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr))
+       if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr))
                goto unlock;
        if (!is_zero_ether_addr(fip->dest_addr)) {
                printk(KERN_NOTICE "libfcoe: host%d: "
@@ -1000,7 +1039,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
                if (fcf->switch_name == new.switch_name &&
                    fcf->fabric_name == new.fabric_name &&
                    fcf->fc_map == new.fc_map &&
-                   compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
+                   ether_addr_equal(fcf->fcf_mac, new.fcf_mac)) {
                        found = 1;
                        break;
                }
@@ -1340,7 +1379,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                        mp = (struct fip_mac_desc *)desc;
                        if (dlen < sizeof(*mp))
                                goto err;
-                       if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac))
+                       if (!ether_addr_equal(mp->fd_mac, fcf->fcf_mac))
                                goto err;
                        desc_mask &= ~BIT(FIP_DT_MAC);
                        break;
@@ -1418,8 +1457,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                         * 'port_id' is already validated, check MAC address and
                         * wwpn
                         */
-                       if (compare_ether_addr(fip->get_src_addr(vn_port),
-                                               vp->fd_mac) != 0 ||
+                       if (!ether_addr_equal(fip->get_src_addr(vn_port),
+                                             vp->fd_mac) ||
                                get_unaligned_be64(&vp->fd_wwpn) !=
                                                        vn_port->wwpn)
                                continue;
@@ -1453,6 +1492,9 @@ err:
  */
 void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return;
        skb_queue_tail(&fip->fip_recv_list, skb);
        schedule_work(&fip->recv_work);
 }
@@ -1479,12 +1521,12 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
                goto drop;
        eh = eth_hdr(skb);
        if (fip->mode == FIP_MODE_VN2VN) {
-               if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
-                   compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) &&
-                   compare_ether_addr(eh->h_dest, fcoe_all_p2p))
+               if (!ether_addr_equal(eh->h_dest, fip->ctl_src_addr) &&
+                   !ether_addr_equal(eh->h_dest, fcoe_all_vn2vn) &&
+                   !ether_addr_equal(eh->h_dest, fcoe_all_p2p))
                        goto drop;
-       } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
-                  compare_ether_addr(eh->h_dest, fcoe_all_enode))
+       } else if (!ether_addr_equal(eh->h_dest, fip->ctl_src_addr) &&
+                  !ether_addr_equal(eh->h_dest, fcoe_all_enode))
                goto drop;
        fiph = (struct fip_header *)skb->data;
        op = ntohs(fiph->fip_op);
@@ -1856,7 +1898,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
                 * address_mode flag to use FC_OUI-based Ethernet DA.
                 * Otherwise we use the FCoE gateway addr
                 */
-               if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
+               if (ether_addr_equal(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
                        fcoe_ctlr_map_dest(fip);
                } else {
                        memcpy(fip->dest_addr, sa, ETH_ALEN);
@@ -2825,8 +2867,8 @@ unlock:
  * disabled, so that should ensure that this routine is only called
  * when nothing is happening.
  */
-void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
-                       enum fip_state fip_mode)
+static void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
+                              enum fip_state fip_mode)
 {
        void *priv;