netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback
@ 2014-08-12 10:48 Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 1/3] xen-netback: move NAPI add/remove calls Wei Liu
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Wei Liu @ 2014-08-12 10:48 UTC (permalink / raw)
  To: xen-devel, netdev; +Cc: ian.campbell, zoltan.kiss, david.vrabel, Wei Liu

The zero-copy netback has far more interactions with core network driver than
the old copying backend. One significant thing is that netback now relies on
a callback from core driver to correctly release resources.

However correct synchronisation between core driver and netback is missing.
Currently netback relies on a loop to wait for core driver to release
resources. This is proven not enough and erroneous recently, partly due to code
structure, partly due to missing synchronisation. Short-live domains like
OpenMirage unikernels can easily trigger race in backend, rendering backend
unresponsive.

This patch series aims to slove this issue by introducing proper
synchronisation between core driver and netback.

Wei.

Chagges in v4:
* avoid using wait queue
* remove dedicated loop for netif_napi_del
* remove unnecessary check on callback

Change in v3: improve commit message in patch 1

Change in v2: fix Zoltan's email address in commit message


Wei Liu (3):
  xen-netback: move NAPI add/remove calls
  xen-netback: don't stop dealloc kthread too early
  xen-netback: remove loop waiting function

 drivers/net/xen-netback/common.h    |    5 ++++
 drivers/net/xen-netback/interface.c |   56 ++++++++++++++---------------------
 drivers/net/xen-netback/netback.c   |   26 +++++++++++-----
 3 files changed, 47 insertions(+), 40 deletions(-)

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net v4 1/3] xen-netback: move NAPI add/remove calls
  2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
@ 2014-08-12 10:48 ` Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 2/3] xen-netback: don't stop dealloc kthread too early Wei Liu
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Wei Liu @ 2014-08-12 10:48 UTC (permalink / raw)
  To: xen-devel, netdev; +Cc: ian.campbell, zoltan.kiss, david.vrabel, Wei Liu

Originally netif_napi_add was in xenvif_init_queue and netif_napi_del
was in xenvif_deinit_queue, while kthreads were handled in
xenvif_connect and xenvif_disconnect. Move netif_napi_add and
netif_napi_del to xenvif_connect and xenvif_disconnect so that they
reside together with kthread operations.

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: Zoltan Kiss <zoltan.kiss@citrix.com>
---
 drivers/net/xen-netback/interface.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index bfd10cb..5f3d6c0 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -524,9 +524,6 @@ int xenvif_init_queue(struct xenvif_queue *queue)
 
 	init_timer(&queue->rx_stalled);
 
-	netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll,
-			XENVIF_NAPI_WEIGHT);
-
 	return 0;
 }
 
@@ -614,6 +611,9 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
 	wake_up_process(queue->task);
 	wake_up_process(queue->dealloc_task);
 
+	netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll,
+			XENVIF_NAPI_WEIGHT);
+
 	return 0;
 
 err_rx_unbind:
@@ -672,6 +672,8 @@ void xenvif_disconnect(struct xenvif *vif)
 	for (queue_index = 0; queue_index < num_queues; ++queue_index) {
 		queue = &vif->queues[queue_index];
 
+		netif_napi_del(&queue->napi);
+
 		if (queue->task) {
 			del_timer_sync(&queue->rx_stalled);
 			kthread_stop(queue->task);
@@ -704,7 +706,6 @@ void xenvif_disconnect(struct xenvif *vif)
 void xenvif_deinit_queue(struct xenvif_queue *queue)
 {
 	free_xenballooned_pages(MAX_PENDING_REQS, queue->mmap_pages);
-	netif_napi_del(&queue->napi);
 }
 
 void xenvif_free(struct xenvif *vif)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net v4 2/3] xen-netback: don't stop dealloc kthread too early
  2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 1/3] xen-netback: move NAPI add/remove calls Wei Liu
@ 2014-08-12 10:48 ` Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 3/3] xen-netback: remove loop waiting function Wei Liu
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Wei Liu @ 2014-08-12 10:48 UTC (permalink / raw)
  To: xen-devel, netdev; +Cc: ian.campbell, zoltan.kiss, david.vrabel, Wei Liu

