ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c @ 6298:e8c2c3123ec6

Improve error paths and cleanup code.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Fri Aug 19 17:38:07 2005 +0000 (2005-08-19)
parents 47d49e8b8042
children 631cc5dc3e8a
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;
29 struct vbd *vbd;
31 long int frontend_id;
32 long int pdev;
33 long int readonly;
35 /* watch back end for changes */
36 struct xenbus_watch backend_watch;
38 /* watch front end for changes */
39 struct xenbus_watch watch;
40 char *frontpath;
41 };
43 static int blkback_remove(struct xenbus_device *dev)
44 {
45 struct backend_info *be = dev->data;
47 if (be->watch.node)
48 unregister_xenbus_watch(&be->watch);
49 unregister_xenbus_watch(&be->backend_watch);
50 if (be->vbd)
51 vbd_free(be->blkif, be->vbd);
52 if (be->blkif)
53 blkif_put(be->blkif);
54 if (be->frontpath)
55 kfree(be->frontpath);
56 kfree(be);
57 return 0;
58 }
60 /* Front end tells us frame. */
61 static void frontend_changed(struct xenbus_watch *watch, const char *node)
62 {
63 unsigned long sharedmfn;
64 unsigned int evtchn;
65 int err;
66 struct backend_info *be
67 = container_of(watch, struct backend_info, watch);
69 /* If other end is gone, delete ourself. */
70 if (!xenbus_exists(be->frontpath, "")) {
71 xenbus_rm(be->dev->nodename, "");
72 device_unregister(&be->dev->dev);
73 return;
74 }
75 if (vbd_is_active(be->vbd))
76 return;
78 #ifndef CONFIG_XEN_BLKDEV_GRANT
79 err = xenbus_gather(be->frontpath, "shared-frame", "%lu", &sharedmfn,
80 "event-channel", "%u", &evtchn, NULL);
81 if (err) {
82 xenbus_dev_error(be->dev, err,
83 "reading %s/shared-frame and event-channel",
84 be->frontpath);
85 return;
86 }
87 #else
88 err = xenbus_gather(be->frontpath, "grant-id", "%lu", &sharedmfn,
89 "event-channel", "%u", &evtchn, NULL);
90 if (err) {
91 xenbus_dev_error(be->dev, err,
92 "reading %s/grant-id and event-channel",
93 be->frontpath);
94 return;
95 }
96 #endif
98 /* Domains must use same shared frame for all vbds. */
99 if (be->blkif->status == CONNECTED &&
100 (evtchn != be->blkif->remote_evtchn ||
101 sharedmfn != be->blkif->shmem_frame)) {
102 xenbus_dev_error(be->dev, err,
103 "Shared frame/evtchn %li/%u not same as"
104 " old %li/%u",
105 sharedmfn, evtchn,
106 be->blkif->shmem_frame,
107 be->blkif->remote_evtchn);
108 return;
109 }
111 /* Supply the information about the device the frontend needs */
112 err = xenbus_transaction_start(be->dev->nodename);
113 if (err) {
114 xenbus_dev_error(be->dev, err, "starting transaction");
115 return;
116 }
118 err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
119 vbd_size(be->vbd));
120 if (err) {
121 xenbus_dev_error(be->dev, err, "writing %s/sectors",
122 be->dev->nodename);
123 goto abort;
124 }
126 /* FIXME: use a typename instead */
127 err = xenbus_printf(be->dev->nodename, "info", "%u",
128 vbd_info(be->vbd));
129 if (err) {
130 xenbus_dev_error(be->dev, err, "writing %s/info",
131 be->dev->nodename);
132 goto abort;
133 }
134 err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
135 vbd_secsize(be->vbd));
136 if (err) {
137 xenbus_dev_error(be->dev, err, "writing %s/sector-size",
138 be->dev->nodename);
139 goto abort;
140 }
142 /* First vbd? We need to map the shared frame, irq etc. */
143 if (be->blkif->status != CONNECTED) {
144 err = blkif_map(be->blkif, sharedmfn, evtchn);
145 if (err) {
146 xenbus_dev_error(be->dev, err,
147 "mapping shared-frame %lu port %u",
148 sharedmfn, evtchn);
149 goto abort;
150 }
151 }
153 /* We're ready, activate. */
154 vbd_activate(be->blkif, be->vbd);
156 xenbus_transaction_end(0);
157 xenbus_dev_ok(be->dev);
159 return;
161 abort:
162 xenbus_transaction_end(1);
163 }
165 /*
166 Setup supplies physical device.
167 We provide event channel and device details to front end.
168 Frontend supplies shared frame and event channel.
169 */
170 static void backend_changed(struct xenbus_watch *watch, const char *node)
171 {
172 int err;
173 char *p;
174 char *frontend;
175 long int handle, pdev;
176 struct backend_info *be
177 = container_of(watch, struct backend_info, backend_watch);
178 struct xenbus_device *dev = be->dev;
180 frontend = NULL;
181 err = xenbus_gather(dev->nodename,
182 "frontend-id", "%li", &be->frontend_id,
183 "frontend", NULL, &frontend,
184 NULL);
185 if (XENBUS_EXIST_ERR(err) ||
186 strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
187 /* If we can't get a frontend path and a frontend-id,
188 * then our bus-id is no longer valid and we need to
189 * destroy the backend device.
190 */
191 goto device_fail;
192 }
193 if (err < 0) {
194 xenbus_dev_error(dev, err,
195 "reading %s/frontend or frontend-id",
196 dev->nodename);
197 goto device_fail;
198 }
200 if (!be->frontpath || strcmp(frontend, be->frontpath)) {
201 if (be->watch.node)
202 unregister_xenbus_watch(&be->watch);
203 if (be->frontpath)
204 kfree(be->frontpath);
205 be->frontpath = frontend;
206 frontend = NULL;
207 be->watch.node = be->frontpath;
208 be->watch.callback = frontend_changed;
209 err = register_xenbus_watch(&be->watch);
210 if (err) {
211 be->watch.node = NULL;
212 goto device_fail;
213 }
214 }
216 err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev);
217 if (XENBUS_EXIST_ERR(err))
218 goto out;
219 if (err < 0) {
220 xenbus_dev_error(dev, err, "reading physical-device");
221 goto device_fail;
222 }
223 if (be->pdev && be->pdev != pdev) {
224 printk(KERN_WARNING
225 "changing physical-device not supported\n");
226 goto device_fail;
227 }
228 be->pdev = pdev;
230 /* If there's a read-only node, we're read only. */
231 p = xenbus_read(dev->nodename, "read-only", NULL);
232 if (!IS_ERR(p)) {
233 be->readonly = 1;
234 kfree(p);
235 }
237 if (be->blkif == NULL) {
238 /* Front end dir is a number, which is used as the handle. */
239 p = strrchr(be->frontpath, '/') + 1;
240 handle = simple_strtoul(p, NULL, 0);
242 be->blkif = blkif_find(be->frontend_id);
243 if (IS_ERR(be->blkif)) {
244 err = PTR_ERR(be->blkif);
245 be->blkif = NULL;
246 goto device_fail;
247 }
249 be->vbd = vbd_create(be->blkif, handle, be->pdev,
250 be->readonly);
251 if (IS_ERR(be->vbd)) {
252 err = PTR_ERR(be->vbd);
253 be->vbd = NULL;
254 goto device_fail;
255 }
257 frontend_changed(&be->watch, be->frontpath);
258 }
260 out:
261 if (frontend)
262 kfree(frontend);
263 return;
265 device_fail:
266 device_unregister(&be->dev->dev);
267 goto out;
268 }
270 static int blkback_probe(struct xenbus_device *dev,
271 const struct xenbus_device_id *id)
272 {
273 struct backend_info *be;
274 int err;
276 be = kmalloc(sizeof(*be), GFP_KERNEL);
277 if (!be)
278 return -ENOMEM;
280 memset(be, 0, sizeof(*be));
282 be->dev = dev;
283 be->backend_watch.node = dev->nodename;
284 be->backend_watch.callback = backend_changed;
285 err = register_xenbus_watch(&be->backend_watch);
286 if (err)
287 goto free_be;
289 dev->data = be;
291 backend_changed(&be->backend_watch, dev->nodename);
292 return err;
293 free_be:
294 kfree(be);
295 return err;
296 }
298 static struct xenbus_device_id blkback_ids[] = {
299 { "vbd" },
300 { "" }
301 };
303 static struct xenbus_driver blkback = {
304 .name = "vbd",
305 .owner = THIS_MODULE,
306 .ids = blkback_ids,
307 .probe = blkback_probe,
308 .remove = blkback_remove,
309 };
311 void blkif_xenbus_init(void)
312 {
313 xenbus_register_backend(&blkback);
314 }