source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 11.9 KB
Line 
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 */
36
37#include <stdarg.h>
38#include <linux/module.h>
39#include <linux/kthread.h>
40#include <xen/xenbus.h>
41#include "common.h"
42
43
44struct 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};
52
53
54static void connect(struct backend_info *);
55static int connect_ring(struct backend_info *);
56static int blktap_remove(struct xenbus_device *dev);
57static int blktap_probe(struct xenbus_device *dev,
58                         const struct xenbus_device_id *id);
59static void tap_backend_changed(struct xenbus_watch *, const char **,
60                            unsigned int);
61static void tap_frontend_changed(struct xenbus_device *dev,
62                             enum xenbus_state frontend_state);
63
64static int strsep_len(const char *str, char c, unsigned int len)
65{
66        unsigned int i;
67
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}
76
77static long get_id(const char *str)
78{
79        int len,end;
80        const char *ptr;
81        char *tptr, num[10];
82       
83        len = strsep_len(str, '/', 2);
84        end = strlen(str);
85        if ( (len < 0) || (end < 0) ) return -1;
86       
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);
92       
93        return simple_strtol(num, NULL, 10);
94}                               
95
96static int blktap_name(blkif_t *blkif, char *buf)
97{
98        char *devpath, *devname;
99        struct xenbus_device *dev = blkif->be->dev;
100
101        devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
102        if (IS_ERR(devpath)) 
103                return PTR_ERR(devpath);
104       
105        if ((devname = strstr(devpath, "/dev/")) != NULL)
106                devname += strlen("/dev/");
107        else
108                devname  = devpath;
109
110        snprintf(buf, TASK_COMM_LEN, "blktap.%d.%s", blkif->domid, devname);
111        kfree(devpath);
112       
113        return 0;
114}
115
116/****************************************************************
117 *  sysfs interface for VBD I/O requests
118 */
119
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        DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
131
132VBD_SHOW(tap_oo_req,  "%d\n", be->blkif->st_oo_req);
133VBD_SHOW(tap_rd_req,  "%d\n", be->blkif->st_rd_req);
134VBD_SHOW(tap_wr_req,  "%d\n", be->blkif->st_wr_req);
135VBD_SHOW(tap_rd_sect, "%d\n", be->blkif->st_rd_sect);
136VBD_SHOW(tap_wr_sect, "%d\n", be->blkif->st_wr_sect);
137
138static struct attribute *tapstat_attrs[] = {
139        &dev_attr_tap_oo_req.attr,
140        &dev_attr_tap_rd_req.attr,
141        &dev_attr_tap_wr_req.attr,
142        &dev_attr_tap_rd_sect.attr,
143        &dev_attr_tap_wr_sect.attr,
144        NULL
145};
146
147static struct attribute_group tapstat_group = {
148        .name = "statistics",
149        .attrs = tapstat_attrs,
150};
151
152int 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}
161
162void xentap_sysfs_delif(struct xenbus_device *dev)
163{
164        sysfs_remove_group(&dev->dev.kobj, &tapstat_group);
165}
166
167static int blktap_remove(struct xenbus_device *dev)
168{
169        struct backend_info *be = dev->dev.driver_data;
170
171        if (be->backend_watch.node) {
172                unregister_xenbus_watch(&be->backend_watch);
173                kfree(be->backend_watch.node);
174                be->backend_watch.node = NULL;
175        }
176        if (be->blkif) {
177                if (be->blkif->xenblkd)
178                        kthread_stop(be->blkif->xenblkd);
179                signal_tapdisk(be->blkif->dev_num);
180                tap_blkif_free(be->blkif);
181                be->blkif = NULL;
182        }
183        if (be->group_added)
184                xentap_sysfs_delif(be->dev);
185        kfree(be);
186        dev->dev.driver_data = NULL;
187        return 0;
188}
189
190static void tap_update_blkif_status(blkif_t *blkif)
191{ 
192        int err;
193        char name[TASK_COMM_LEN];
194
195        /* Not ready to connect? */
196        if(!blkif->irq || !blkif->sectors) {
197                return;
198        } 
199
200        /* Already connected? */
201        if (blkif->be->dev->state == XenbusStateConnected)
202                return;
203
204        /* Attempt to connect: exit if we fail to. */
205        connect(blkif->be);
206        if (blkif->be->dev->state != XenbusStateConnected)
207                return;
208
209        err = blktap_name(blkif, name);
210        if (err) {
211                xenbus_dev_error(blkif->be->dev, err, "get blktap dev name");
212                return;
213        }
214
215        err = xentap_sysfs_addif(blkif->be->dev);
216        if (err) {
217                xenbus_dev_fatal(blkif->be->dev, err, 
218                                 "creating sysfs entries");
219                return;
220        }
221
222        blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif, name);
223        if (IS_ERR(blkif->xenblkd)) {
224                err = PTR_ERR(blkif->xenblkd);
225                blkif->xenblkd = NULL;
226                xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
227                WPRINTK("Error starting thread\n");
228        }
229}
230
231/**
232 * Entry point to this code when a new device is created.  Allocate
233 * the basic structures, and watch the store waiting for the
234 * user-space program to tell us the physical device info.  Switch to
235 * InitWait.
236 */
237static int blktap_probe(struct xenbus_device *dev,
238                         const struct xenbus_device_id *id)
239{
240        int err;
241        struct backend_info *be = kzalloc(sizeof(struct backend_info),
242                                          GFP_KERNEL);
243        if (!be) {
244                xenbus_dev_fatal(dev, -ENOMEM,
245                                 "allocating backend structure");
246                return -ENOMEM;
247        }
248
249        be->dev = dev;
250        dev->dev.driver_data = be;
251        be->xenbus_id = get_id(dev->nodename);
252
253        be->blkif = tap_alloc_blkif(dev->otherend_id);
254        if (IS_ERR(be->blkif)) {
255                err = PTR_ERR(be->blkif);
256                be->blkif = NULL;
257                xenbus_dev_fatal(dev, err, "creating block interface");
258                goto fail;
259        }
260
261        /* setup back pointer */
262        be->blkif->be = be;
263        be->blkif->sectors = 0;
264
265        /* set a watch on disk info, waiting for userspace to update details*/
266        err = xenbus_watch_path2(dev, dev->nodename, "info",
267                                 &be->backend_watch, tap_backend_changed);
268        if (err)
269                goto fail;
270       
271        err = xenbus_switch_state(dev, XenbusStateInitWait);
272        if (err)
273                goto fail;
274        return 0;
275
276fail:
277        DPRINTK("blktap probe failed\n");
278        blktap_remove(dev);
279        return err;
280}
281
282
283/**
284 * Callback received when the user space code has placed the device
285 * information in xenstore.
286 */
287static void tap_backend_changed(struct xenbus_watch *watch,
288                            const char **vec, unsigned int len)
289{
290        int err;
291        unsigned long info;
292        struct backend_info *be
293                = container_of(watch, struct backend_info, backend_watch);
294        struct xenbus_device *dev = be->dev;
295       
296        /**
297         * Check to see whether userspace code has opened the image
298         * and written sector
299         * and disk info to xenstore
300         */
301        err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, 
302                            NULL);
303        if (XENBUS_EXIST_ERR(err))
304                return;
305        if (err) {
306                xenbus_dev_error(dev, err, "getting info");
307                return;
308        }
309
310        DPRINTK("Userspace update on disk info, %lu\n",info);
311
312        err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", 
313                            &be->blkif->sectors, NULL);
314
315        /* Associate tap dev with domid*/
316        be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, 
317                                          be->blkif);
318        DPRINTK("Thread started for domid [%d], connecting disk\n", 
319                be->blkif->dev_num);
320
321        tap_update_blkif_status(be->blkif);
322}
323
324/**
325 * Callback received when the frontend's state changes.
326 */
327static void tap_frontend_changed(struct xenbus_device *dev,
328                             enum xenbus_state frontend_state)
329{
330        struct backend_info *be = dev->dev.driver_data;
331        int err;
332
333        DPRINTK("\n");
334
335        switch (frontend_state) {
336        case XenbusStateInitialising:
337                if (dev->state == XenbusStateClosed) {
338                        printk(KERN_INFO "%s: %s: prepare for reconnect\n",
339                               __FUNCTION__, dev->nodename);
340                        xenbus_switch_state(dev, XenbusStateInitWait);
341                }
342                break;
343
344        case XenbusStateInitialised:
345        case XenbusStateConnected:
346                /* Ensure we connect even when two watches fire in
347                   close successsion and we miss the intermediate value
348                   of frontend_state. */
349                if (dev->state == XenbusStateConnected)
350                        break;
351
352                err = connect_ring(be);
353                if (err)
354                        break;
355                tap_update_blkif_status(be->blkif);
356                break;
357
358        case XenbusStateClosing:
359                if (be->blkif->xenblkd) {
360                        kthread_stop(be->blkif->xenblkd);
361                        be->blkif->xenblkd = NULL;
362                }
363                xenbus_switch_state(dev, XenbusStateClosing);
364                break;
365
366        case XenbusStateClosed:
367                xenbus_switch_state(dev, XenbusStateClosed);
368                if (xenbus_dev_is_online(dev))
369                        break;
370                /* fall through if not online */
371        case XenbusStateUnknown:
372                device_unregister(&dev->dev);
373                break;
374
375        default:
376                xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
377                                 frontend_state);
378                break;
379        }
380}
381
382
383/**
384 * Switch to Connected state.
385 */
386static void connect(struct backend_info *be)
387{
388        int err;
389
390        struct xenbus_device *dev = be->dev;
391
392        err = xenbus_switch_state(dev, XenbusStateConnected);
393        if (err)
394                xenbus_dev_fatal(dev, err, "switching to Connected state",
395                                 dev->nodename);
396
397        return;
398}
399
400
401static int connect_ring(struct backend_info *be)
402{
403        struct xenbus_device *dev = be->dev;
404        unsigned long ring_ref;
405        unsigned int evtchn;
406        char protocol[64];
407        int err;
408
409        DPRINTK("%s\n", dev->otherend);
410
411        err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", 
412                            &ring_ref, "event-channel", "%u", &evtchn, NULL);
413        if (err) {
414                xenbus_dev_fatal(dev, err,
415                                 "reading %s/ring-ref and event-channel",
416                                 dev->otherend);
417                return err;
418        }
419
420        be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
421        err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
422                            "%63s", protocol, NULL);
423        if (err)
424                strcpy(protocol, "unspecified, assuming native");
425        else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
426                be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
427        else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
428                be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
429        else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
430                be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
431        else {
432                xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
433                return -1;
434        }
435        printk(KERN_INFO
436               "blktap: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
437               ring_ref, evtchn, be->blkif->blk_protocol, protocol);
438
439        /* Map the shared frame, irq etc. */
440        err = tap_blkif_map(be->blkif, ring_ref, evtchn);
441        if (err) {
442                xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
443                                 ring_ref, evtchn);
444                return err;
445        } 
446
447        return 0;
448}
449
450
451/* ** Driver Registration ** */
452
453
454static struct xenbus_device_id blktap_ids[] = {
455        { "tap" },
456        { "" }
457};
458
459
460static struct xenbus_driver blktap = {
461        .name = "tap",
462        .owner = THIS_MODULE,
463        .ids = blktap_ids,
464        .probe = blktap_probe,
465        .remove = blktap_remove,
466        .otherend_changed = tap_frontend_changed
467};
468
469
470void tap_blkif_xenbus_init(void)
471{
472        xenbus_register_backend(&blktap);
473}
Note: See TracBrowser for help on using the repository browser.