The feature 'staging grant' changed the behaviour of
xenvif_zerocopy_callback() that queue->dealloc_prod may not increase during
the do-while loop because of 'staging grant'. As a result,
xenvif_skb_zerocopy_complete() would not wake up xenvif_dealloc_kthread
because (prod == queue->dealloc_prod).
This makes trouble when the xenvif_dealloc_kthread is requested to stop by
xenvif_disconnect(). When xenvif_dealloc_kthread is stopped while
inflight_packets is not 0, xenvif_dealloc_kthread would not exit until
inflight_packets becomes 0.
However, because of 'staging grant', xenvif_skb_zerocopy_complete() would
not wake up xenvif_dealloc_kthread() although inflight_packets is
decremented and already becomes 0. As a result, xenvif_dealloc_kthread will
never wakes up.
xenvif_skb_zerocopy_complete() should wake up xenvif_dealloc_kthread when
the latter is in the progress to stop.
Orabug:
29217927
Fixes: fdbb2e3659b3 ("xen-netback: use gref mappings for Tx requests")
Reported-by: Ajaykumar Hotchandani <ajaykumar.hotchandani@oracle.com>
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
Reviewed-by: Joe Jin <joe.jin@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
/* Wake the dealloc thread _after_ decrementing inflight_packets so
* that if kthread_stop() has already been called, the dealloc thread
* does not wait forever with nothing to wake it. But only wake up when
- * there are grants to unmap.
+ * there are grants to unmap, or when we disconnect/teardown the
+ * interface.
*/
- if (prod != queue->dealloc_prod)
+ if (prod != queue->dealloc_prod ||
+ (unlikely(!test_bit(VIF_STATUS_CONNECTED, &queue->vif->status) &&
+ !atomic_read(&queue->inflight_packets))))
wake_up(&queue->dealloc_wq);
}