From db8c8ab61a28d7e3eb86d247b342a853263262c3 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:22 +0100 Subject: xen-netfront: fix locking in connect error path If no queues could be created when connecting to the backend, one of the error paths would deadlock. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/xen-netfront.c') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 055222bae6e..1cc46d00d20 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2001,7 +2001,7 @@ abort_transaction_no_dev_fatal: info->queues = NULL; rtnl_lock(); netif_set_real_num_tx_queues(info->netdev, 0); - rtnl_lock(); + rtnl_unlock(); out: return err; } -- cgit v1.2.3-70-g09d2 From a5b5dc3ce4df4f05f4d81c7d3c56a7604b242093 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:23 +0100 Subject: xen-netfront: release per-queue Tx and Rx resource when disconnecting Since netfront may reconnect to a backend with a different number of queues, all per-queue Rx and Tx resources (skbs and grant references) should be freed when disconnecting. Without this fix, the Tx and Rx grant refs are not released and netfront will exhaust them after only a few reconnections. netfront will fail to connect when no free grant references are available. Since all Rx bufs are freed and reallocated instead of reused this will add some additional delay to the reconnection but this is expected to be small compared to the time taken by any backend hotplug scripts etc. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 68 +++++----------------------------------------- 1 file changed, 7 insertions(+), 61 deletions(-) (limited to 'drivers/net/xen-netfront.c') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 1cc46d00d20..0b133a3d431 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1196,22 +1196,6 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue) spin_unlock_bh(&queue->rx_lock); } -static void xennet_uninit(struct net_device *dev) -{ - struct netfront_info *np = netdev_priv(dev); - unsigned int num_queues = dev->real_num_tx_queues; - struct netfront_queue *queue; - unsigned int i; - - for (i = 0; i < num_queues; ++i) { - queue = &np->queues[i]; - xennet_release_tx_bufs(queue); - xennet_release_rx_bufs(queue); - gnttab_free_grant_references(queue->gref_tx_head); - gnttab_free_grant_references(queue->gref_rx_head); - } -} - static netdev_features_t xennet_fix_features(struct net_device *dev, netdev_features_t features) { @@ -1313,7 +1297,6 @@ static void xennet_poll_controller(struct net_device *dev) static const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, - .ndo_uninit = xennet_uninit, .ndo_stop = xennet_close, .ndo_start_xmit = xennet_start_xmit, .ndo_change_mtu = xennet_change_mtu, @@ -1455,6 +1438,11 @@ static void xennet_disconnect_backend(struct netfront_info *info) napi_synchronize(&queue->napi); + xennet_release_tx_bufs(queue); + xennet_release_rx_bufs(queue); + gnttab_free_grant_references(queue->gref_tx_head); + gnttab_free_grant_references(queue->gref_rx_head); + /* End access and free the pages */ xennet_end_access(queue->tx_ring_ref, queue->tx.sring); xennet_end_access(queue->rx_ring_ref, queue->rx.sring); @@ -2010,10 +1998,7 @@ static int xennet_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); unsigned int num_queues = 0; - int i, requeue_idx, err; - struct sk_buff *skb; - grant_ref_t ref; - struct xen_netif_rx_request *req; + int err; unsigned int feature_rx_copy; unsigned int j = 0; struct netfront_queue *queue = NULL; @@ -2040,47 +2025,8 @@ static int xennet_connect(struct net_device *dev) netdev_update_features(dev); rtnl_unlock(); - /* By now, the queue structures have been set up */ - for (j = 0; j < num_queues; ++j) { - queue = &np->queues[j]; - - /* Step 1: Discard all pending TX packet fragments. */ - spin_lock_irq(&queue->tx_lock); - xennet_release_tx_bufs(queue); - spin_unlock_irq(&queue->tx_lock); - - /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ - spin_lock_bh(&queue->rx_lock); - - for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { - skb_frag_t *frag; - const struct page *page; - if (!queue->rx_skbs[i]) - continue; - - skb = queue->rx_skbs[requeue_idx] = xennet_get_rx_skb(queue, i); - ref = queue->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(queue, i); - req = RING_GET_REQUEST(&queue->rx, requeue_idx); - - frag = &skb_shinfo(skb)->frags[0]; - page = skb_frag_page(frag); - gnttab_grant_foreign_access_ref( - ref, queue->info->xbdev->otherend_id, - pfn_to_mfn(page_to_pfn(page)), - 0); - req->gref = ref; - req->id = requeue_idx; - - requeue_idx++; - } - - queue->rx.req_prod_pvt = requeue_idx; - - spin_unlock_bh(&queue->rx_lock); - } - /* - * Step 3: All public and private state should now be sane. Get + * All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver * domain a kick because we've probably just requeued some * packets. -- cgit v1.2.3-70-g09d2 From 69cb85242f4ff1cbbac5a45c05223600084760e8 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:24 +0100 Subject: xen-netfront: print correct number of queues When less than the requested number of queues could be created, include the actual number in the warning (instead of the requested number). Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/xen-netfront.c') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 0b133a3d431..28204bc4f36 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1815,8 +1815,8 @@ static int xennet_create_queues(struct netfront_info *info, ret = xennet_init_queue(queue); if (ret < 0) { - dev_warn(&info->netdev->dev, "only created %d queues\n", - num_queues); + dev_warn(&info->netdev->dev, + "only created %d queues\n", i); num_queues = i; break; } -- cgit v1.2.3-70-g09d2 From 97a6d1bb2b658ac85ed88205ccd1ab809899884d Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Mon, 11 Aug 2014 18:32:23 +0100 Subject: xen-netfront: Fix handling packets on compound pages with skb_linearize There is a long known problem with the netfront/netback interface: if the guest tries to send a packet which constitues more than MAX_SKB_FRAGS + 1 ring slots, it gets dropped. The reason is that netback maps these slots to a frag in the frags array, which is limited by size. Having so many slots can occur since compound pages were introduced, as the ring protocol slice them up into individual (non-compound) page aligned slots. The theoretical worst case scenario looks like this (note, skbs are limited to 64 Kb here): linear buffer: at most PAGE_SIZE - 17 * 2 bytes, overlapping page boundary, using 2 slots first 15 frags: 1 + PAGE_SIZE + 1 bytes long, first and last bytes are at the end and the beginning of a page, therefore they use 3 * 15 = 45 slots last 2 frags: 1 + 1 bytes, overlapping page boundary, 2 * 2 = 4 slots Although I don't think this 51 slots skb can really happen, we need a solution which can deal with every scenario. In real life there is only a few slots overdue, but usually it causes the TCP stream to be blocked, as the retry will most likely have the same buffer layout. This patch solves this problem by linearizing the packet. This is not the fastest way, and it can fail much easier as it tries to allocate a big linear area for the whole packet, but probably easier by an order of magnitude than anything else. Probably this code path is not touched very frequently anyway. Signed-off-by: Zoltan Kiss Cc: Wei Liu Cc: Ian Campbell Cc: Paul Durrant Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: xen-devel@lists.xenproject.org Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/xen-netfront.c') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 28204bc4f36..ca82f545ec2 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -628,9 +628,10 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + xennet_count_skb_frag_slots(skb); if (unlikely(slots > MAX_SKB_FRAGS + 1)) { - net_alert_ratelimited( - "xennet: skb rides the rocket: %d slots\n", slots); - goto drop; + net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n", + slots, skb->len); + if (skb_linearize(skb)) + goto drop; } spin_lock_irqsave(&queue->tx_lock, flags); -- cgit v1.2.3-70-g09d2