ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c @ 6401:4ab607ca02c3

Watch may fire before we've allocated the interface structure.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Wed Aug 24 20:43:16 2005 +0000 (2005-08-24)
parents d3c0d85b7ef8
children be5c24f2709c
line source
1 /* Xenbus code for blkif backend
2 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <stdarg.h>
19 #include <linux/module.h>
20 #include <asm-xen/xenbus.h>
21 #include "common.h"
23 struct backend_info
24 {
25 struct xenbus_device *dev;
27 /* our communications channel */
28 blkif_t *blkif;
30 long int frontend_id;
31 long int pdev;
32 long int readonly;
34 /* watch back end for changes */
35 struct xenbus_watch backend_watch;
37 /* watch front end for changes */
38 struct xenbus_watch watch;
39 char *frontpath;
40 };
42 static int blkback_remove(struct xenbus_device *dev)
43 {
44 struct backend_info *be = dev->data;
46 if (be->watch.node)
47 unregister_xenbus_watch(&be->watch);
48 unregister_xenbus_watch(&be->backend_watch);
49 if (be->blkif)
50 blkif_put(be->blkif);
51 if (be->frontpath)
52 kfree(be->frontpath);
53 kfree(be);
54 return 0;
55 }
57 /* Front end tells us frame. */
58 static void frontend_changed(struct xenbus_watch *watch, const char *node)
59 {
60 unsigned long sharedmfn;
61 unsigned int evtchn;
62 int err;
63 struct backend_info *be
64 = container_of(watch, struct backend_info, watch);
66 /* If other end is gone, delete ourself. */
67 if (node && !xenbus_exists(be->frontpath, "")) {
68 xenbus_rm(be->dev->nodename, "");
69 device_unregister(&be->dev->dev);
70 return;
71 }
72 if (be->blkif == NULL || be->blkif->status == CONNECTED)
73 return;
75 err = xenbus_gather(be->frontpath, "grant-id", "%lu", &sharedmfn,
76 "event-channel", "%u", &evtchn, NULL);
77 if (err) {
78 xenbus_dev_error(be->dev, err,
79 "reading %s/grant-id and event-channel",
80 be->frontpath);
81 return;
82 }
84 /* Supply the information about the device the frontend needs */
85 err = xenbus_transaction_start(be->dev->nodename);
86 if (err) {
87 xenbus_dev_error(be->dev, err, "starting transaction");
88 return;
89 }
91 err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
92 vbd_size(&be->blkif->vbd));
93 if (err) {
94 xenbus_dev_error(be->dev, err, "writing %s/sectors",
95 be->dev->nodename);
96 goto abort;
97 }
99 /* FIXME: use a typename instead */
100 err = xenbus_printf(be->dev->nodename, "info", "%u",
101 vbd_info(&be->blkif->vbd));
102 if (err) {
103 xenbus_dev_error(be->dev, err, "writing %s/info",
104 be->dev->nodename);
105 goto abort;
106 }
107 err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
108 vbd_secsize(&be->blkif->vbd));
109 if (err) {
110 xenbus_dev_error(be->dev, err, "writing %s/sector-size",
111 be->dev->nodename);
112 goto abort;
113 }
115 /* Map the shared frame, irq etc. */
116 err = blkif_map(be->blkif, sharedmfn, evtchn);
117 if (err) {
118 xenbus_dev_error(be->dev, err,
119 "mapping shared-frame %lu port %u",
120 sharedmfn, evtchn);
121 goto abort;
122 }
124 xenbus_transaction_end(0);
125 xenbus_dev_ok(be->dev);
127 return;
129 abort:
130 xenbus_transaction_end(1);
131 }
133 /*
134 Setup supplies physical device.
135 We provide event channel and device details to front end.
136 Frontend supplies shared frame and event channel.
137 */
138 static void backend_changed(struct xenbus_watch *watch, const char *node)
139 {
140 int err;
141 char *p;
142 long int handle, pdev;
143 struct backend_info *be
144 = container_of(watch, struct backend_info, backend_watch);
145 struct xenbus_device *dev = be->dev;
147 err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev);
148 if (XENBUS_EXIST_ERR(err))
149 return;
150 if (err < 0) {
151 xenbus_dev_error(dev, err, "reading physical-device");
152 return;
153 }
154 if (be->pdev && be->pdev != pdev) {
155 printk(KERN_WARNING
156 "changing physical-device not supported\n");
157 return;
158 }
159 be->pdev = pdev;
161 /* If there's a read-only node, we're read only. */
162 p = xenbus_read(dev->nodename, "read-only", NULL);
163 if (!IS_ERR(p)) {
164 be->readonly = 1;
165 kfree(p);
166 }
168 if (be->blkif == NULL) {
169 /* Front end dir is a number, which is used as the handle. */
170 p = strrchr(be->frontpath, '/') + 1;
171 handle = simple_strtoul(p, NULL, 0);
173 be->blkif = alloc_blkif(be->frontend_id);
174 if (IS_ERR(be->blkif)) {
175 err = PTR_ERR(be->blkif);
176 be->blkif = NULL;
177 xenbus_dev_error(dev, err, "creating block interface");
178 return;
179 }
181 err = vbd_create(be->blkif, handle, be->pdev, be->readonly);
182 if (err) {
183 xenbus_dev_error(dev, err, "creating vbd structure");
184 return;
185 }
187 /* Pass in NULL node to skip exist test. */
188 frontend_changed(&be->watch, NULL);
189 }
190 }
192 static int blkback_probe(struct xenbus_device *dev,
193 const struct xenbus_device_id *id)
194 {
195 struct backend_info *be;
196 char *frontend;
197 int err;
199 be = kmalloc(sizeof(*be), GFP_KERNEL);
200 if (!be) {
201 xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
202 return -ENOMEM;
203 }
204 memset(be, 0, sizeof(*be));
206 frontend = NULL;
207 err = xenbus_gather(dev->nodename,
208 "frontend-id", "%li", &be->frontend_id,
209 "frontend", NULL, &frontend,
210 NULL);
211 if (XENBUS_EXIST_ERR(err))
212 goto free_be;
213 if (err < 0) {
214 xenbus_dev_error(dev, err,
215 "reading %s/frontend or frontend-id",
216 dev->nodename);
217 goto free_be;
218 }
219 if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
220 /* If we can't get a frontend path and a frontend-id,
221 * then our bus-id is no longer valid and we need to
222 * destroy the backend device.
223 */
224 err = -ENOENT;
225 goto free_be;
226 }
228 be->dev = dev;
229 be->backend_watch.node = dev->nodename;
230 be->backend_watch.callback = backend_changed;
231 err = register_xenbus_watch(&be->backend_watch);
232 if (err) {
233 be->backend_watch.node = NULL;
234 xenbus_dev_error(dev, err, "adding backend watch on %s",
235 dev->nodename);
236 goto free_be;
237 }
239 be->frontpath = frontend;
240 be->watch.node = be->frontpath;
241 be->watch.callback = frontend_changed;
242 err = register_xenbus_watch(&be->watch);
243 if (err) {
244 be->watch.node = NULL;
245 xenbus_dev_error(dev, err,
246 "adding frontend watch on %s",
247 be->frontpath);
248 goto free_be;
249 }
251 dev->data = be;
253 backend_changed(&be->backend_watch, dev->nodename);
254 return 0;
256 free_be:
257 if (be->backend_watch.node)
258 unregister_xenbus_watch(&be->backend_watch);
259 if (frontend)
260 kfree(frontend);
261 kfree(be);
262 return err;
263 }
265 static struct xenbus_device_id blkback_ids[] = {
266 { "vbd" },
267 { "" }
268 };
270 static struct xenbus_driver blkback = {
271 .name = "vbd",
272 .owner = THIS_MODULE,
273 .ids = blkback_ids,
274 .probe = blkback_probe,
275 .remove = blkback_remove,
276 };
278 void blkif_xenbus_init(void)
279 {
280 xenbus_register_backend(&blkback);
281 }