debuggers.hg

view tools/ioemu/xenstore.c @ 17010:90844659c458

Revert 16947:32b898768217027. Breaks HVM qcow-backed discs.
Sigend-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 04 13:42:53 2008 +0000 (2008-02-04)
parents 32b898768217
children a905c582a406
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 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, *drv = NULL;
86 int i, is_scsi, is_hdN = 0;
87 unsigned int len, num, hd_index;
88 BlockDriverState *bs;
90 for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
91 media_filename[i] = NULL;
93 xsh = xs_daemon_open();
94 if (xsh == NULL) {
95 fprintf(logfile, "Could not contact xenstore for domain config\n");
96 return;
97 }
99 path = xs_get_domain_path(xsh, domid);
100 if (path == NULL) {
101 fprintf(logfile, "xs_get_domain_path() error\n");
102 goto out;
103 }
105 if (pasprintf(&buf, "%s/device/vbd", path) == -1)
106 goto out;
108 e = xs_directory(xsh, XBT_NULL, buf, &num);
109 if (e == NULL)
110 goto out;
112 for (i = 0; i < num; i++) {
113 /* read the backend path */
114 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
115 continue;
116 free(bpath);
117 bpath = xs_read(xsh, XBT_NULL, buf, &len);
118 if (bpath == NULL)
119 continue;
120 /* read the name of the device */
121 if (pasprintf(&buf, "%s/dev", bpath) == -1)
122 continue;
123 free(dev);
124 dev = xs_read(xsh, XBT_NULL, buf, &len);
125 if (dev == NULL)
126 continue;
127 if (!strncmp(dev, "hd", 2)) {
128 is_hdN = 1;
129 break;
130 }
131 }
133 for (i = 0; i < num; i++) {
134 /* read the backend path */
135 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
136 continue;
137 free(bpath);
138 bpath = xs_read(xsh, XBT_NULL, buf, &len);
139 if (bpath == NULL)
140 continue;
141 /* read the name of the device */
142 if (pasprintf(&buf, "%s/dev", bpath) == -1)
143 continue;
144 free(dev);
145 dev = xs_read(xsh, XBT_NULL, buf, &len);
146 if (dev == NULL)
147 continue;
148 /* Change xvdN to look like hdN */
149 if (!is_hdN && !strncmp(dev, "xvd", 3)) {
150 fprintf(logfile, "Change xvd%c to look like hd%c\n",
151 dev[3], dev[3]);
152 memmove(dev, dev+1, strlen(dev));
153 dev[0] = 'h';
154 dev[1] = 'd';
155 }
156 is_scsi = !strncmp(dev, "sd", 2);
157 if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
158 continue;
159 hd_index = dev[2] - 'a';
160 if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
161 continue;
162 /* read the type of the device */
163 if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
164 continue;
165 free(type);
166 type = xs_read(xsh, XBT_NULL, buf, &len);
167 if (pasprintf(&buf, "%s/params", bpath) == -1)
168 continue;
169 free(params);
170 params = xs_read(xsh, XBT_NULL, buf, &len);
171 if (params == NULL)
172 continue;
173 /* read the name of the device */
174 if (pasprintf(&buf, "%s/type", bpath) == -1)
175 continue;
176 free(drv);
177 drv = xs_read(xsh, XBT_NULL, buf, &len);
178 if (drv == NULL)
179 continue;
180 /* Strip off blktap sub-type prefix aio: - QEMU can autodetect this */
181 if (!strcmp(drv, "tap") && params[0]) {
182 char *offset = strchr(params, ':');
183 if (!offset)
184 continue ;
185 memmove(params, offset+1, strlen(offset+1)+1 );
186 fprintf(logfile, "Strip off blktap sub-type prefix to %s\n", params);
187 }
189 /*
190 * check if device has a phantom vbd; the phantom is hooked
191 * to the frontend device (for ease of cleanup), so lookup
192 * the frontend device, and see if there is a phantom_vbd
193 * if there is, we will use resolution as the filename
194 */
195 if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
196 continue;
197 free(fpath);
198 fpath = xs_read(xsh, XBT_NULL, buf, &len);
199 if (fpath) {
200 if (pasprintf(&buf, "%s/dev", fpath) == -1)
201 continue;
202 free(params);
203 params = xs_read(xsh, XBT_NULL, buf , &len);
204 if (params) {
205 /*
206 * wait for device, on timeout silently fail because we will
207 * fail to open below
208 */
209 waitForDevice(params);
210 }
211 }
213 bs = bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
214 /* check if it is a cdrom */
215 if (type && !strcmp(type, "cdrom")) {
216 bdrv_set_type_hint(bs, BDRV_TYPE_CDROM);
217 if (pasprintf(&buf, "%s/params", bpath) != -1)
218 xs_watch(xsh, buf, dev);
219 }
221 /* open device now if media present */
222 if (params[0]) {
223 if (bdrv_open(bs, params, 0 /* snapshot */) < 0)
224 fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
225 params);
226 }
227 }
229 /* Set a watch for log-dirty requests from the migration tools */
230 if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
231 domid) != -1) {
232 xs_watch(xsh, buf, "logdirty");
233 fprintf(logfile, "Watching %s\n", buf);
234 }
236 /* Set a watch for suspend requests from the migration tools */
237 if (pasprintf(&buf,
238 "/local/domain/0/device-model/%u/command", domid) != -1) {
239 xs_watch(xsh, buf, "dm-command");
240 fprintf(logfile, "Watching %s\n", buf);
241 }
243 out:
244 free(type);
245 free(params);
246 free(dev);
247 free(bpath);
248 free(buf);
249 free(path);
250 free(e);
251 free(drv);
252 return;
253 }
255 int xenstore_fd(void)
256 {
257 if (xsh)
258 return xs_fileno(xsh);
259 return -1;
260 }
262 unsigned long *logdirty_bitmap = NULL;
263 unsigned long logdirty_bitmap_size;
264 extern int vga_ram_size, bios_size;
266 void xenstore_process_logdirty_event(void)
267 {
268 char *act;
269 static char *active_path = NULL;
270 static char *next_active_path = NULL;
271 static char *seg = NULL;
272 unsigned int len;
273 int i;
275 if (!seg) {
276 char *path = NULL, *key_ascii, key_terminated[17] = {0,};
277 key_t key;
278 int shmid;
280 /* Find and map the shared memory segment for log-dirty bitmaps */
281 if (pasprintf(&path,
282 "/local/domain/0/device-model/%u/logdirty/key",
283 domid) == -1) {
284 fprintf(logfile, "Log-dirty: out of memory\n");
285 exit(1);
286 }
288 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
289 free(path);
291 if (!key_ascii)
292 /* No key yet: wait for the next watch */
293 return;
295 strncpy(key_terminated, key_ascii, 16);
296 free(key_ascii);
297 key = (key_t) strtoull(key_terminated, NULL, 16);
299 /* Figure out how bit the log-dirty bitmaps are */
300 logdirty_bitmap_size = xc_memory_op(xc_handle,
301 XENMEM_maximum_gpfn, &domid) + 1;
302 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
303 / HOST_LONG_BITS); /* longs */
304 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
306 /* Map the shared-memory segment */
307 fprintf(logfile, "%s: key=%16.16llx size=%lu\n", __FUNCTION__,
308 (unsigned long long)key, logdirty_bitmap_size);
309 shmid = shmget(key, 2 * logdirty_bitmap_size, S_IRUSR|S_IWUSR);
310 if (shmid == -1) {
311 fprintf(logfile, "Log-dirty: shmget failed: segment %16.16llx "
312 "(%s)\n", (unsigned long long)key, strerror(errno));
313 exit(1);
314 }
316 seg = shmat(shmid, NULL, 0);
317 if (seg == (void *)-1) {
318 fprintf(logfile, "Log-dirty: shmat failed: segment %16.16llx "
319 "(%s)\n", (unsigned long long)key, strerror(errno));
320 exit(1);
321 }
323 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
325 /* Double-check that the bitmaps are the size we expect */
326 if (logdirty_bitmap_size != *(uint32_t *)seg) {
327 fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
328 *(uint32_t *)seg, logdirty_bitmap_size);
329 /* Stale key: wait for next watch */
330 shmdt(seg);
331 seg = NULL;
332 return;
333 }
335 /* Remember the paths for the next-active and active entries */
336 if (pasprintf(&active_path,
337 "/local/domain/0/device-model/%u/logdirty/active",
338 domid) == -1) {
339 fprintf(logfile, "Log-dirty: out of memory\n");
340 exit(1);
341 }
342 if (pasprintf(&next_active_path,
343 "/local/domain/0/device-model/%u/logdirty/next-active",
344 domid) == -1) {
345 fprintf(logfile, "Log-dirty: out of memory\n");
346 exit(1);
347 }
348 }
350 fprintf(logfile, "Triggered log-dirty buffer switch\n");
352 /* Read the required active buffer from the store */
353 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
354 if (!act) {
355 fprintf(logfile, "Log-dirty: can't read next-active\n");
356 exit(1);
357 }
359 /* Switch buffers */
360 i = act[0] - '0';
361 if (i != 0 && i != 1) {
362 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
363 exit(1);
364 }
365 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
367 /* Ack that we've switched */
368 xs_write(xsh, XBT_NULL, active_path, act, len);
369 free(act);
370 }
373 /* Accept state change commands from the control tools */
374 static void xenstore_process_dm_command_event(void)
375 {
376 char *path = NULL, *command = NULL;
377 unsigned int len;
378 extern int suspend_requested;
380 if (pasprintf(&path,
381 "/local/domain/0/device-model/%u/command", domid) == -1) {
382 fprintf(logfile, "out of memory reading dm command\n");
383 goto out;
384 }
385 command = xs_read(xsh, XBT_NULL, path, &len);
386 if (!command)
387 goto out;
389 if (!strncmp(command, "save", len)) {
390 fprintf(logfile, "dm-command: pause and save state\n");
391 suspend_requested = 1;
392 } else if (!strncmp(command, "continue", len)) {
393 fprintf(logfile, "dm-command: continue after state save\n");
394 suspend_requested = 0;
395 } else {
396 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
397 }
399 out:
400 free(path);
401 free(command);
402 }
404 void xenstore_record_dm_state(char *state)
405 {
406 char *path = NULL;
408 if (pasprintf(&path,
409 "/local/domain/0/device-model/%u/state", domid) == -1) {
410 fprintf(logfile, "out of memory recording dm state\n");
411 goto out;
412 }
413 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
414 fprintf(logfile, "error recording dm state\n");
416 out:
417 free(path);
418 }
420 void xenstore_process_event(void *opaque)
421 {
422 char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL;
423 unsigned int len, num, hd_index;
425 vec = xs_read_watch(xsh, &num);
426 if (!vec)
427 return;
429 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
430 xenstore_process_logdirty_event();
431 goto out;
432 }
434 if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
435 xenstore_process_dm_command_event();
436 goto out;
437 }
439 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
440 strlen(vec[XS_WATCH_TOKEN]) != 3)
441 goto out;
442 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
443 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
444 if (image == NULL)
445 goto out; /* gone */
447 /* Strip off blktap sub-type prefix */
448 bpath = strdup(vec[XS_WATCH_PATH]);
449 if (bpath == NULL)
450 goto out;
451 if ((offset = strrchr(bpath, '/')) != NULL)
452 *offset = '\0';
453 if (pasprintf(&buf, "%s/type", bpath) == -1)
454 goto out;
455 drv = xs_read(xsh, XBT_NULL, buf, &len);
456 if (drv && !strcmp(drv, "tap") && ((offset = strchr(image, ':')) != NULL))
457 memmove(image, offset+1, strlen(offset+1)+1);
459 if (!strcmp(image, bs_table[hd_index]->filename))
460 goto out; /* identical */
462 do_eject(0, vec[XS_WATCH_TOKEN]);
463 bs_table[hd_index]->filename[0] = 0;
464 if (media_filename[hd_index]) {
465 free(media_filename[hd_index]);
466 media_filename[hd_index] = NULL;
467 }
469 if (image[0]) {
470 media_filename[hd_index] = strdup(image);
471 xenstore_check_new_media_present(5000);
472 }
474 out:
475 free(drv);
476 free(buf);
477 free(bpath);
478 free(image);
479 free(vec);
480 }
482 void xenstore_write_vncport(int display)
483 {
484 char *buf = NULL, *path;
485 char *portstr = NULL;
487 if (xsh == NULL)
488 return;
490 path = xs_get_domain_path(xsh, domid);
491 if (path == NULL) {
492 fprintf(logfile, "xs_get_domain_path() error\n");
493 goto out;
494 }
496 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
497 goto out;
499 if (pasprintf(&portstr, "%d", display) == -1)
500 goto out;
502 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
503 fprintf(logfile, "xs_write() vncport failed\n");
505 out:
506 free(portstr);
507 free(buf);
508 }
510 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
511 {
512 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
513 unsigned int i, len;
515 pwbuf[0] = '\0';
517 if (xsh == NULL)
518 return;
520 path = xs_get_domain_path(xsh, domid);
521 if (path == NULL) {
522 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
523 return;
524 }
526 pasprintf(&buf, "%s/vm", path);
527 free(path);
528 uuid = xs_read(xsh, XBT_NULL, buf, &len);
529 if (uuid == NULL) {
530 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
531 free(buf);
532 return;
533 }
535 pasprintf(&buf, "%s/vncpasswd", uuid);
536 free(uuid);
537 passwd = xs_read(xsh, XBT_NULL, buf, &len);
538 if (passwd == NULL) {
539 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
540 free(buf);
541 return;
542 }
544 if (len >= pwbuflen)
545 {
546 fprintf(logfile, "xenstore_read_vncpasswd(): truncated password to avoid buffer overflow\n");
547 len = pwbuflen - 1;
548 }
550 for (i=0; i<len; i++)
551 pwbuf[i] = passwd[i];
552 pwbuf[len] = '\0';
553 passwd[0] = '\0';
554 if (xs_write(xsh, XBT_NULL, buf, passwd, 1) == 0)
555 fprintf(logfile, "xs_write() vncpasswd failed.\n");
557 free(passwd);
558 free(buf);
559 }
562 /*
563 * get all device instances of a certain type
564 */
565 char **xenstore_domain_get_devices(struct xs_handle *handle,
566 const char *devtype, unsigned int *num)
567 {
568 char *path;
569 char *buf = NULL;
570 char **e = NULL;
572 path = xs_get_domain_path(handle, domid);
573 if (path == NULL)
574 goto out;
576 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
577 goto out;
579 e = xs_directory(handle, XBT_NULL, buf, num);
581 out:
582 free(path);
583 free(buf);
584 return e;
585 }
587 /*
588 * Check whether a domain has devices of the given type
589 */
590 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
591 {
592 int rc = 0;
593 unsigned int num;
594 char **e = xenstore_domain_get_devices(handle, devtype, &num);
595 if (e)
596 rc = 1;
597 free(e);
598 return rc;
599 }
601 /*
602 * Function that creates a path to a variable of an instance of a
603 * certain device
604 */
605 static char *get_device_variable_path(const char *devtype, const char *inst,
606 const char *var)
607 {
608 char *buf = NULL;
609 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
610 devtype,
611 domid,
612 inst,
613 var) == -1) {
614 free(buf);
615 buf = NULL;
616 }
617 return buf;
618 }
620 char *xenstore_backend_read_variable(struct xs_handle *handle,
621 const char *devtype, const char *inst,
622 const char *var)
623 {
624 char *value = NULL;
625 char *buf = NULL;
626 unsigned int len;
628 buf = get_device_variable_path(devtype, inst, var);
629 if (NULL == buf)
630 goto out;
632 value = xs_read(handle, XBT_NULL, buf, &len);
634 free(buf);
636 out:
637 return value;
638 }
640 /*
641 Read the hotplug status variable from the backend given the type
642 of device and its instance.
643 */
644 char *xenstore_read_hotplug_status(struct xs_handle *handle,
645 const char *devtype, const char *inst)
646 {
647 return xenstore_backend_read_variable(handle, devtype, inst,
648 "hotplug-status");
649 }
651 /*
652 Subscribe to the hotplug status of a device given the type of device and
653 its instance.
654 In case an error occurrs, a negative number is returned.
655 */
656 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
657 const char *devtype,
658 const char *inst,
659 const char *token)
660 {
661 int rc = 0;
662 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
664 if (path == NULL)
665 return -1;
667 if (0 == xs_watch(handle, path, token))
668 rc = -2;
670 free(path);
672 return rc;
673 }
675 /*
676 * Unsubscribe from a subscription to the status of a hotplug variable of
677 * a device.
678 */
679 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
680 const char *devtype,
681 const char *inst,
682 const char *token)
683 {
684 int rc = 0;
685 char *path;
686 path = get_device_variable_path(devtype, inst, "hotplug-status");
687 if (path == NULL)
688 return -1;
690 if (0 == xs_unwatch(handle, path, token))
691 rc = -2;
693 free(path);
695 return rc;
696 }
698 char *xenstore_vm_read(int domid, char *key, unsigned int *len)
699 {
700 char *buf = NULL, *path = NULL, *value = NULL;
702 if (xsh == NULL)
703 goto out;
705 path = xs_get_domain_path(xsh, domid);
706 if (path == NULL) {
707 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
708 goto out;
709 }
711 pasprintf(&buf, "%s/vm", path);
712 free(path);
713 path = xs_read(xsh, XBT_NULL, buf, NULL);
714 if (path == NULL) {
715 fprintf(logfile, "xs_read(%s): read error\n", buf);
716 goto out;
717 }
719 pasprintf(&buf, "%s/%s", path, key);
720 value = xs_read(xsh, XBT_NULL, buf, len);
721 if (value == NULL) {
722 fprintf(logfile, "xs_read(%s): read error\n", buf);
723 goto out;
724 }
726 out:
727 free(path);
728 free(buf);
729 return value;
730 }
732 int xenstore_vm_write(int domid, char *key, char *value)
733 {
734 char *buf = NULL, *path = NULL;
735 int rc = -1;
737 if (xsh == NULL)
738 goto out;
740 path = xs_get_domain_path(xsh, domid);
741 if (path == NULL) {
742 fprintf(logfile, "xs_get_domain_path: error\n");
743 goto out;
744 }
746 pasprintf(&buf, "%s/vm", path);
747 free(path);
748 path = xs_read(xsh, XBT_NULL, buf, NULL);
749 if (path == NULL) {
750 fprintf(logfile, "xs_read(%s): read error\n", buf);
751 goto out;
752 }
754 pasprintf(&buf, "%s/%s", path, key);
755 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
756 if (rc == 0) {
757 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
758 goto out;
759 }
761 out:
762 free(path);
763 free(buf);
764 return rc;
765 }