ia64/xen-unstable

view tools/ioemu/xenstore.c @ 16240:e4cd41c5c4e8

hvm: In xenstore_process_logdirty_event(), if a stale shared memory
key is encountered reset 'seg' to NULL so the shared memory
initialization can be retried later.

Signed-off-by: Ben Guthro <bguthro@virtualron.com>
Signed-off-by: Robert Phillips <rphillips@virtualiron.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Thu Oct 25 15:01:59 2007 +0100 (2007-10-25)
parents b34ba3bcab0b
children 01d45050a808
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;
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 if (!strncmp(dev, "hd", 2)) {
127 is_hdN = 1;
128 break;
129 }
130 }
132 for (i = 0; i < num; i++) {
133 /* read the backend path */
134 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
135 continue;
136 free(bpath);
137 bpath = xs_read(xsh, XBT_NULL, buf, &len);
138 if (bpath == NULL)
139 continue;
140 /* read the name of the device */
141 if (pasprintf(&buf, "%s/dev", bpath) == -1)
142 continue;
143 free(dev);
144 dev = xs_read(xsh, XBT_NULL, buf, &len);
145 if (dev == NULL)
146 continue;
147 /* Change xvdN to look like hdN */
148 if (!is_hdN && !strncmp(dev, "xvd", 3)) {
149 fprintf(logfile, "Change xvd%c to look like hd%c\n",
150 dev[3], dev[3]);
151 memmove(dev, dev+1, strlen(dev));
152 dev[0] = 'h';
153 dev[1] = 'd';
154 }
155 is_scsi = !strncmp(dev, "sd", 2);
156 if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
157 continue;
158 hd_index = dev[2] - 'a';
159 if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
160 continue;
161 /* read the type of the device */
162 if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
163 continue;
164 free(type);
165 type = xs_read(xsh, XBT_NULL, buf, &len);
166 if (pasprintf(&buf, "%s/params", bpath) == -1)
167 continue;
168 free(params);
169 params = xs_read(xsh, XBT_NULL, buf, &len);
170 if (params == NULL)
171 continue;
172 /* read the name of the device */
173 if (pasprintf(&buf, "%s/type", bpath) == -1)
174 continue;
175 free(drv);
176 drv = xs_read(xsh, XBT_NULL, buf, &len);
177 if (drv == NULL)
178 continue;
179 /* Strip off blktap sub-type prefix aio: - QEMU can autodetect this */
180 if (!strcmp(drv, "tap") && params[0]) {
181 char *offset = strchr(params, ':');
182 if (!offset)
183 continue ;
184 memmove(params, offset+1, strlen(offset+1)+1 );
185 fprintf(logfile, "Strip off blktap sub-type prefix to %s\n", params);
186 }
188 /*
189 * check if device has a phantom vbd; the phantom is hooked
190 * to the frontend device (for ease of cleanup), so lookup
191 * the frontend device, and see if there is a phantom_vbd
192 * if there is, we will use resolution as the filename
193 */
194 if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
195 continue;
196 free(fpath);
197 fpath = xs_read(xsh, XBT_NULL, buf, &len);
198 if (fpath) {
199 if (pasprintf(&buf, "%s/dev", fpath) == -1)
200 continue;
201 free(params);
202 params = xs_read(xsh, XBT_NULL, buf , &len);
203 if (params) {
204 /*
205 * wait for device, on timeout silently fail because we will
206 * fail to open below
207 */
208 waitForDevice(params);
209 }
210 }
212 bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
213 /* check if it is a cdrom */
214 if (type && !strcmp(type, "cdrom")) {
215 bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
216 if (pasprintf(&buf, "%s/params", bpath) != -1)
217 xs_watch(xsh, buf, dev);
218 }
219 /* open device now if media present */
220 if (params[0]) {
221 if (bdrv_open(bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)],
222 params, 0 /* snapshot */) < 0)
223 fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
224 params);
225 }
226 }
228 /* Set a watch for log-dirty requests from the migration tools */
229 if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
230 domid) != -1) {
231 xs_watch(xsh, buf, "logdirty");
232 fprintf(logfile, "Watching %s\n", buf);
233 }
235 /* Set a watch for suspend requests from the migration tools */
236 if (pasprintf(&buf,
237 "/local/domain/0/device-model/%u/command", domid) != -1) {
238 xs_watch(xsh, buf, "dm-command");
239 fprintf(logfile, "Watching %s\n", buf);
240 }
242 out:
243 free(type);
244 free(params);
245 free(dev);
246 free(bpath);
247 free(buf);
248 free(path);
249 free(e);
250 free(drv);
251 return;
252 }
254 int xenstore_fd(void)
255 {
256 if (xsh)
257 return xs_fileno(xsh);
258 return -1;
259 }
261 unsigned long *logdirty_bitmap = NULL;
262 unsigned long logdirty_bitmap_size;
263 extern int vga_ram_size, bios_size;
265 void xenstore_process_logdirty_event(void)
266 {
267 char *act;
268 static char *active_path = NULL;
269 static char *next_active_path = NULL;
270 static char *seg = NULL;
271 unsigned int len;
272 int i;
274 if (!seg) {
275 char *path = NULL, *key_ascii, key_terminated[17] = {0,};
276 key_t key;
277 int shmid;
279 /* Find and map the shared memory segment for log-dirty bitmaps */
280 if (pasprintf(&path,
281 "/local/domain/0/device-model/%u/logdirty/key",
282 domid) == -1) {
283 fprintf(logfile, "Log-dirty: out of memory\n");
284 exit(1);
285 }
287 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
288 free(path);
290 if (!key_ascii)
291 /* No key yet: wait for the next watch */
292 return;
294 strncpy(key_terminated, key_ascii, 16);
295 free(key_ascii);
296 key = (key_t) strtoull(key_terminated, NULL, 16);
298 /* Figure out how bit the log-dirty bitmaps are */
299 logdirty_bitmap_size = xc_memory_op(xc_handle,
300 XENMEM_maximum_gpfn, &domid) + 1;
301 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
302 / HOST_LONG_BITS); /* longs */
303 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
305 /* Map the shared-memory segment */
306 if ((shmid = shmget(key,
307 2 * logdirty_bitmap_size,
308 S_IRUSR|S_IWUSR)) == -1
309 || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
310 fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
311 (unsigned long long) key, strerror(errno));
312 exit(1);
313 }
315 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
317 /* Double-check that the bitmaps are the size we expect */
318 if (logdirty_bitmap_size != *(uint32_t *)seg) {
319 fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
320 *(uint32_t *)seg, logdirty_bitmap_size);
321 /* Stale key: wait for next watch */
322 shmdt(seg);
323 seg = NULL;
324 return;
325 }
327 /* Remember the paths for the next-active and active entries */
328 if (pasprintf(&active_path,
329 "/local/domain/0/device-model/%u/logdirty/active",
330 domid) == -1) {
331 fprintf(logfile, "Log-dirty: out of memory\n");
332 exit(1);
333 }
334 if (pasprintf(&next_active_path,
335 "/local/domain/0/device-model/%u/logdirty/next-active",
336 domid) == -1) {
337 fprintf(logfile, "Log-dirty: out of memory\n");
338 exit(1);
339 }
340 }
342 fprintf(logfile, "Triggered log-dirty buffer switch\n");
344 /* Read the required active buffer from the store */
345 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
346 if (!act) {
347 fprintf(logfile, "Log-dirty: can't read next-active\n");
348 exit(1);
349 }
351 /* Switch buffers */
352 i = act[0] - '0';
353 if (i != 0 && i != 1) {
354 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
355 exit(1);
356 }
357 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
359 /* Ack that we've switched */
360 xs_write(xsh, XBT_NULL, active_path, act, len);
361 free(act);
362 }
365 /* Accept state change commands from the control tools */
366 static void xenstore_process_dm_command_event(void)
367 {
368 char *path = NULL, *command = NULL;
369 unsigned int len;
370 extern int suspend_requested;
372 if (pasprintf(&path,
373 "/local/domain/0/device-model/%u/command", domid) == -1) {
374 fprintf(logfile, "out of memory reading dm command\n");
375 goto out;
376 }
377 command = xs_read(xsh, XBT_NULL, path, &len);
378 if (!command)
379 goto out;
381 if (!strncmp(command, "save", len)) {
382 fprintf(logfile, "dm-command: pause and save state\n");
383 suspend_requested = 1;
384 } else if (!strncmp(command, "continue", len)) {
385 fprintf(logfile, "dm-command: continue after state save\n");
386 suspend_requested = 0;
387 } else {
388 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
389 }
391 out:
392 free(path);
393 free(command);
394 }
396 void xenstore_record_dm_state(char *state)
397 {
398 char *path = NULL;
400 if (pasprintf(&path,
401 "/local/domain/0/device-model/%u/state", domid) == -1) {
402 fprintf(logfile, "out of memory recording dm state\n");
403 goto out;
404 }
405 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
406 fprintf(logfile, "error recording dm state\n");
408 out:
409 free(path);
410 }
412 void xenstore_process_event(void *opaque)
413 {
414 char **vec, *image = NULL;
415 unsigned int len, num, hd_index;
417 vec = xs_read_watch(xsh, &num);
418 if (!vec)
419 return;
421 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
422 xenstore_process_logdirty_event();
423 goto out;
424 }
426 if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
427 xenstore_process_dm_command_event();
428 goto out;
429 }
431 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
432 strlen(vec[XS_WATCH_TOKEN]) != 3)
433 goto out;
434 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
435 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
436 if (image == NULL || !strcmp(image, bs_table[hd_index]->filename))
437 goto out; /* gone or identical */
439 do_eject(0, vec[XS_WATCH_TOKEN]);
440 bs_table[hd_index]->filename[0] = 0;
441 if (media_filename[hd_index]) {
442 free(media_filename[hd_index]);
443 media_filename[hd_index] = NULL;
444 }
446 if (image[0]) {
447 media_filename[hd_index] = strdup(image);
448 xenstore_check_new_media_present(5000);
449 }
451 out:
452 free(image);
453 free(vec);
454 }
456 void xenstore_write_vncport(int display)
457 {
458 char *buf = NULL, *path;
459 char *portstr = NULL;
461 if (xsh == NULL)
462 return;
464 path = xs_get_domain_path(xsh, domid);
465 if (path == NULL) {
466 fprintf(logfile, "xs_get_domain_path() error\n");
467 goto out;
468 }
470 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
471 goto out;
473 if (pasprintf(&portstr, "%d", display) == -1)
474 goto out;
476 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
477 fprintf(logfile, "xs_write() vncport failed\n");
479 out:
480 free(portstr);
481 free(buf);
482 }
484 int xenstore_read_vncpasswd(int domid)
485 {
486 extern char vncpasswd[64];
487 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
488 unsigned int i, len, rc = 0;
490 if (xsh == NULL) {
491 return -1;
492 }
494 path = xs_get_domain_path(xsh, domid);
495 if (path == NULL) {
496 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
497 return -1;
498 }
500 pasprintf(&buf, "%s/vm", path);
501 uuid = xs_read(xsh, XBT_NULL, buf, &len);
502 if (uuid == NULL) {
503 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
504 free(path);
505 return -1;
506 }
508 pasprintf(&buf, "%s/vncpasswd", uuid);
509 passwd = xs_read(xsh, XBT_NULL, buf, &len);
510 if (passwd == NULL) {
511 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
512 free(uuid);
513 free(path);
514 return rc;
515 }
517 for (i=0; i<len && i<63; i++) {
518 vncpasswd[i] = passwd[i];
519 passwd[i] = '\0';
520 }
521 vncpasswd[len] = '\0';
522 pasprintf(&buf, "%s/vncpasswd", uuid);
523 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
524 fprintf(logfile, "xs_write() vncpasswd failed.\n");
525 rc = -1;
526 }
528 free(passwd);
529 free(uuid);
530 free(path);
532 return rc;
533 }
536 /*
537 * get all device instances of a certain type
538 */
539 char **xenstore_domain_get_devices(struct xs_handle *handle,
540 const char *devtype, unsigned int *num)
541 {
542 char *path;
543 char *buf = NULL;
544 char **e = NULL;
546 path = xs_get_domain_path(handle, domid);
547 if (path == NULL)
548 goto out;
550 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
551 goto out;
553 e = xs_directory(handle, XBT_NULL, buf, num);
555 out:
556 free(path);
557 free(buf);
558 return e;
559 }
561 /*
562 * Check whether a domain has devices of the given type
563 */
564 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
565 {
566 int rc = 0;
567 unsigned int num;
568 char **e = xenstore_domain_get_devices(handle, devtype, &num);
569 if (e)
570 rc = 1;
571 free(e);
572 return rc;
573 }
575 /*
576 * Function that creates a path to a variable of an instance of a
577 * certain device
578 */
579 static char *get_device_variable_path(const char *devtype, const char *inst,
580 const char *var)
581 {
582 char *buf = NULL;
583 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
584 devtype,
585 domid,
586 inst,
587 var) == -1) {
588 free(buf);
589 buf = NULL;
590 }
591 return buf;
592 }
594 char *xenstore_backend_read_variable(struct xs_handle *handle,
595 const char *devtype, const char *inst,
596 const char *var)
597 {
598 char *value = NULL;
599 char *buf = NULL;
600 unsigned int len;
602 buf = get_device_variable_path(devtype, inst, var);
603 if (NULL == buf)
604 goto out;
606 value = xs_read(handle, XBT_NULL, buf, &len);
608 free(buf);
610 out:
611 return value;
612 }
614 /*
615 Read the hotplug status variable from the backend given the type
616 of device and its instance.
617 */
618 char *xenstore_read_hotplug_status(struct xs_handle *handle,
619 const char *devtype, const char *inst)
620 {
621 return xenstore_backend_read_variable(handle, devtype, inst,
622 "hotplug-status");
623 }
625 /*
626 Subscribe to the hotplug status of a device given the type of device and
627 its instance.
628 In case an error occurrs, a negative number is returned.
629 */
630 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
631 const char *devtype,
632 const char *inst,
633 const char *token)
634 {
635 int rc = 0;
636 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
638 if (path == NULL)
639 return -1;
641 if (0 == xs_watch(handle, path, token))
642 rc = -2;
644 free(path);
646 return rc;
647 }
649 /*
650 * Unsubscribe from a subscription to the status of a hotplug variable of
651 * a device.
652 */
653 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
654 const char *devtype,
655 const char *inst,
656 const char *token)
657 {
658 int rc = 0;
659 char *path;
660 path = get_device_variable_path(devtype, inst, "hotplug-status");
661 if (path == NULL)
662 return -1;
664 if (0 == xs_unwatch(handle, path, token))
665 rc = -2;
667 free(path);
669 return rc;
670 }
672 char *xenstore_vm_read(int domid, char *key, int *len)
673 {
674 char *buf = NULL, *path = NULL, *value = NULL;
676 if (xsh == NULL)
677 goto out;
679 path = xs_get_domain_path(xsh, domid);
680 if (path == NULL) {
681 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
682 goto out;
683 }
685 pasprintf(&buf, "%s/vm", path);
686 free(path);
687 path = xs_read(xsh, XBT_NULL, buf, NULL);
688 if (path == NULL) {
689 fprintf(logfile, "xs_read(%s): read error\n", buf);
690 goto out;
691 }
693 pasprintf(&buf, "%s/%s", path, key);
694 value = xs_read(xsh, XBT_NULL, buf, len);
695 if (value == NULL) {
696 fprintf(logfile, "xs_read(%s): read error\n", buf);
697 goto out;
698 }
700 out:
701 free(path);
702 free(buf);
703 return value;
704 }
706 int xenstore_vm_write(int domid, char *key, char *value)
707 {
708 char *buf = NULL, *path = NULL;
709 int rc = -1;
711 if (xsh == NULL)
712 goto out;
714 path = xs_get_domain_path(xsh, domid);
715 if (path == NULL) {
716 fprintf(logfile, "xs_get_domain_path: error\n");
717 goto out;
718 }
720 pasprintf(&buf, "%s/vm", path);
721 free(path);
722 path = xs_read(xsh, XBT_NULL, buf, NULL);
723 if (path == NULL) {
724 fprintf(logfile, "xs_read(%s): read error\n", buf);
725 goto out;
726 }
728 pasprintf(&buf, "%s/%s", path, key);
729 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
730 if (rc) {
731 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
732 goto out;
733 }
735 out:
736 free(path);
737 free(buf);
738 return rc;
739 }