ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/interface.c @ 10029:019411cc3ae5

Fix blkif and netif backend teardown -- do not remove devices from
sysfs (and hence trigger hotplug callbacks) until the devices really
are dead. This fixes a bug where the deferred code to free a blk
device was running concurrently with a hotplug-remove callback which
would try to reclaim the underlying storage. In some cases the race
would be lost and the hotplug script would fail.

Thanks to the Zhu Han at Intel for finding the root cause of this
long-term and annoying bug!

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 10 13:27:17 2006 +0100 (2006-05-10)
parents 42a8e3101c6c
children 48c0f5489d44
line source
1 /******************************************************************************
2 * arch/xen/drivers/netif/backend/interface.c
3 *
4 * Network-device interface management.
5 *
6 * Copyright (c) 2004-2005, Keir Fraser
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
33 #include "common.h"
34 #include <linux/ethtool.h>
35 #include <linux/rtnetlink.h>
37 static void __netif_up(netif_t *netif)
38 {
39 struct net_device *dev = netif->dev;
40 spin_lock_bh(&dev->xmit_lock);
41 netif->active = 1;
42 spin_unlock_bh(&dev->xmit_lock);
43 enable_irq(netif->irq);
44 netif_schedule_work(netif);
45 }
47 static void __netif_down(netif_t *netif)
48 {
49 struct net_device *dev = netif->dev;
50 disable_irq(netif->irq);
51 spin_lock_bh(&dev->xmit_lock);
52 netif->active = 0;
53 spin_unlock_bh(&dev->xmit_lock);
54 netif_deschedule_work(netif);
55 }
57 static int net_open(struct net_device *dev)
58 {
59 netif_t *netif = netdev_priv(dev);
60 if (netif->status == CONNECTED)
61 __netif_up(netif);
62 netif_start_queue(dev);
63 return 0;
64 }
66 static int net_close(struct net_device *dev)
67 {
68 netif_t *netif = netdev_priv(dev);
69 netif_stop_queue(dev);
70 if (netif->status == CONNECTED)
71 __netif_down(netif);
72 return 0;
73 }
75 static struct ethtool_ops network_ethtool_ops =
76 {
77 .get_tx_csum = ethtool_op_get_tx_csum,
78 .set_tx_csum = ethtool_op_set_tx_csum,
79 };
81 netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
82 {
83 int err = 0, i;
84 struct net_device *dev;
85 netif_t *netif;
86 char name[IFNAMSIZ] = {};
88 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
89 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
90 if (dev == NULL) {
91 DPRINTK("Could not create netif: out of memory\n");
92 return ERR_PTR(-ENOMEM);
93 }
95 netif = netdev_priv(dev);
96 memset(netif, 0, sizeof(*netif));
97 netif->domid = domid;
98 netif->handle = handle;
99 netif->status = DISCONNECTED;
100 atomic_set(&netif->refcnt, 1);
101 init_waitqueue_head(&netif->waiting_to_free);
102 netif->dev = dev;
104 netif->credit_bytes = netif->remaining_credit = ~0UL;
105 netif->credit_usec = 0UL;
106 init_timer(&netif->credit_timeout);
108 dev->hard_start_xmit = netif_be_start_xmit;
109 dev->get_stats = netif_be_get_stats;
110 dev->open = net_open;
111 dev->stop = net_close;
112 dev->features = NETIF_F_IP_CSUM;
114 SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
116 /* Disable queuing. */
117 dev->tx_queue_len = 0;
119 for (i = 0; i < ETH_ALEN; i++)
120 if (be_mac[i] != 0)
121 break;
122 if (i == ETH_ALEN) {
123 /*
124 * Initialise a dummy MAC address. We choose the numerically
125 * largest non-broadcast address to prevent the address getting
126 * stolen by an Ethernet bridge for STP purposes.
127 * (FE:FF:FF:FF:FF:FF)
128 */
129 memset(dev->dev_addr, 0xFF, ETH_ALEN);
130 dev->dev_addr[0] &= ~0x01;
131 } else
132 memcpy(dev->dev_addr, be_mac, ETH_ALEN);
134 rtnl_lock();
135 err = register_netdevice(dev);
136 rtnl_unlock();
137 if (err) {
138 DPRINTK("Could not register new net device %s: err=%d\n",
139 dev->name, err);
140 free_netdev(dev);
141 return ERR_PTR(err);
142 }
144 DPRINTK("Successfully created netif\n");
145 return netif;
146 }
148 static int map_frontend_pages(
149 netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
150 {
151 struct gnttab_map_grant_ref op;
152 int ret;
154 gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
155 GNTMAP_host_map, tx_ring_ref, netif->domid);
157 lock_vm_area(netif->tx_comms_area);
158 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
159 unlock_vm_area(netif->tx_comms_area);
160 BUG_ON(ret);
162 if (op.status) {
163 DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
164 return op.status;
165 }
167 netif->tx_shmem_ref = tx_ring_ref;
168 netif->tx_shmem_handle = op.handle;
170 gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
171 GNTMAP_host_map, rx_ring_ref, netif->domid);
173 lock_vm_area(netif->rx_comms_area);
174 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
175 unlock_vm_area(netif->rx_comms_area);
176 BUG_ON(ret);
178 if (op.status) {
179 DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
180 return op.status;
181 }
183 netif->rx_shmem_ref = rx_ring_ref;
184 netif->rx_shmem_handle = op.handle;
186 return 0;
187 }
189 static void unmap_frontend_pages(netif_t *netif)
190 {
191 struct gnttab_unmap_grant_ref op;
192 int ret;
194 gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
195 GNTMAP_host_map, netif->tx_shmem_handle);
197 lock_vm_area(netif->tx_comms_area);
198 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
199 unlock_vm_area(netif->tx_comms_area);
200 BUG_ON(ret);
202 gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
203 GNTMAP_host_map, netif->rx_shmem_handle);
205 lock_vm_area(netif->rx_comms_area);
206 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
207 unlock_vm_area(netif->rx_comms_area);
208 BUG_ON(ret);
209 }
211 int netif_map(netif_t *netif, unsigned long tx_ring_ref,
212 unsigned long rx_ring_ref, unsigned int evtchn)
213 {
214 int err = -ENOMEM;
215 netif_tx_sring_t *txs;
216 netif_rx_sring_t *rxs;
217 struct evtchn_bind_interdomain bind_interdomain;
219 /* Already connected through? */
220 if (netif->irq)
221 return 0;
223 netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
224 if (netif->tx_comms_area == NULL)
225 return -ENOMEM;
226 netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
227 if (netif->rx_comms_area == NULL)
228 goto err_rx;
230 err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
231 if (err)
232 goto err_map;
234 bind_interdomain.remote_dom = netif->domid;
235 bind_interdomain.remote_port = evtchn;
237 err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
238 &bind_interdomain);
239 if (err)
240 goto err_hypervisor;
242 netif->evtchn = bind_interdomain.local_port;
244 netif->irq = bind_evtchn_to_irqhandler(
245 netif->evtchn, netif_be_int, 0, netif->dev->name, netif);
246 disable_irq(netif->irq);
248 txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
249 BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
251 rxs = (netif_rx_sring_t *)
252 ((char *)netif->rx_comms_area->addr);
253 BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
255 netif->rx_req_cons_peek = 0;
257 netif_get(netif);
258 wmb(); /* Other CPUs see new state before interface is started. */
260 rtnl_lock();
261 netif->status = CONNECTED;
262 wmb();
263 if (netif_running(netif->dev))
264 __netif_up(netif);
265 rtnl_unlock();
267 return 0;
268 err_hypervisor:
269 unmap_frontend_pages(netif);
270 err_map:
271 free_vm_area(netif->rx_comms_area);
272 err_rx:
273 free_vm_area(netif->tx_comms_area);
274 return err;
275 }
277 static void netif_free(netif_t *netif)
278 {
279 atomic_dec(&netif->refcnt);
280 wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
282 if (netif->irq)
283 unbind_from_irqhandler(netif->irq, netif);
285 unregister_netdev(netif->dev);
287 if (netif->tx.sring) {
288 unmap_frontend_pages(netif);
289 free_vm_area(netif->tx_comms_area);
290 free_vm_area(netif->rx_comms_area);
291 }
293 free_netdev(netif->dev);
294 }
296 void netif_disconnect(netif_t *netif)
297 {
298 switch (netif->status) {
299 case CONNECTED:
300 rtnl_lock();
301 netif->status = DISCONNECTING;
302 wmb();
303 if (netif_running(netif->dev))
304 __netif_down(netif);
305 rtnl_unlock();
306 netif_put(netif);
307 /* fall through */
308 case DISCONNECTED:
309 netif_free(netif);
310 break;
311 default:
312 BUG();
313 }
314 }
316 /*
317 * Local variables:
318 * c-file-style: "linux"
319 * indent-tabs-mode: t
320 * c-indent-level: 8
321 * c-basic-offset: 8
322 * tab-width: 8
323 * End:
324 */