ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/blkback/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 9ffa49fe58ab
children 48c0f5489d44
line source
1 /******************************************************************************
2 * arch/xen/drivers/blkif/backend/interface.c
3 *
4 * Block-device interface management.
5 *
6 * Copyright (c) 2004, 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 <xen/evtchn.h>
36 static kmem_cache_t *blkif_cachep;
38 blkif_t *blkif_alloc(domid_t domid)
39 {
40 blkif_t *blkif;
42 blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
43 if (!blkif)
44 return ERR_PTR(-ENOMEM);
46 memset(blkif, 0, sizeof(*blkif));
47 blkif->domid = domid;
48 spin_lock_init(&blkif->blk_ring_lock);
49 atomic_set(&blkif->refcnt, 1);
50 init_waitqueue_head(&blkif->wq);
51 blkif->st_print = jiffies;
52 init_waitqueue_head(&blkif->waiting_to_free);
54 return blkif;
55 }
57 static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
58 {
59 struct gnttab_map_grant_ref op;
60 int ret;
62 gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
63 GNTMAP_host_map, shared_page, blkif->domid);
65 lock_vm_area(blkif->blk_ring_area);
66 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
67 unlock_vm_area(blkif->blk_ring_area);
68 BUG_ON(ret);
70 if (op.status) {
71 DPRINTK(" Grant table operation failure !\n");
72 return op.status;
73 }
75 blkif->shmem_ref = shared_page;
76 blkif->shmem_handle = op.handle;
78 #ifdef CONFIG_XEN_IA64_DOM0_NON_VP
79 /* on some arch's, map_grant_ref behaves like mmap, in that the
80 * passed address is a hint and a different address may be returned */
81 blkif->blk_ring_area->addr = gnttab_map_vaddr(op);
82 #endif
84 return 0;
85 }
87 static void unmap_frontend_page(blkif_t *blkif)
88 {
89 struct gnttab_unmap_grant_ref op;
90 int ret;
92 gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
93 GNTMAP_host_map, blkif->shmem_handle);
95 lock_vm_area(blkif->blk_ring_area);
96 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
97 unlock_vm_area(blkif->blk_ring_area);
98 BUG_ON(ret);
99 }
101 int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
102 {
103 blkif_sring_t *sring;
104 int err;
105 struct evtchn_bind_interdomain bind_interdomain;
107 /* Already connected through? */
108 if (blkif->irq)
109 return 0;
111 if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
112 return -ENOMEM;
114 err = map_frontend_page(blkif, shared_page);
115 if (err) {
116 free_vm_area(blkif->blk_ring_area);
117 return err;
118 }
120 bind_interdomain.remote_dom = blkif->domid;
121 bind_interdomain.remote_port = evtchn;
123 err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
124 &bind_interdomain);
125 if (err) {
126 unmap_frontend_page(blkif);
127 free_vm_area(blkif->blk_ring_area);
128 return err;
129 }
131 blkif->evtchn = bind_interdomain.local_port;
133 sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
134 BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
136 blkif->irq = bind_evtchn_to_irqhandler(
137 blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif);
139 return 0;
140 }
142 void blkif_free(blkif_t *blkif)
143 {
144 atomic_dec(&blkif->refcnt);
145 wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
147 /* Already disconnected? */
148 if (blkif->irq)
149 unbind_from_irqhandler(blkif->irq, blkif);
151 vbd_free(&blkif->vbd);
153 if (blkif->blk_ring.sring) {
154 unmap_frontend_page(blkif);
155 free_vm_area(blkif->blk_ring_area);
156 }
158 kmem_cache_free(blkif_cachep, blkif);
159 }
161 void __init blkif_interface_init(void)
162 {
163 blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
164 0, 0, NULL, NULL);
165 }
167 /*
168 * Local variables:
169 * c-file-style: "linux"
170 * indent-tabs-mode: t
171 * c-indent-level: 8
172 * c-basic-offset: 8
173 * tab-width: 8
174 * End:
175 */