ia64/linux-2.6.18-xen.hg

view drivers/xen/blktap/xenbus.c @ 663:035670ec617c

blktap: Fix Reconnect demand by Frontend

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Sep 09 15:13:29 2008 +0100 (2008-09-09)
parents ba72914de93a
children
line source
1 /* drivers/xen/blktap/xenbus.c
2 *
3 * Xenbus code for blktap
4 *
5 * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
6 *
7 * Based on the blkback xenbus code:
8 *
9 * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
10 * Copyright (C) 2005 XenSource Ltd
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License version 2
14 * as published by the Free Software Foundation; or, when distributed
15 * separately from the Linux kernel or incorporated into other
16 * software packages, subject to the following license:
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a copy
19 * of this source file (the "Software"), to deal in the Software without
20 * restriction, including without limitation the rights to use, copy, modify,
21 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
22 * and to permit persons to whom the Software is furnished to do so, subject to
23 * the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included in
26 * all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
34 * IN THE SOFTWARE.
35 */
37 #include <stdarg.h>
38 #include <linux/module.h>
39 #include <linux/kthread.h>
40 #include <xen/xenbus.h>
41 #include "common.h"
44 struct backend_info
45 {
46 struct xenbus_device *dev;
47 blkif_t *blkif;
48 struct xenbus_watch backend_watch;
49 int xenbus_id;
50 int group_added;
51 };
54 static void connect(struct backend_info *);
55 static int connect_ring(struct backend_info *);
56 static int blktap_remove(struct xenbus_device *dev);
57 static int blktap_probe(struct xenbus_device *dev,
58 const struct xenbus_device_id *id);
59 static void tap_backend_changed(struct xenbus_watch *, const char **,
60 unsigned int);
61 static void tap_frontend_changed(struct xenbus_device *dev,
62 enum xenbus_state frontend_state);
64 static int strsep_len(const char *str, char c, unsigned int len)
65 {
66 unsigned int i;
68 for (i = 0; str[i]; i++)
69 if (str[i] == c) {
70 if (len == 0)
71 return i;
72 len--;
73 }
74 return (len == 0) ? i : -ERANGE;
75 }
77 static long get_id(const char *str)
78 {
79 int len,end;
80 const char *ptr;
81 char *tptr, num[10];
83 len = strsep_len(str, '/', 2);
84 end = strlen(str);
85 if ( (len < 0) || (end < 0) ) return -1;
87 ptr = str + len + 1;
88 strncpy(num,ptr,end - len);
89 tptr = num + (end - (len + 1));
90 *tptr = '\0';
91 DPRINTK("Get_id called for %s (%s)\n",str,num);
93 return simple_strtol(num, NULL, 10);
94 }
96 static int blktap_name(blkif_t *blkif, char *buf)
97 {
98 char *devpath, *devname;
99 struct xenbus_device *dev = blkif->be->dev;
101 devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
102 if (IS_ERR(devpath))
103 return PTR_ERR(devpath);
105 if ((devname = strstr(devpath, "/dev/")) != NULL)
106 devname += strlen("/dev/");
107 else
108 devname = devpath;
110 snprintf(buf, TASK_COMM_LEN, "blktap.%d.%s", blkif->domid, devname);
111 kfree(devpath);
113 return 0;
114 }
116 /****************************************************************
117 * sysfs interface for I/O requests of blktap device
118 */
120 #define VBD_SHOW(name, format, args...) \
121 static ssize_t show_##name(struct device *_dev, \
122 struct device_attribute *attr, \
123 char *buf) \
124 { \
125 struct xenbus_device *dev = to_xenbus_device(_dev); \
126 struct backend_info *be = dev->dev.driver_data; \
127 \
128 return sprintf(buf, format, ##args); \
129 } \
130 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
132 VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
133 VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
134 VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
135 VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
136 VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
138 static struct attribute *tapstat_attrs[] = {
139 &dev_attr_oo_req.attr,
140 &dev_attr_rd_req.attr,
141 &dev_attr_wr_req.attr,
142 &dev_attr_rd_sect.attr,
143 &dev_attr_wr_sect.attr,
144 NULL
145 };
147 static struct attribute_group tapstat_group = {
148 .name = "statistics",
149 .attrs = tapstat_attrs,
150 };
152 int xentap_sysfs_addif(struct xenbus_device *dev)
153 {
154 int err;
155 struct backend_info *be = dev->dev.driver_data;
156 err = sysfs_create_group(&dev->dev.kobj, &tapstat_group);
157 if (!err)
158 be->group_added = 1;
159 return err;
160 }
162 void xentap_sysfs_delif(struct xenbus_device *dev)
163 {
164 struct backend_info *be = dev->dev.driver_data;
165 sysfs_remove_group(&dev->dev.kobj, &tapstat_group);
166 be->group_added = 0;
167 }
169 static int blktap_remove(struct xenbus_device *dev)
170 {
171 struct backend_info *be = dev->dev.driver_data;
173 if (be->group_added)
174 xentap_sysfs_delif(be->dev);
175 if (be->backend_watch.node) {
176 unregister_xenbus_watch(&be->backend_watch);
177 kfree(be->backend_watch.node);
178 be->backend_watch.node = NULL;
179 }
180 if (be->blkif) {
181 if (be->blkif->xenblkd)
182 kthread_stop(be->blkif->xenblkd);
183 signal_tapdisk(be->blkif->dev_num);
184 tap_blkif_free(be->blkif);
185 tap_blkif_kmem_cache_free(be->blkif);
186 be->blkif = NULL;
187 }
188 kfree(be);
189 dev->dev.driver_data = NULL;
190 return 0;
191 }
193 static void tap_update_blkif_status(blkif_t *blkif)
194 {
195 int err;
196 char name[TASK_COMM_LEN];
198 /* Not ready to connect? */
199 if(!blkif->irq || !blkif->sectors) {
200 return;
201 }
203 /* Already connected? */
204 if (blkif->be->dev->state == XenbusStateConnected)
205 return;
207 /* Attempt to connect: exit if we fail to. */
208 connect(blkif->be);
209 if (blkif->be->dev->state != XenbusStateConnected)
210 return;
212 err = blktap_name(blkif, name);
213 if (err) {
214 xenbus_dev_error(blkif->be->dev, err, "get blktap dev name");
215 return;
216 }
218 if (!blkif->be->group_added) {
219 err = xentap_sysfs_addif(blkif->be->dev);
220 if (err) {
221 xenbus_dev_fatal(blkif->be->dev, err,
222 "creating sysfs entries");
223 return;
224 }
225 }
227 blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif, name);
228 if (IS_ERR(blkif->xenblkd)) {
229 err = PTR_ERR(blkif->xenblkd);
230 blkif->xenblkd = NULL;
231 xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
232 WPRINTK("Error starting thread\n");
233 }
234 }
236 /**
237 * Entry point to this code when a new device is created. Allocate
238 * the basic structures, and watch the store waiting for the
239 * user-space program to tell us the physical device info. Switch to
240 * InitWait.
241 */
242 static int blktap_probe(struct xenbus_device *dev,
243 const struct xenbus_device_id *id)
244 {
245 int err;
246 struct backend_info *be = kzalloc(sizeof(struct backend_info),
247 GFP_KERNEL);
248 if (!be) {
249 xenbus_dev_fatal(dev, -ENOMEM,
250 "allocating backend structure");
251 return -ENOMEM;
252 }
254 be->dev = dev;
255 dev->dev.driver_data = be;
256 be->xenbus_id = get_id(dev->nodename);
258 be->blkif = tap_alloc_blkif(dev->otherend_id);
259 if (IS_ERR(be->blkif)) {
260 err = PTR_ERR(be->blkif);
261 be->blkif = NULL;
262 xenbus_dev_fatal(dev, err, "creating block interface");
263 goto fail;
264 }
266 /* setup back pointer */
267 be->blkif->be = be;
268 be->blkif->sectors = 0;
270 /* set a watch on disk info, waiting for userspace to update details*/
271 err = xenbus_watch_path2(dev, dev->nodename, "info",
272 &be->backend_watch, tap_backend_changed);
273 if (err)
274 goto fail;
276 err = xenbus_switch_state(dev, XenbusStateInitWait);
277 if (err)
278 goto fail;
279 return 0;
281 fail:
282 DPRINTK("blktap probe failed\n");
283 blktap_remove(dev);
284 return err;
285 }
288 /**
289 * Callback received when the user space code has placed the device
290 * information in xenstore.
291 */
292 static void tap_backend_changed(struct xenbus_watch *watch,
293 const char **vec, unsigned int len)
294 {
295 int err;
296 unsigned long info;
297 struct backend_info *be
298 = container_of(watch, struct backend_info, backend_watch);
299 struct xenbus_device *dev = be->dev;
301 /**
302 * Check to see whether userspace code has opened the image
303 * and written sector
304 * and disk info to xenstore
305 */
306 err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info,
307 NULL);
308 if (XENBUS_EXIST_ERR(err))
309 return;
310 if (err) {
311 xenbus_dev_error(dev, err, "getting info");
312 return;
313 }
315 DPRINTK("Userspace update on disk info, %lu\n",info);
317 err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu",
318 &be->blkif->sectors, NULL);
320 /* Associate tap dev with domid*/
321 be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id,
322 be->blkif);
323 DPRINTK("Thread started for domid [%d], connecting disk\n",
324 be->blkif->dev_num);
326 tap_update_blkif_status(be->blkif);
327 }
329 /**
330 * Callback received when the frontend's state changes.
331 */
332 static void tap_frontend_changed(struct xenbus_device *dev,
333 enum xenbus_state frontend_state)
334 {
335 struct backend_info *be = dev->dev.driver_data;
336 int err;
338 DPRINTK("\n");
340 switch (frontend_state) {
341 case XenbusStateInitialising:
342 if (dev->state == XenbusStateClosed) {
343 printk(KERN_INFO "%s: %s: prepare for reconnect\n",
344 __FUNCTION__, dev->nodename);
345 xenbus_switch_state(dev, XenbusStateInitWait);
346 }
347 break;
349 case XenbusStateInitialised:
350 case XenbusStateConnected:
351 /* Ensure we connect even when two watches fire in
352 close successsion and we miss the intermediate value
353 of frontend_state. */
354 if (dev->state == XenbusStateConnected)
355 break;
357 err = connect_ring(be);
358 if (err)
359 break;
360 tap_update_blkif_status(be->blkif);
361 break;
363 case XenbusStateClosing:
364 if (be->blkif->xenblkd) {
365 kthread_stop(be->blkif->xenblkd);
366 be->blkif->xenblkd = NULL;
367 }
368 tap_blkif_free(be->blkif);
369 xenbus_switch_state(dev, XenbusStateClosing);
370 break;
372 case XenbusStateClosed:
373 xenbus_switch_state(dev, XenbusStateClosed);
374 if (xenbus_dev_is_online(dev))
375 break;
376 /* fall through if not online */
377 case XenbusStateUnknown:
378 device_unregister(&dev->dev);
379 break;
381 default:
382 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
383 frontend_state);
384 break;
385 }
386 }
389 /**
390 * Switch to Connected state.
391 */
392 static void connect(struct backend_info *be)
393 {
394 int err;
396 struct xenbus_device *dev = be->dev;
398 err = xenbus_switch_state(dev, XenbusStateConnected);
399 if (err)
400 xenbus_dev_fatal(dev, err, "switching to Connected state",
401 dev->nodename);
403 return;
404 }
407 static int connect_ring(struct backend_info *be)
408 {
409 struct xenbus_device *dev = be->dev;
410 unsigned long ring_ref;
411 unsigned int evtchn;
412 char protocol[64];
413 int err;
415 DPRINTK("%s\n", dev->otherend);
417 err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
418 &ring_ref, "event-channel", "%u", &evtchn, NULL);
419 if (err) {
420 xenbus_dev_fatal(dev, err,
421 "reading %s/ring-ref and event-channel",
422 dev->otherend);
423 return err;
424 }
426 be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
427 err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
428 "%63s", protocol, NULL);
429 if (err)
430 strcpy(protocol, "unspecified, assuming native");
431 else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
432 be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
433 else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
434 be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
435 else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
436 be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
437 else {
438 xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
439 return -1;
440 }
441 printk(KERN_INFO
442 "blktap: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
443 ring_ref, evtchn, be->blkif->blk_protocol, protocol);
445 /* Map the shared frame, irq etc. */
446 err = tap_blkif_map(be->blkif, ring_ref, evtchn);
447 if (err) {
448 xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
449 ring_ref, evtchn);
450 return err;
451 }
453 return 0;
454 }
457 /* ** Driver Registration ** */
460 static const struct xenbus_device_id blktap_ids[] = {
461 { "tap" },
462 { "" }
463 };
466 static struct xenbus_driver blktap = {
467 .name = "tap",
468 .owner = THIS_MODULE,
469 .ids = blktap_ids,
470 .probe = blktap_probe,
471 .remove = blktap_remove,
472 .otherend_changed = tap_frontend_changed
473 };
476 void tap_blkif_xenbus_init(void)
477 {
478 xenbus_register_backend(&blktap);
479 }