]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/fcoe/fcoe.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/fs/xfs/xfs
[karo-tx-linux.git] / drivers / scsi / fcoe / fcoe.c
index ac481ad112adfb6fe82359e8e2934f96196f851d..704b8e034946f9522b1ccd13c665a560371c0d8b 100644 (file)
@@ -57,6 +57,9 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for "    \
 
 DEFINE_MUTEX(fcoe_config_mutex);
 
+/* fcoe_percpu_clean completion.  Waiter protected by fcoe_create_mutex */
+static DECLARE_COMPLETION(fcoe_flush_completion);
+
 /* fcoe host list */
 /* must only by accessed under the RTNL mutex */
 LIST_HEAD(fcoe_hostlist);
@@ -827,7 +830,7 @@ static void fcoe_percpu_thread_create(unsigned int cpu)
        thread = kthread_create(fcoe_percpu_receive_thread,
                                (void *)p, "fcoethread/%d", cpu);
 
-       if (likely(!IS_ERR(p->thread))) {
+       if (likely(!IS_ERR(thread))) {
                kthread_bind(thread, cpu);
                wake_up_process(thread);
 
@@ -1299,6 +1302,15 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
        return 0;
 }
 
+/**
+ * fcoe_percpu_flush_done() - Indicate percpu queue flush completion.
+ * @skb: the skb being completed.
+ */
+static void fcoe_percpu_flush_done(struct sk_buff *skb)
+{
+       complete(&fcoe_flush_completion);
+}
+
 /**
  * fcoe_percpu_receive_thread() - recv thread per cpu
  * @arg: ptr to the fcoe per cpu struct
@@ -1338,7 +1350,8 @@ int fcoe_percpu_receive_thread(void *arg)
                fr = fcoe_dev_from_skb(skb);
                lp = fr->fr_dev;
                if (unlikely(lp == NULL)) {
-                       FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure");
+                       if (skb->destructor != fcoe_percpu_flush_done)
+                               FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb");
                        kfree_skb(skb);
                        continue;
                }
@@ -1799,6 +1812,13 @@ int fcoe_link_ok(struct fc_lport *lp)
 /**
  * fcoe_percpu_clean() - Clear the pending skbs for an lport
  * @lp: the fc_lport
+ *
+ * Must be called with fcoe_create_mutex held to single-thread completion.
+ *
+ * This flushes the pending skbs by adding a new skb to each queue and
+ * waiting until they are all freed.  This assures us that not only are
+ * there no packets that will be handled by the lport, but also that any
+ * threads already handling packet have returned.
  */
 void fcoe_percpu_clean(struct fc_lport *lp)
 {
@@ -1823,7 +1843,25 @@ void fcoe_percpu_clean(struct fc_lport *lp)
                                kfree_skb(skb);
                        }
                }
+
+               if (!pp->thread || !cpu_online(cpu)) {
+                       spin_unlock_bh(&pp->fcoe_rx_list.lock);
+                       continue;
+               }
+
+               skb = dev_alloc_skb(0);
+               if (!skb) {
+                       spin_unlock_bh(&pp->fcoe_rx_list.lock);
+                       continue;
+               }
+               skb->destructor = fcoe_percpu_flush_done;
+
+               __skb_queue_tail(&pp->fcoe_rx_list, skb);
+               if (pp->fcoe_rx_list.qlen == 1)
+                       wake_up_process(pp->thread);
                spin_unlock_bh(&pp->fcoe_rx_list.lock);
+
+               wait_for_completion(&fcoe_flush_completion);
        }
 }