direct-io.hg

view tools/ioemu/xenstore.c @ 15481:538c3d8aa4b1

Revert 15471:7ac7f147241405af83e7a9d748cf7b01279734fc

Block-device specifiers in ioemu can contain colons, so skipping
always past the first colon is not a good idea. Better solutions are
in the pipeline to solve the blktap issues.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Jul 06 15:01:20 2007 +0100 (2007-07-06)
parents 7ac7f1472414
children
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General
3 * Public License. See the file "COPYING" in the main directory of
4 * this archive for more details.
5 *
6 * Copyright (C) 2006 Christian Limpach
7 * Copyright (C) 2006 XenSource Ltd.
8 *
9 */
11 #include "vl.h"
12 #include "block_int.h"
13 #include <unistd.h>
14 #include <sys/ipc.h>
15 #include <sys/shm.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
20 static struct xs_handle *xsh = NULL;
21 static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS];
22 static QEMUTimer *insert_timer = NULL;
24 #define UWAIT_MAX (30*1000000) /* thirty seconds */
25 #define UWAIT (100000) /* 1/10th second */
27 static int pasprintf(char **buf, const char *fmt, ...)
28 {
29 va_list ap;
30 int ret = 0;
32 if (*buf)
33 free(*buf);
34 va_start(ap, fmt);
35 if (vasprintf(buf, fmt, ap) == -1) {
36 buf = NULL;
37 ret = -1;
38 }
39 va_end(ap);
40 return ret;
41 }
43 static void insert_media(void *opaque)
44 {
45 int i;
47 for (i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) {
48 if (media_filename[i] && bs_table[i]) {
49 do_change(bs_table[i]->device_name, media_filename[i]);
50 free(media_filename[i]);
51 media_filename[i] = NULL;
52 }
53 }
54 }
56 void xenstore_check_new_media_present(int timeout)
57 {
59 if (insert_timer == NULL)
60 insert_timer = qemu_new_timer(rt_clock, insert_media, NULL);
61 qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout);
62 }
64 static void waitForDevice(char *fn)
65 {
66 struct stat sbuf;
67 int status;
68 int uwait = UWAIT_MAX;
70 do {
71 status = stat(fn, &sbuf);
72 if (!status) break;
73 usleep(UWAIT);
74 uwait -= UWAIT;
75 } while (uwait > 0);
77 return;
78 }
80 void xenstore_parse_domain_config(int domid)
81 {
82 char **e = NULL;
83 char *buf = NULL, *path;
84 char *fpath = NULL, *bpath = NULL,
85 *dev = NULL, *params = NULL, *type = NULL;
86 int i, is_scsi;
87 unsigned int len, num, hd_index;
89 for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
90 media_filename[i] = NULL;
92 xsh = xs_daemon_open();
93 if (xsh == NULL) {
94 fprintf(logfile, "Could not contact xenstore for domain config\n");
95 return;
96 }
98 path = xs_get_domain_path(xsh, domid);
99 if (path == NULL) {
100 fprintf(logfile, "xs_get_domain_path() error\n");
101 goto out;
102 }
104 if (pasprintf(&buf, "%s/device/vbd", path) == -1)
105 goto out;
107 e = xs_directory(xsh, XBT_NULL, buf, &num);
108 if (e == NULL)
109 goto out;
111 for (i = 0; i < num; i++) {
112 /* read the backend path */
113 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
114 continue;
115 free(bpath);
116 bpath = xs_read(xsh, XBT_NULL, buf, &len);
117 if (bpath == NULL)
118 continue;
119 /* read the name of the device */
120 if (pasprintf(&buf, "%s/dev", bpath) == -1)
121 continue;
122 free(dev);
123 dev = xs_read(xsh, XBT_NULL, buf, &len);
124 if (dev == NULL)
125 continue;
126 is_scsi = !strncmp(dev, "sd", 2);
127 if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
128 continue;
129 hd_index = dev[2] - 'a';
130 if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
131 continue;
132 /* read the type of the device */
133 if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
134 continue;
135 free(type);
136 type = xs_read(xsh, XBT_NULL, buf, &len);
137 if (pasprintf(&buf, "%s/params", bpath) == -1)
138 continue;
139 free(params);
140 params = xs_read(xsh, XBT_NULL, buf, &len);
141 if (params == NULL)
142 continue;
143 /*
144 * check if device has a phantom vbd; the phantom is hooked
145 * to the frontend device (for ease of cleanup), so lookup
146 * the frontend device, and see if there is a phantom_vbd
147 * if there is, we will use resolution as the filename
148 */
149 if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
150 continue;
151 free(fpath);
152 fpath = xs_read(xsh, XBT_NULL, buf, &len);
153 if (fpath) {
154 if (pasprintf(&buf, "%s/dev", fpath) == -1)
155 continue;
156 free(params);
157 params = xs_read(xsh, XBT_NULL, buf , &len);
158 if (params) {
159 /*
160 * wait for device, on timeout silently fail because we will
161 * fail to open below
162 */
163 waitForDevice(params);
164 }
165 }
167 bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
168 /* check if it is a cdrom */
169 if (type && !strcmp(type, "cdrom")) {
170 bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
171 if (pasprintf(&buf, "%s/params", bpath) != -1)
172 xs_watch(xsh, buf, dev);
173 }
174 /* open device now if media present */
175 if (params[0]) {
176 if (bdrv_open(bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)],
177 params, 0 /* snapshot */) < 0)
178 fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
179 params);
180 }
181 }
183 /* Set a watch for log-dirty requests from the migration tools */
184 if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
185 xs_watch(xsh, buf, "logdirty");
186 fprintf(logfile, "Watching %s\n", buf);
187 }
190 out:
191 free(type);
192 free(params);
193 free(dev);
194 free(bpath);
195 free(buf);
196 free(path);
197 free(e);
198 return;
199 }
201 int xenstore_fd(void)
202 {
203 if (xsh)
204 return xs_fileno(xsh);
205 return -1;
206 }
208 unsigned long *logdirty_bitmap = NULL;
209 unsigned long logdirty_bitmap_size;
210 extern int vga_ram_size, bios_size;
212 void xenstore_process_logdirty_event(void)
213 {
214 char *act;
215 static char *active_path = NULL;
216 static char *next_active_path = NULL;
217 static char *seg = NULL;
218 unsigned int len;
219 int i;
221 fprintf(logfile, "Triggered log-dirty buffer switch\n");
223 if (!seg) {
224 char *path, *p, *key_ascii, key_terminated[17] = {0,};
225 key_t key;
226 int shmid;
228 /* Find and map the shared memory segment for log-dirty bitmaps */
229 if (!(path = xs_get_domain_path(xsh, domid))) {
230 fprintf(logfile, "Log-dirty: can't get domain path in store\n");
231 exit(1);
232 }
233 if (!(path = realloc(path, strlen(path)
234 + strlen("/logdirty/next-active") + 1))) {
235 fprintf(logfile, "Log-dirty: out of memory\n");
236 exit(1);
237 }
238 strcat(path, "/logdirty/");
239 p = path + strlen(path);
240 strcpy(p, "key");
242 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
243 if (!key_ascii) {
244 /* No key yet: wait for the next watch */
245 free(path);
246 return;
247 }
248 strncpy(key_terminated, key_ascii, 16);
249 free(key_ascii);
250 key = (key_t) strtoull(key_terminated, NULL, 16);
252 /* Figure out how bit the log-dirty bitmaps are */
253 logdirty_bitmap_size = xc_memory_op(xc_handle,
254 XENMEM_maximum_gpfn, &domid) + 1;
255 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
256 / HOST_LONG_BITS); /* longs */
257 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
259 /* Map the shared-memory segment */
260 if ((shmid = shmget(key,
261 2 * logdirty_bitmap_size,
262 S_IRUSR|S_IWUSR)) == -1
263 || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
264 fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
265 (unsigned long long) key, strerror(errno));
266 exit(1);
267 }
269 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
271 /* Double-check that the bitmaps are the size we expect */
272 if (logdirty_bitmap_size != *(uint32_t *)seg) {
273 fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
274 *(uint32_t *)seg, logdirty_bitmap_size);
275 return;
276 }
278 /* Remember the paths for the next-active and active entries */
279 strcpy(p, "active");
280 if (!(active_path = strdup(path))) {
281 fprintf(logfile, "Log-dirty: out of memory\n");
282 exit(1);
283 }
284 strcpy(p, "next-active");
285 if (!(next_active_path = strdup(path))) {
286 fprintf(logfile, "Log-dirty: out of memory\n");
287 exit(1);
288 }
289 free(path);
290 }
292 /* Read the required active buffer from the store */
293 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
294 if (!act) {
295 fprintf(logfile, "Log-dirty: can't read next-active\n");
296 exit(1);
297 }
299 /* Switch buffers */
300 i = act[0] - '0';
301 if (i != 0 && i != 1) {
302 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
303 exit(1);
304 }
305 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
307 /* Ack that we've switched */
308 xs_write(xsh, XBT_NULL, active_path, act, len);
309 free(act);
310 }
314 void xenstore_process_event(void *opaque)
315 {
316 char **vec, *image = NULL;
317 unsigned int len, num, hd_index;
319 vec = xs_read_watch(xsh, &num);
320 if (!vec)
321 return;
323 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
324 xenstore_process_logdirty_event();
325 goto out;
326 }
328 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
329 strlen(vec[XS_WATCH_TOKEN]) != 3)
330 goto out;
331 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
332 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
333 if (image == NULL || !strcmp(image, bs_table[hd_index]->filename))
334 goto out; /* gone or identical */
336 do_eject(0, vec[XS_WATCH_TOKEN]);
337 bs_table[hd_index]->filename[0] = 0;
338 if (media_filename[hd_index]) {
339 free(media_filename[hd_index]);
340 media_filename[hd_index] = NULL;
341 }
343 if (image[0]) {
344 media_filename[hd_index] = strdup(image);
345 xenstore_check_new_media_present(5000);
346 }
348 out:
349 free(image);
350 free(vec);
351 }
353 void xenstore_write_vncport(int display)
354 {
355 char *buf = NULL, *path;
356 char *portstr = NULL;
358 if (xsh == NULL)
359 return;
361 path = xs_get_domain_path(xsh, domid);
362 if (path == NULL) {
363 fprintf(logfile, "xs_get_domain_path() error\n");
364 goto out;
365 }
367 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
368 goto out;
370 if (pasprintf(&portstr, "%d", display) == -1)
371 goto out;
373 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
374 fprintf(logfile, "xs_write() vncport failed\n");
376 out:
377 free(portstr);
378 free(buf);
379 }
381 int xenstore_read_vncpasswd(int domid)
382 {
383 extern char vncpasswd[64];
384 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
385 unsigned int i, len, rc = 0;
387 if (xsh == NULL) {
388 return -1;
389 }
391 path = xs_get_domain_path(xsh, domid);
392 if (path == NULL) {
393 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
394 return -1;
395 }
397 pasprintf(&buf, "%s/vm", path);
398 uuid = xs_read(xsh, XBT_NULL, buf, &len);
399 if (uuid == NULL) {
400 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
401 free(path);
402 return -1;
403 }
405 pasprintf(&buf, "%s/vncpasswd", uuid);
406 passwd = xs_read(xsh, XBT_NULL, buf, &len);
407 if (passwd == NULL) {
408 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
409 free(uuid);
410 free(path);
411 return rc;
412 }
414 for (i=0; i<len && i<63; i++) {
415 vncpasswd[i] = passwd[i];
416 passwd[i] = '\0';
417 }
418 vncpasswd[len] = '\0';
419 pasprintf(&buf, "%s/vncpasswd", uuid);
420 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
421 fprintf(logfile, "xs_write() vncpasswd failed.\n");
422 rc = -1;
423 }
425 free(passwd);
426 free(uuid);
427 free(path);
429 return rc;
430 }
433 /*
434 * get all device instances of a certain type
435 */
436 char **xenstore_domain_get_devices(struct xs_handle *handle,
437 const char *devtype, unsigned int *num)
438 {
439 char *path;
440 char *buf = NULL;
441 char **e = NULL;
443 path = xs_get_domain_path(handle, domid);
444 if (path == NULL)
445 goto out;
447 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
448 goto out;
450 e = xs_directory(handle, XBT_NULL, buf, num);
452 out:
453 free(path);
454 free(buf);
455 return e;
456 }
458 /*
459 * Check whether a domain has devices of the given type
460 */
461 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
462 {
463 int rc = 0;
464 unsigned int num;
465 char **e = xenstore_domain_get_devices(handle, devtype, &num);
466 if (e)
467 rc = 1;
468 free(e);
469 return rc;
470 }
472 /*
473 * Function that creates a path to a variable of an instance of a
474 * certain device
475 */
476 static char *get_device_variable_path(const char *devtype, const char *inst,
477 const char *var)
478 {
479 char *buf = NULL;
480 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
481 devtype,
482 domid,
483 inst,
484 var) == -1) {
485 free(buf);
486 buf = NULL;
487 }
488 return buf;
489 }
491 char *xenstore_backend_read_variable(struct xs_handle *handle,
492 const char *devtype, const char *inst,
493 const char *var)
494 {
495 char *value = NULL;
496 char *buf = NULL;
497 unsigned int len;
499 buf = get_device_variable_path(devtype, inst, var);
500 if (NULL == buf)
501 goto out;
503 value = xs_read(handle, XBT_NULL, buf, &len);
505 free(buf);
507 out:
508 return value;
509 }
511 /*
512 Read the hotplug status variable from the backend given the type
513 of device and its instance.
514 */
515 char *xenstore_read_hotplug_status(struct xs_handle *handle,
516 const char *devtype, const char *inst)
517 {
518 return xenstore_backend_read_variable(handle, devtype, inst,
519 "hotplug-status");
520 }
522 /*
523 Subscribe to the hotplug status of a device given the type of device and
524 its instance.
525 In case an error occurrs, a negative number is returned.
526 */
527 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
528 const char *devtype,
529 const char *inst,
530 const char *token)
531 {
532 int rc = 0;
533 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
535 if (path == NULL)
536 return -1;
538 if (0 == xs_watch(handle, path, token))
539 rc = -2;
541 free(path);
543 return rc;
544 }
546 /*
547 * Unsubscribe from a subscription to the status of a hotplug variable of
548 * a device.
549 */
550 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
551 const char *devtype,
552 const char *inst,
553 const char *token)
554 {
555 int rc = 0;
556 char *path;
557 path = get_device_variable_path(devtype, inst, "hotplug-status");
558 if (path == NULL)
559 return -1;
561 if (0 == xs_unwatch(handle, path, token))
562 rc = -2;
564 free(path);
566 return rc;
567 }
569 char *xenstore_vm_read(int domid, char *key, int *len)
570 {
571 char *buf = NULL, *path = NULL, *value = NULL;
573 if (xsh == NULL)
574 goto out;
576 path = xs_get_domain_path(xsh, domid);
577 if (path == NULL) {
578 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
579 goto out;
580 }
582 pasprintf(&buf, "%s/vm", path);
583 free(path);
584 path = xs_read(xsh, XBT_NULL, buf, NULL);
585 if (path == NULL) {
586 fprintf(logfile, "xs_read(%s): read error\n", buf);
587 goto out;
588 }
590 pasprintf(&buf, "%s/%s", path, key);
591 value = xs_read(xsh, XBT_NULL, buf, len);
592 if (value == NULL) {
593 fprintf(logfile, "xs_read(%s): read error\n", buf);
594 goto out;
595 }
597 out:
598 free(path);
599 free(buf);
600 return value;
601 }
603 int xenstore_vm_write(int domid, char *key, char *value)
604 {
605 char *buf = NULL, *path = NULL;
606 int rc = -1;
608 if (xsh == NULL)
609 goto out;
611 path = xs_get_domain_path(xsh, domid);
612 if (path == NULL) {
613 fprintf(logfile, "xs_get_domain_path: error\n");
614 goto out;
615 }
617 pasprintf(&buf, "%s/vm", path);
618 free(path);
619 path = xs_read(xsh, XBT_NULL, buf, NULL);
620 if (path == NULL) {
621 fprintf(logfile, "xs_read(%s): read error\n", buf);
622 goto out;
623 }
625 pasprintf(&buf, "%s/%s", path, key);
626 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
627 if (rc) {
628 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
629 goto out;
630 }
632 out:
633 free(path);
634 free(buf);
635 return rc;
636 }