Reference count the number of packets in host stack, so that we don't
stop the deallocation thread too early. If not, we can end up with
xenvif_free permanently waiting for deallocation thread to unmap grefs.

Reported-by: Thomas Leonard <talex5@gmail.com>
Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: Zoltan Kiss <zoltan.kiss@citrix.com>
---
 drivers/net/xen-netback/common.h    |    5 +++++
 drivers/net/xen-netback/interface.c |   18 ++++++++++++++++++
 drivers/net/xen-netback/netback.c   |   26 +++++++++++++++++++-------
 3 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index ef3026f..d4eb8d2 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -165,6 +165,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */
 	u16 dealloc_ring[MAX_PENDING_REQS];
 	struct task_struct *dealloc_task;
 	wait_queue_head_t dealloc_wq;
+	atomic_t inflight_packets;
 
 	/* Use kthread for guest RX */
 	struct task_struct *task;
@@ -329,4 +330,8 @@ extern unsigned int xenvif_max_queues;
 extern struct dentry *xen_netback_dbg_root;
 #endif
 
+void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
+				 struct sk_buff *skb);
+void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue);
+
 #endif /* __XEN_NETBACK__COMMON_H__ */
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 5f3d6c0..0aaca90 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -43,6 +43,23 @@
 #define XENVIF_QUEUE_LENGTH 32
 #define XENVIF_NAPI_WEIGHT  64
 
+/* This function is used to set SKBTX_DEV_ZEROCOPY as well as
+ * increasing the inflight counter. We need to increase the inflight
+ * counter because core driver calls into xenvif_zerocopy_callback
+ * which calls xenvif_skb_zerocopy_complete.
+ */
+void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
+				 struct sk_buff *skb)
+{
+	skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+	atomic_inc(&queue->inflight_packets);
+}
+
+void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue)
+{
+	atomic_dec(&queue->inflight_packets);
+}
+
 static inline void xenvif_stop_queue(struct xenvif_queue *queue)
 {
 	struct net_device *dev = queue->vif->dev;
@@ -557,6 +574,7 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
 
 	init_waitqueue_head(&queue->wq);
 	init_waitqueue_head(&queue->dealloc_wq);
+	atomic_set(&queue->inflight_packets, 0);
 
 	if (tx_evtchn == rx_evtchn) {
 		/* feature-split-event-channels == 0 */
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 4734472..08f6599 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1525,10 +1525,12 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
 	/* remove traces of mapped pages and frag_list */
 	skb_frag_list_init(skb);
 	uarg = skb_shinfo(skb)->destructor_arg;
+	/* increase inflight counter to offset decrement in callback */
+	atomic_inc(&queue->inflight_packets);
 	uarg->callback(uarg, true);
 	skb_shinfo(skb)->destructor_arg = NULL;
 
-	skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+	xenvif_skb_zerocopy_prepare(queue, nskb);
 	kfree_skb(nskb);
 
 	return 0;
@@ -1589,7 +1591,7 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
 				if (net_ratelimit())
 					netdev_err(queue->vif->dev,
 						   "Not enough memory to consolidate frag_list!\n");
-				skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+				xenvif_skb_zerocopy_prepare(queue, skb);
 				kfree_skb(skb);
 				continue;
 			}
@@ -1609,7 +1611,7 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
 				   "Can't setup checksum in net_tx_action\n");
 			/* We have to set this flag to trigger the callback */
 			if (skb_shinfo(skb)->destructor_arg)
-				skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+				xenvif_skb_zerocopy_prepare(queue, skb);
 			kfree_skb(skb);
 			continue;
 		}
@@ -1641,7 +1643,7 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
 		 * skb. E.g. the __pskb_pull_tail earlier can do such thing.
 		 */
 		if (skb_shinfo(skb)->destructor_arg) {
-			skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+			xenvif_skb_zerocopy_prepare(queue, skb);
 			queue->stats.tx_zerocopy_sent++;
 		}
 
