debuggers.hg

view tools/blktap/lib/xenbus.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /*
2 * xenbus.c
3 *
4 * xenbus interface to the blocktap.
5 *
6 * this handles the top-half of integration with block devices through the
7 * store -- the tap driver negotiates the device channel etc, while the
8 * userland tap client needs to sort out the disk parameters etc.
9 *
10 * (c) 2005 Andrew Warfield and Julian Chesterfield
11 *
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License version 2
15 * as published by the Free Software Foundation; or, when distributed
16 * separately from the Linux kernel or incorporated into other
17 * software packages, subject to the following license:
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this source file (the "Software"), to deal in the Software without
21 * restriction, including without limitation the rights to use, copy, modify,
22 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
23 * and to permit persons to whom the Software is furnished to do so, subject to
24 * the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
35 * IN THE SOFTWARE.
36 */
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <err.h>
42 #include <stdarg.h>
43 #include <errno.h>
44 #include <xs.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <poll.h>
49 #include <time.h>
50 #include <sys/time.h>
51 #include "blktaplib.h"
52 #include "list.h"
53 #include "xs_api.h"
55 #if 0
56 #define DPRINTF(_f, _a...) printf ( _f , ## _a )
57 #else
58 #define DPRINTF(_f, _a...) ((void)0)
59 #endif
61 struct backend_info
62 {
63 /* our communications channel */
64 blkif_t *blkif;
66 long int frontend_id;
67 long int pdev;
68 long int readonly;
70 char *backpath;
71 char *frontpath;
73 struct list_head list;
74 };
76 static LIST_HEAD(belist);
78 static int strsep_len(const char *str, char c, unsigned int len)
79 {
80 unsigned int i;
82 for (i = 0; str[i]; i++)
83 if (str[i] == c) {
84 if (len == 0)
85 return i;
86 len--;
87 }
88 return (len == 0) ? i : -ERANGE;
89 }
91 static int get_be_id(const char *str)
92 {
93 int len,end;
94 const char *ptr;
95 char *tptr, num[10];
97 len = strsep_len(str, '/', 6);
98 end = strlen(str);
99 if( (len < 0) || (end < 0) ) return -1;
101 ptr = str + len + 1;
102 strncpy(num, ptr, end - len);
103 tptr = num + (end - (len + 1));
104 *tptr = '\0';
106 return atoi(num);
107 }
109 static struct backend_info *be_lookup_be(const char *bepath)
110 {
111 struct backend_info *be;
113 list_for_each_entry(be, &belist, list)
114 if (strcmp(bepath, be->backpath) == 0)
115 return be;
116 return (struct backend_info *)NULL;
117 }
119 static int be_exists_be(const char *bepath)
120 {
121 return (be_lookup_be(bepath) != NULL);
122 }
124 static struct backend_info *be_lookup_fe(const char *fepath)
125 {
126 struct backend_info *be;
128 list_for_each_entry(be, &belist, list)
129 if (strcmp(fepath, be->frontpath) == 0)
130 return be;
131 return (struct backend_info *)NULL;
132 }
134 static int backend_remove(struct xs_handle *h, struct backend_info *be)
135 {
136 /* Unhook from be list. */
137 list_del(&be->list);
139 /* Free everything else. */
140 if (be->blkif) {
141 DPRINTF("Freeing blkif dev [%d]\n",be->blkif->devnum);
142 free_blkif(be->blkif);
143 }
144 if (be->frontpath)
145 free(be->frontpath);
146 if (be->backpath)
147 free(be->backpath);
148 free(be);
149 return 0;
150 }
152 static void ueblktap_setup(struct xs_handle *h, char *bepath)
153 {
154 struct backend_info *be;
155 char *path = NULL, *p,*dev;
156 int len, er, deverr;
157 long int pdev = 0, handle;
158 blkif_info_t *blk;
160 be = be_lookup_be(bepath);
161 if (be == NULL)
162 {
163 DPRINTF("ERROR: backend changed called for nonexistent "
164 "backend! (%s)\n", bepath);
165 goto fail;
166 }
168 deverr = xs_gather(h, bepath, "physical-device", "%li", &pdev, NULL);
169 if (!deverr) {
170 DPRINTF("pdev set to %ld\n",pdev);
171 if (be->pdev && be->pdev != pdev) {
172 DPRINTF("changing physical-device not supported");
173 goto fail;
174 }
175 be->pdev = pdev;
176 }
178 /* Check to see if device is to be opened read-only. */
179 deverr = xs_gather(h, bepath, "mode", NULL, &path, NULL);
180 if (deverr) {
181 DPRINTF("ERROR: could not find read/write mode\n");
182 goto fail;
183 } else if (path[0] == 'r')
184 be->readonly = 1;
186 if (be->blkif == NULL) {
187 /* Front end dir is a number, which is used as the handle. */
188 p = strrchr(be->frontpath, '/') + 1;
189 handle = strtoul(p, NULL, 0);
191 be->blkif = alloc_blkif(be->frontend_id);
192 if (be->blkif == NULL)
193 goto fail;
195 be->blkif->be_id = get_be_id(bepath);
197 /* Insert device specific info, */
198 blk = malloc(sizeof(blkif_info_t));
199 if (!blk) {
200 DPRINTF("Out of memory - blkif_info_t\n");
201 goto fail;
202 }
203 er = xs_gather(h, bepath, "params", NULL, &blk->params, NULL);
204 if (er)
205 goto fail;
206 be->blkif->info = blk;
208 if (deverr) {
209 /*Dev number was not available, try to set manually*/
210 pdev = convert_dev_name_to_num(blk->params);
211 be->pdev = pdev;
212 }
214 er = blkif_init(be->blkif, handle, be->pdev, be->readonly);
215 if (er != 0) {
216 DPRINTF("Unable to open device %s\n",blk->params);
217 goto fail;
218 }
220 DPRINTF("[BECHG]: ADDED A NEW BLKIF (%s)\n", bepath);
221 }
223 /* Supply the information about the device to xenstore */
224 er = xs_printf(h, be->backpath, "sectors", "%llu",
225 be->blkif->ops->get_size(be->blkif));
227 if (er == 0) {
228 DPRINTF("ERROR: Failed writing sectors");
229 goto fail;
230 }
232 er = xs_printf(h, be->backpath, "sector-size", "%lu",
233 be->blkif->ops->get_secsize(be->blkif));
235 if (er == 0) {
236 DPRINTF("ERROR: Failed writing sector-size");
237 goto fail;
238 }
240 er = xs_printf(h, be->backpath, "info", "%u",
241 be->blkif->ops->get_info(be->blkif));
243 if (er == 0) {
244 DPRINTF("ERROR: Failed writing info");
245 goto fail;
246 }
248 be->blkif->state = CONNECTED;
249 DPRINTF("[SETUP] Complete\n\n");
250 goto close;
252 fail:
253 if ( (be != NULL) && (be->blkif != NULL) )
254 backend_remove(h, be);
255 close:
256 if (path)
257 free(path);
258 return;
259 }
261 /**
262 * Xenstore watch callback entry point. This code replaces the hotplug scripts,
263 * and as soon as the xenstore backend driver entries are created, this script
264 * gets called.
265 */
266 static void ueblktap_probe(struct xs_handle *h, struct xenbus_watch *w,
267 const char *bepath_im)
268 {
269 struct backend_info *be = NULL;
270 char *frontend = NULL, *bepath = NULL, *p;
271 int er, len;
272 blkif_t *blkif;
275 bepath = strdup(bepath_im);
277 if (!bepath) {
278 DPRINTF("No path\n");
279 return;
280 }
282 /*
283 *asserts that xenstore structure is always 7 levels deep
284 *e.g. /local/domain/0/backend/vbd/1/2049
285 */
286 len = strsep_len(bepath, '/', 7);
287 if (len < 0)
288 goto free_be;
289 bepath[len] = '\0';
291 be = malloc(sizeof(*be));
292 if (!be) {
293 DPRINTF("ERROR: allocating backend structure\n");
294 goto free_be;
295 }
296 memset(be, 0, sizeof(*be));
297 frontend = NULL;
299 er = xs_gather(h, bepath,
300 "frontend-id", "%li", &be->frontend_id,
301 "frontend", NULL, &frontend,
302 NULL);
304 if (er) {
305 /*
306 *Unable to find frontend entries,
307 *bus-id is no longer valid
308 */
309 DPRINTF("ERROR: Frontend-id check failed, removing backend: "
310 "[%s]\n",bepath);
312 /**
313 * BE info should already exist,
314 * free new mem and find old entry
315 */
316 free(be);
317 be = be_lookup_be(bepath);
318 if ( (be != NULL) && (be->blkif != NULL) )
319 backend_remove(h, be);
320 else goto free_be;
321 if (bepath)
322 free(bepath);
323 return;
324 }
326 /* Are we already tracking this device? */
327 if (be_exists_be(bepath))
328 goto free_be;
330 be->backpath = bepath;
331 be->frontpath = frontend;
333 list_add(&be->list, &belist);
335 DPRINTF("[PROBE]\tADDED NEW DEVICE (%s)\n", bepath);
336 DPRINTF("\tFRONTEND (%s),(%ld)\n", frontend,be->frontend_id);
338 ueblktap_setup(h, bepath);
339 return;
341 free_be:
342 if (frontend)
343 free(frontend);
344 if (bepath)
345 free(bepath);
346 if (be)
347 free(be);
348 }
350 /**
351 *We set a general watch on the backend vbd directory
352 *ueblktap_probe is called for every update
353 *Our job is to monitor for new entries. As they
354 *are created, we initalise the state and attach a disk.
355 */
357 int add_blockdevice_probe_watch(struct xs_handle *h, const char *domid)
358 {
359 char *path;
360 struct xenbus_watch *vbd_watch;
362 if (asprintf(&path, "/local/domain/%s/backend/tap", domid) == -1)
363 return -ENOMEM;
365 vbd_watch = (struct xenbus_watch *)malloc(sizeof(struct xenbus_watch));
366 if (!vbd_watch) {
367 DPRINTF("ERROR: unable to malloc vbd_watch [%s]\n", path);
368 return -EINVAL;
369 }
370 vbd_watch->node = path;
371 vbd_watch->callback = ueblktap_probe;
372 if (register_xenbus_watch(h, vbd_watch) != 0) {
373 DPRINTF("ERROR: adding vbd probe watch %s\n", path);
374 return -EINVAL;
375 }
376 return 0;
377 }
379 /* Asynch callback to check for /local/domain/<DOMID>/name */
380 void check_dom(struct xs_handle *h, struct xenbus_watch *w,
381 const char *bepath_im)
382 {
383 char *domid;
385 domid = get_dom_domid(h);
386 if (domid == NULL)
387 return;
389 add_blockdevice_probe_watch(h, domid);
390 free(domid);
391 unregister_xenbus_watch(h, w);
392 }
394 /* We must wait for xend to register /local/domain/<DOMID> */
395 int watch_for_domid(struct xs_handle *h)
396 {
397 struct xenbus_watch *domid_watch;
398 char *path = NULL;
400 if (asprintf(&path, "/local/domain") == -1)
401 return -ENOMEM;
403 domid_watch = malloc(sizeof(struct xenbus_watch));
404 if (domid_watch == NULL) {
405 DPRINTF("ERROR: unable to malloc domid_watch [%s]\n", path);
406 return -EINVAL;
407 }
409 domid_watch->node = path;
410 domid_watch->callback = check_dom;
412 if (register_xenbus_watch(h, domid_watch) != 0) {
413 DPRINTF("ERROR: adding vbd probe watch %s\n", path);
414 return -EINVAL;
415 }
417 DPRINTF("Set async watch for /local/domain\n");
419 return 0;
420 }
422 int setup_probe_watch(struct xs_handle *h)
423 {
424 char *domid;
425 int ret;
427 domid = get_dom_domid(h);
428 if (domid == NULL)
429 return watch_for_domid(h);
431 ret = add_blockdevice_probe_watch(h, domid);
432 free(domid);
433 return ret;
434 }