* [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