@@ -1681,6 +1683,7 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
 		queue->stats.tx_zerocopy_success++;
 	else
 		queue->stats.tx_zerocopy_fail++;
+	xenvif_skb_zerocopy_complete(queue);
 }
 
 static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue)
@@ -2058,15 +2061,24 @@ int xenvif_kthread_guest_rx(void *data)
 	return 0;
 }
 
+static bool xenvif_dealloc_kthread_should_stop(struct xenvif_queue *queue)
+{
+	/* Dealloc thread must remain running until all inflight
+	 * packets complete.
+	 */
+	return kthread_should_stop() &&
+		!atomic_read(&queue->inflight_packets);
+}
+
 int xenvif_dealloc_kthread(void *data)
 {
 	struct xenvif_queue *queue = data;
 
-	while (!kthread_should_stop()) {
+	for (;;) {
 		wait_event_interruptible(queue->dealloc_wq,
 					 tx_dealloc_work_todo(queue) ||
-					 kthread_should_stop());
-		if (kthread_should_stop())
+					 xenvif_dealloc_kthread_should_stop(queue));
+		if (xenvif_dealloc_kthread_should_stop(queue))
 			break;
 
 		xenvif_tx_dealloc_action(queue);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net v4 3/3] xen-netback: remove loop waiting function
  2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 1/3] xen-netback: move NAPI add/remove calls Wei Liu
  2014-08-12 10:48 ` [PATCH net v4 2/3] xen-netback: don't stop dealloc kthread too early Wei Liu
@ 2014-08-12 10:48 ` Wei Liu
  2014-08-12 16:53 ` [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Zoltan Kiss
  2014-08-12 21:42 ` David Miller
  4 siblings, 0 replies; 6+ messages in thread
From: Wei Liu @ 2014-08-12 10:48 UTC (permalink / raw)
  To: xen-devel, netdev; +Cc: ian.campbell, zoltan.kiss, david.vrabel, Wei Liu

The original implementation relies on a loop to check if all inflight
packets are freed. Now we have proper reference counting, there's no
need to use loop anymore.

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: Zoltan Kiss <zoltan.kiss@citrix.com>
---
 drivers/net/xen-netback/interface.c |   29 -----------------------------
 1 file changed, 29 deletions(-)

diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 0aaca90..e29e15d 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -660,25 +660,6 @@ void xenvif_carrier_off(struct xenvif *vif)
 	rtnl_unlock();
 }
 
-static void xenvif_wait_unmap_timeout(struct xenvif_queue *queue,
-				      unsigned int worst_case_skb_lifetime)
-{
-	int i, unmap_timeout = 0;
-
-	for (i = 0; i < MAX_PENDING_REQS; ++i) {
-		if (queue->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) {
-			unmap_timeout++;
-			schedule_timeout(msecs_to_jiffies(1000));
-			if (unmap_timeout > worst_case_skb_lifetime &&
-			    net_ratelimit())
-				netdev_err(queue->vif->dev,
-					   "Page still granted! Index: %x\n",
-					   i);
-			i = -1;
-		}
-	}
-}
-
 void xenvif_disconnect(struct xenvif *vif)
 {
 	struct xenvif_queue *queue = NULL;
@@ -731,21 +712,11 @@ void xenvif_free(struct xenvif *vif)
 	struct xenvif_queue *queue = NULL;
 	unsigned int num_queues = vif->num_queues;
 	unsigned int queue_index;
-	/* Here we want to avoid timeout messages if an skb can be legitimately
-	 * stuck somewhere else. Realistically this could be an another vif's
-	 * internal or QDisc queue. That another vif also has this
-	 * rx_drain_timeout_msecs timeout, so give it time to drain out.
-	 * Although if that other guest wakes up just before its timeout happens
-	 * and takes only one skb from QDisc, it can hold onto other skbs for a
-	 * longer period.
-	 */
-	unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000);
 
 	unregister_netdev(vif->dev);
 
 	for (queue_index = 0; queue_index < num_queues; ++queue_index) {
 		queue = &vif->queues[queue_index];
-		xenvif_wait_unmap_timeout(queue, worst_case_skb_lifetime);
 		xenvif_deinit_queue(queue);
 	}
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback
  2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
                   ` (2 preceding siblings ...)
  2014-08-12 10:48 ` [PATCH net v4 3/3] xen-netback: remove loop waiting function Wei Liu
