diff options
author | David Vrabel <david.vrabel@citrix.com> | 2014-06-18 05:47:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-21 19:14:26 -0400 |
commit | ce58725fec6e609eee162e6af848bd57107b97af (patch) | |
tree | 0c2b20bc313a7e0b292904e2352b7ac72719044a | |
parent | 765418694bc99d91e71ede6d2889a6328da137fe (diff) |
xen-netfront: recreate queues correctly when reconnecting
When reconnecting to the backend (after a resume/migration, for example),
a different number of queues may be required (since the guest may have
moved to a different host with different capabilities). During the
reconnection the old queues are torn down and new ones created.
Introduce xennet_create_queues() and xennet_destroy_queues() that fixes
three bugs during the reconnection.
- The old info->queues was leaked.
- The old queue's napi instances were not deleted.
- The new queue's napi instances were left disabled (which meant no
packets could be received).
The xennet_destroy_queues() calls is deferred until the reconnection
instead of the disconnection (in xennet_disconnect_backend()) because
napi_disable() might sleep.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/xen-netfront.c | 104 |
1 files changed, 72 insertions, 32 deletions
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index daaf1e56e41e..2ccb4a02368b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -1699,8 +1699,6 @@ static int xennet_init_queue(struct netfront_queue *queue) | |||
1699 | goto exit_free_tx; | 1699 | goto exit_free_tx; |
1700 | } | 1700 | } |
1701 | 1701 | ||
1702 | netif_napi_add(queue->info->netdev, &queue->napi, xennet_poll, 64); | ||
1703 | |||
1704 | return 0; | 1702 | return 0; |
1705 | 1703 | ||
1706 | exit_free_tx: | 1704 | exit_free_tx: |
@@ -1791,6 +1789,70 @@ error: | |||
1791 | return err; | 1789 | return err; |
1792 | } | 1790 | } |
1793 | 1791 | ||
1792 | static void xennet_destroy_queues(struct netfront_info *info) | ||
1793 | { | ||
1794 | unsigned int i; | ||
1795 | |||
1796 | rtnl_lock(); | ||
1797 | |||
1798 | for (i = 0; i < info->netdev->real_num_tx_queues; i++) { | ||
1799 | struct netfront_queue *queue = &info->queues[i]; | ||
1800 | |||
1801 | if (netif_running(info->netdev)) | ||
1802 | napi_disable(&queue->napi); | ||
1803 | netif_napi_del(&queue->napi); | ||
1804 | } | ||
1805 | |||
1806 | rtnl_unlock(); | ||
1807 | |||
1808 | kfree(info->queues); | ||
1809 | info->queues = NULL; | ||
1810 | } | ||
1811 | |||
1812 | static int xennet_create_queues(struct netfront_info *info, | ||
1813 | unsigned int num_queues) | ||
1814 | { | ||
1815 | unsigned int i; | ||
1816 | int ret; | ||
1817 | |||
1818 | info->queues = kcalloc(num_queues, sizeof(struct netfront_queue), | ||
1819 | GFP_KERNEL); | ||
1820 | if (!info->queues) | ||
1821 | return -ENOMEM; | ||
1822 | |||
1823 | rtnl_lock(); | ||
1824 | |||
1825 | for (i = 0; i < num_queues; i++) { | ||
1826 | struct netfront_queue *queue = &info->queues[i]; | ||
1827 | |||
1828 | queue->id = i; | ||
1829 | queue->info = info; | ||
1830 | |||
1831 | ret = xennet_init_queue(queue); | ||
1832 | if (ret < 0) { | ||
1833 | dev_warn(&info->netdev->dev, "only created %d queues\n", | ||
1834 | num_queues); | ||
1835 | num_queues = i; | ||
1836 | break; | ||
1837 | } | ||
1838 | |||
1839 | netif_napi_add(queue->info->netdev, &queue->napi, | ||
1840 | xennet_poll, 64); | ||
1841 | if (netif_running(info->netdev)) | ||
1842 | napi_enable(&queue->napi); | ||
1843 | } | ||
1844 | |||
1845 | netif_set_real_num_tx_queues(info->netdev, num_queues); | ||
1846 | |||
1847 | rtnl_unlock(); | ||
1848 | |||
1849 | if (num_queues == 0) { | ||
1850 | dev_err(&info->netdev->dev, "no queues\n"); | ||
1851 | return -EINVAL; | ||
1852 | } | ||
1853 | return 0; | ||
1854 | } | ||
1855 | |||
1794 | /* Common code used when first setting up, and when resuming. */ | 1856 | /* Common code used when first setting up, and when resuming. */ |
1795 | static int talk_to_netback(struct xenbus_device *dev, | 1857 | static int talk_to_netback(struct xenbus_device *dev, |
1796 | struct netfront_info *info) | 1858 | struct netfront_info *info) |
@@ -1827,42 +1889,20 @@ static int talk_to_netback(struct xenbus_device *dev, | |||
1827 | goto out; | 1889 | goto out; |
1828 | } | 1890 | } |
1829 | 1891 | ||
1830 | /* Allocate array of queues */ | 1892 | if (info->queues) |
1831 | info->queues = kcalloc(num_queues, sizeof(struct netfront_queue), GFP_KERNEL); | 1893 | xennet_destroy_queues(info); |
1832 | if (!info->queues) { | 1894 | |
1833 | err = -ENOMEM; | 1895 | err = xennet_create_queues(info, num_queues); |
1834 | goto out; | 1896 | if (err < 0) |
1835 | } | 1897 | goto destroy_ring; |
1836 | rtnl_lock(); | ||
1837 | netif_set_real_num_tx_queues(info->netdev, num_queues); | ||
1838 | rtnl_unlock(); | ||
1839 | 1898 | ||
1840 | /* Create shared ring, alloc event channel -- for each queue */ | 1899 | /* Create shared ring, alloc event channel -- for each queue */ |
1841 | for (i = 0; i < num_queues; ++i) { | 1900 | for (i = 0; i < num_queues; ++i) { |
1842 | queue = &info->queues[i]; | 1901 | queue = &info->queues[i]; |
1843 | queue->id = i; | ||
1844 | queue->info = info; | ||
1845 | err = xennet_init_queue(queue); | ||
1846 | if (err) { | ||
1847 | /* xennet_init_queue() cleans up after itself on failure, | ||
1848 | * but we still have to clean up any previously initialised | ||
1849 | * queues. If i > 0, set num_queues to i, then goto | ||
1850 | * destroy_ring, which calls xennet_disconnect_backend() | ||
1851 | * to tidy up. | ||
1852 | */ | ||
1853 | if (i > 0) { | ||
1854 | rtnl_lock(); | ||
1855 | netif_set_real_num_tx_queues(info->netdev, i); | ||
1856 | rtnl_unlock(); | ||
1857 | goto destroy_ring; | ||
1858 | } else { | ||
1859 | goto out; | ||
1860 | } | ||
1861 | } | ||
1862 | err = setup_netfront(dev, queue, feature_split_evtchn); | 1902 | err = setup_netfront(dev, queue, feature_split_evtchn); |
1863 | if (err) { | 1903 | if (err) { |
1864 | /* As for xennet_init_queue(), setup_netfront() will tidy | 1904 | /* setup_netfront() will tidy up the current |
1865 | * up the current queue on error, but we need to clean up | 1905 | * queue on error, but we need to clean up |
1866 | * those already allocated. | 1906 | * those already allocated. |
1867 | */ | 1907 | */ |
1868 | if (i > 0) { | 1908 | if (i > 0) { |