]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.44/hv_netvsc-use-rcu-to-fix-concurrent-rx-and-queue-changes.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.44 / hv_netvsc-use-rcu-to-fix-concurrent-rx-and-queue-changes.patch
CommitLineData
684f36d1
GKH
1From foo@baz Tue May 22 20:10:42 CEST 2018
2From: Stephen Hemminger <stephen@networkplumber.org>
3Date: Mon, 14 May 2018 15:32:16 -0700
4Subject: hv_netvsc: use RCU to fix concurrent rx and queue changes
5
6From: Stephen Hemminger <stephen@networkplumber.org>
7
8[ Commit 02400fcee2542ee334a2394e0d9f6efd969fe782 upstream. ]
9
10The receive processing may continue to happen while the
11internal network device state is in RCU grace period.
12The internal RNDIS structure is associated with the
13internal netvsc_device structure; both have the same
14RCU lifetime.
15
16Defer freeing all associated parts until after grace
17period.
18
19Fixes: 0cf737808ae7 ("hv_netvsc: netvsc_teardown_gpadl() split")
20Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
21Signed-off-by: David S. Miller <davem@davemloft.net>
22Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
23---
24 drivers/net/hyperv/netvsc.c | 17 ++++------------
25 drivers/net/hyperv/rndis_filter.c | 39 ++++++++++++++++----------------------
26 2 files changed, 22 insertions(+), 34 deletions(-)
27
28--- a/drivers/net/hyperv/netvsc.c
29+++ b/drivers/net/hyperv/netvsc.c
30@@ -89,6 +89,11 @@ static void free_netvsc_device(struct rc
31 = container_of(head, struct netvsc_device, rcu);
32 int i;
33
34+ kfree(nvdev->extension);
35+ vfree(nvdev->recv_buf);
36+ vfree(nvdev->send_buf);
37+ kfree(nvdev->send_section_map);
38+
39 for (i = 0; i < VRSS_CHANNEL_MAX; i++)
40 vfree(nvdev->chan_table[i].mrc.slots);
41
42@@ -210,12 +215,6 @@ static void netvsc_teardown_gpadl(struct
43 net_device->recv_buf_gpadl_handle = 0;
44 }
45
46- if (net_device->recv_buf) {
47- /* Free up the receive buffer */
48- vfree(net_device->recv_buf);
49- net_device->recv_buf = NULL;
50- }
51-
52 if (net_device->send_buf_gpadl_handle) {
53 ret = vmbus_teardown_gpadl(device->channel,
54 net_device->send_buf_gpadl_handle);
55@@ -230,12 +229,6 @@ static void netvsc_teardown_gpadl(struct
56 }
57 net_device->send_buf_gpadl_handle = 0;
58 }
59- if (net_device->send_buf) {
60- /* Free up the send buffer */
61- vfree(net_device->send_buf);
62- net_device->send_buf = NULL;
63- }
64- kfree(net_device->send_section_map);
65 }
66
67 int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx)
68--- a/drivers/net/hyperv/rndis_filter.c
69+++ b/drivers/net/hyperv/rndis_filter.c
70@@ -266,13 +266,23 @@ static void rndis_set_link_state(struct
71 }
72 }
73
74-static void rndis_filter_receive_response(struct rndis_device *dev,
75- struct rndis_message *resp)
76+static void rndis_filter_receive_response(struct net_device *ndev,
77+ struct netvsc_device *nvdev,
78+ const struct rndis_message *resp)
79 {
80+ struct rndis_device *dev = nvdev->extension;
81 struct rndis_request *request = NULL;
82 bool found = false;
83 unsigned long flags;
84- struct net_device *ndev = dev->ndev;
85+
86+ /* This should never happen, it means control message
87+ * response received after device removed.
88+ */
89+ if (dev->state == RNDIS_DEV_UNINITIALIZED) {
90+ netdev_err(ndev,
91+ "got rndis message uninitialized\n");
92+ return;
93+ }
94
95 spin_lock_irqsave(&dev->request_lock, flags);
96 list_for_each_entry(request, &dev->req_list, list_ent) {
97@@ -353,7 +363,7 @@ static inline void *rndis_get_ppi(struct
98 }
99
100 static int rndis_filter_receive_data(struct net_device *ndev,
101- struct rndis_device *dev,
102+ struct netvsc_device *nvdev,
103 struct rndis_message *msg,
104 struct vmbus_channel *channel,
105 void *data, u32 data_buflen)
106@@ -373,7 +383,7 @@ static int rndis_filter_receive_data(str
107 * should be the data packet size plus the trailer padding size
108 */
109 if (unlikely(data_buflen < rndis_pkt->data_len)) {
110- netdev_err(dev->ndev, "rndis message buffer "
111+ netdev_err(ndev, "rndis message buffer "
112 "overflow detected (got %u, min %u)"
113 "...dropping this message!\n",
114 data_buflen, rndis_pkt->data_len);
115@@ -401,34 +411,20 @@ int rndis_filter_receive(struct net_devi
116 void *data, u32 buflen)
117 {
118 struct net_device_context *net_device_ctx = netdev_priv(ndev);
119- struct rndis_device *rndis_dev = net_dev->extension;
120 struct rndis_message *rndis_msg = data;
121
122- /* Make sure the rndis device state is initialized */
123- if (unlikely(!rndis_dev)) {
124- netif_err(net_device_ctx, rx_err, ndev,
125- "got rndis message but no rndis device!\n");
126- return NVSP_STAT_FAIL;
127- }
128-
129- if (unlikely(rndis_dev->state == RNDIS_DEV_UNINITIALIZED)) {
130- netif_err(net_device_ctx, rx_err, ndev,
131- "got rndis message uninitialized\n");
132- return NVSP_STAT_FAIL;
133- }
134-
135 if (netif_msg_rx_status(net_device_ctx))
136 dump_rndis_message(dev, rndis_msg);
137
138 switch (rndis_msg->ndis_msg_type) {
139 case RNDIS_MSG_PACKET:
140- return rndis_filter_receive_data(ndev, rndis_dev, rndis_msg,
141+ return rndis_filter_receive_data(ndev, net_dev, rndis_msg,
142 channel, data, buflen);
143 case RNDIS_MSG_INIT_C:
144 case RNDIS_MSG_QUERY_C:
145 case RNDIS_MSG_SET_C:
146 /* completion msgs */
147- rndis_filter_receive_response(rndis_dev, rndis_msg);
148+ rndis_filter_receive_response(ndev, net_dev, rndis_msg);
149 break;
150
151 case RNDIS_MSG_INDICATE:
152@@ -1349,7 +1345,6 @@ void rndis_filter_device_remove(struct h
153 net_dev->extension = NULL;
154
155 netvsc_device_remove(dev);
156- kfree(rndis_dev);
157 }
158
159 int rndis_filter_open(struct netvsc_device *nvdev)