@ 2014-08-12 16:53 ` Zoltan Kiss
  2014-08-12 21:42 ` David Miller
  4 siblings, 0 replies; 6+ messages in thread
From: Zoltan Kiss @ 2014-08-12 16:53 UTC (permalink / raw)
  To: Wei Liu, xen-devel, netdev; +Cc: ian.campbell, david.vrabel

On 12/08/14 11:48, Wei Liu wrote:
> The zero-copy netback has far more interactions with core network driver than
> the old copying backend. One significant thing is that netback now relies on
> a callback from core driver to correctly release resources.
>
> However correct synchronisation between core driver and netback is missing.
> Currently netback relies on a loop to wait for core driver to release
> resources. This is proven not enough and erroneous recently, partly due to code
> structure, partly due to missing synchronisation. Short-live domains like
> OpenMirage unikernels can easily trigger race in backend, rendering backend
> unresponsive.
>
> This patch series aims to slove this issue by introducing proper
> synchronisation between core driver and netback.
>
> Wei.
>
> Chagges in v4:
> * avoid using wait queue
> * remove dedicated loop for netif_napi_del
> * remove unnecessary check on callback
>
> Change in v3: improve commit message in patch 1
>
> Change in v2: fix Zoltan's email address in commit message
>
>
> Wei Liu (3):
>    xen-netback: move NAPI add/remove calls
>    xen-netback: don't stop dealloc kthread too early
>    xen-netback: remove loop waiting function
>
>   drivers/net/xen-netback/common.h    |    5 ++++
>   drivers/net/xen-netback/interface.c |   56 ++++++++++++++---------------------
>   drivers/net/xen-netback/netback.c   |   26 +++++++++++-----
>   3 files changed, 47 insertions(+), 40 deletions(-)
>

Looks good for me.

Acked-by: Zoltan Kiss <zoltan.kiss@citrix.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback
  2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
                   ` (3 preceding siblings ...)
  2014-08-12 16:53 ` [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Zoltan Kiss
@ 2014-08-12 21:42 ` David Miller
  4 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2014-08-12 21:42 UTC (permalink / raw)
  To: wei.liu2; +Cc: xen-devel, netdev, ian.campbell, zoltan.kiss, david.vrabel

From: Wei Liu <wei.liu2@citrix.com>
Date: Tue, 12 Aug 2014 11:48:05 +0100

> The zero-copy netback has far more interactions with core network driver than
> the old copying backend. One significant thing is that netback now relies on
> a callback from core driver to correctly release resources.
> 
> However correct synchronisation between core driver and netback is missing.
> Currently netback relies on a loop to wait for core driver to release
> resources. This is proven not enough and erroneous recently, partly due to code
> structure, partly due to missing synchronisation. Short-live domains like
> OpenMirage unikernels can easily trigger race in backend, rendering backend
> unresponsive.
> 
> This patch series aims to slove this issue by introducing proper
> synchronisation between core driver and netback.

Series applied.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-08-12 21:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-12 10:48 [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Wei Liu
2014-08-12 10:48 ` [PATCH net v4 1/3] xen-netback: move NAPI add/remove calls Wei Liu
2014-08-12 10:48 ` [PATCH net v4 2/3] xen-netback: don't stop dealloc kthread too early Wei Liu
2014-08-12 10:48 ` [PATCH net v4 3/3] xen-netback: remove loop waiting function Wei Liu
2014-08-12 16:53 ` [PATCH net v4 0/3] xen-netback: synchronisation between core driver and netback Zoltan Kiss
2014-08-12 21:42 ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).