ia64/xen-unstable

view tools/ioemu/xenstore.c @ 15841:c5f735271e22

[IA64] Foreign p2m: Fix vti domain builder.

It should set arch_domain::convmem_end.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Thu Sep 06 13:48:43 2007 -0600 (2007-09-06)
parents d9836851a2a4
children 2372f89c0447
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, "/local/domain/0/device-model/%u/logdirty/next-active",
185 domid) != -1) {
186 xs_watch(xsh, buf, "logdirty");
187 fprintf(logfile, "Watching %s\n", buf);
188 }
190 /* Set a watch for suspend requests from the migration tools */
191 if (pasprintf(&buf,
192 "/local/domain/0/device-model/%u/command", domid) != -1) {
193 xs_watch(xsh, buf, "dm-command");
194 fprintf(logfile, "Watching %s\n", buf);
195 }
197 out:
198 free(type);
199 free(params);
200 free(dev);
201 free(bpath);
202 free(buf);
203 free(path);
204 free(e);
205 return;
206 }
208 int xenstore_fd(void)
209 {
210 if (xsh)
211 return xs_fileno(xsh);
212 return -1;
213 }
215 unsigned long *logdirty_bitmap = NULL;
216 unsigned long logdirty_bitmap_size;
217 extern int vga_ram_size, bios_size;
219 void xenstore_process_logdirty_event(void)
220 {
221 char *act;
222 static char *active_path = NULL;
223 static char *next_active_path = NULL;
224 static char *seg = NULL;
225 unsigned int len;
226 int i;
228 if (!seg) {
229 char *path = NULL, *key_ascii, key_terminated[17] = {0,};
230 key_t key;
231 int shmid;
233 /* Find and map the shared memory segment for log-dirty bitmaps */
234 if (pasprintf(&path,
235 "/local/domain/0/device-model/%u/logdirty/key",
236 domid) == -1) {
237 fprintf(logfile, "Log-dirty: out of memory\n");
238 exit(1);
239 }
241 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
242 free(path);
244 if (!key_ascii)
245 /* No key yet: wait for the next watch */
246 return;
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 if (pasprintf(&active_path,
280 "/local/domain/0/device-model/%u/logdirty/active",
281 domid) == -1) {
282 fprintf(logfile, "Log-dirty: out of memory\n");
283 exit(1);
284 }
285 if (pasprintf(&next_active_path,
286 "/local/domain/0/device-model/%u/logdirty/next-active",
287 domid) == -1) {
288 fprintf(logfile, "Log-dirty: out of memory\n");
289 exit(1);
290 }
291 }
293 fprintf(logfile, "Triggered log-dirty buffer switch\n");
295 /* Read the required active buffer from the store */
296 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
297 if (!act) {
298 fprintf(logfile, "Log-dirty: can't read next-active\n");
299 exit(1);
300 }
302 /* Switch buffers */
303 i = act[0] - '0';
304 if (i != 0 && i != 1) {
305 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
306 exit(1);
307 }
308 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
310 /* Ack that we've switched */
311 xs_write(xsh, XBT_NULL, active_path, act, len);
312 free(act);
313 }
316 /* Accept state change commands from the control tools */
317 static void xenstore_process_dm_command_event(void)
318 {
319 char *path = NULL, *command = NULL;
320 unsigned int len;
321 extern int suspend_requested;
323 if (pasprintf(&path,
324 "/local/domain/0/device-model/%u/command", domid) == -1) {
325 fprintf(logfile, "out of memory reading dm command\n");
326 goto out;
327 }
328 command = xs_read(xsh, XBT_NULL, path, &len);
329 if (!command)
330 goto out;
332 if (!strncmp(command, "save", len)) {
333 fprintf(logfile, "dm-command: pause and save state\n");
334 suspend_requested = 1;
335 } else if (!strncmp(command, "continue", len)) {
336 fprintf(logfile, "dm-command: continue after state save\n");
337 suspend_requested = 0;
338 } else {
339 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
340 }
342 out:
343 free(path);
344 free(command);
345 }
347 void xenstore_record_dm_state(char *state)
348 {
349 char *path = NULL;
351 if (pasprintf(&path,
352 "/local/domain/0/device-model/%u/state", domid) == -1) {
353 fprintf(logfile, "out of memory recording dm state\n");
354 goto out;
355 }
356 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
357 fprintf(logfile, "error recording dm state\n");
359 out:
360 free(path);
361 }
363 void xenstore_process_event(void *opaque)
364 {
365 char **vec, *image = NULL;
366 unsigned int len, num, hd_index;
368 vec = xs_read_watch(xsh, &num);
369 if (!vec)
370 return;
372 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
373 xenstore_process_logdirty_event();
374 goto out;
375 }
377 if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
378 xenstore_process_dm_command_event();
379 goto out;
380 }
382 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
383 strlen(vec[XS_WATCH_TOKEN]) != 3)
384 goto out;
385 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
386 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
387 if (image == NULL || !strcmp(image, bs_table[hd_index]->filename))
388 goto out; /* gone or identical */
390 do_eject(0, vec[XS_WATCH_TOKEN]);
391 bs_table[hd_index]->filename[0] = 0;
392 if (media_filename[hd_index]) {
393 free(media_filename[hd_index]);
394 media_filename[hd_index] = NULL;
395 }
397 if (image[0]) {
398 media_filename[hd_index] = strdup(image);
399 xenstore_check_new_media_present(5000);
400 }
402 out:
403 free(image);
404 free(vec);
405 }
407 void xenstore_write_vncport(int display)
408 {
409 char *buf = NULL, *path;
410 char *portstr = NULL;
412 if (xsh == NULL)
413 return;
415 path = xs_get_domain_path(xsh, domid);
416 if (path == NULL) {
417 fprintf(logfile, "xs_get_domain_path() error\n");
418 goto out;
419 }
421 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
422 goto out;
424 if (pasprintf(&portstr, "%d", display) == -1)
425 goto out;
427 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
428 fprintf(logfile, "xs_write() vncport failed\n");
430 out:
431 free(portstr);
432 free(buf);
433 }
435 int xenstore_read_vncpasswd(int domid)
436 {
437 extern char vncpasswd[64];
438 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
439 unsigned int i, len, rc = 0;
441 if (xsh == NULL) {
442 return -1;
443 }
445 path = xs_get_domain_path(xsh, domid);
446 if (path == NULL) {
447 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
448 return -1;
449 }
451 pasprintf(&buf, "%s/vm", path);
452 uuid = xs_read(xsh, XBT_NULL, buf, &len);
453 if (uuid == NULL) {
454 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
455 free(path);
456 return -1;
457 }
459 pasprintf(&buf, "%s/vncpasswd", uuid);
460 passwd = xs_read(xsh, XBT_NULL, buf, &len);
461 if (passwd == NULL) {
462 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
463 free(uuid);
464 free(path);
465 return rc;
466 }
468 for (i=0; i<len && i<63; i++) {
469 vncpasswd[i] = passwd[i];
470 passwd[i] = '\0';
471 }
472 vncpasswd[len] = '\0';
473 pasprintf(&buf, "%s/vncpasswd", uuid);
474 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
475 fprintf(logfile, "xs_write() vncpasswd failed.\n");
476 rc = -1;
477 }
479 free(passwd);
480 free(uuid);
481 free(path);
483 return rc;
484 }
487 /*
488 * get all device instances of a certain type
489 */
490 char **xenstore_domain_get_devices(struct xs_handle *handle,
491 const char *devtype, unsigned int *num)
492 {
493 char *path;
494 char *buf = NULL;
495 char **e = NULL;
497 path = xs_get_domain_path(handle, domid);
498 if (path == NULL)
499 goto out;
501 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
502 goto out;
504 e = xs_directory(handle, XBT_NULL, buf, num);
506 out:
507 free(path);
508 free(buf);
509 return e;
510 }
512 /*
513 * Check whether a domain has devices of the given type
514 */
515 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
516 {
517 int rc = 0;
518 unsigned int num;
519 char **e = xenstore_domain_get_devices(handle, devtype, &num);
520 if (e)
521 rc = 1;
522 free(e);
523 return rc;
524 }
526 /*
527 * Function that creates a path to a variable of an instance of a
528 * certain device
529 */
530 static char *get_device_variable_path(const char *devtype, const char *inst,
531 const char *var)
532 {
533 char *buf = NULL;
534 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
535 devtype,
536 domid,
537 inst,
538 var) == -1) {
539 free(buf);
540 buf = NULL;
541 }
542 return buf;
543 }
545 char *xenstore_backend_read_variable(struct xs_handle *handle,
546 const char *devtype, const char *inst,
547 const char *var)
548 {
549 char *value = NULL;
550 char *buf = NULL;
551 unsigned int len;
553 buf = get_device_variable_path(devtype, inst, var);
554 if (NULL == buf)
555 goto out;
557 value = xs_read(handle, XBT_NULL, buf, &len);
559 free(buf);
561 out:
562 return value;
563 }
565 /*
566 Read the hotplug status variable from the backend given the type
567 of device and its instance.
568 */
569 char *xenstore_read_hotplug_status(struct xs_handle *handle,
570 const char *devtype, const char *inst)
571 {
572 return xenstore_backend_read_variable(handle, devtype, inst,
573 "hotplug-status");
574 }
576 /*
577 Subscribe to the hotplug status of a device given the type of device and
578 its instance.
579 In case an error occurrs, a negative number is returned.
580 */
581 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
582 const char *devtype,
583 const char *inst,
584 const char *token)
585 {
586 int rc = 0;
587 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
589 if (path == NULL)
590 return -1;
592 if (0 == xs_watch(handle, path, token))
593 rc = -2;
595 free(path);
597 return rc;
598 }
600 /*
601 * Unsubscribe from a subscription to the status of a hotplug variable of
602 * a device.
603 */
604 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
605 const char *devtype,
606 const char *inst,
607 const char *token)
608 {
609 int rc = 0;
610 char *path;
611 path = get_device_variable_path(devtype, inst, "hotplug-status");
612 if (path == NULL)
613 return -1;
615 if (0 == xs_unwatch(handle, path, token))
616 rc = -2;
618 free(path);
620 return rc;
621 }
623 char *xenstore_vm_read(int domid, char *key, int *len)
624 {
625 char *buf = NULL, *path = NULL, *value = NULL;
627 if (xsh == NULL)
628 goto out;
630 path = xs_get_domain_path(xsh, domid);
631 if (path == NULL) {
632 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
633 goto out;
634 }
636 pasprintf(&buf, "%s/vm", path);
637 free(path);
638 path = xs_read(xsh, XBT_NULL, buf, NULL);
639 if (path == NULL) {
640 fprintf(logfile, "xs_read(%s): read error\n", buf);
641 goto out;
642 }
644 pasprintf(&buf, "%s/%s", path, key);
645 value = xs_read(xsh, XBT_NULL, buf, len);
646 if (value == NULL) {
647 fprintf(logfile, "xs_read(%s): read error\n", buf);
648 goto out;
649 }
651 out:
652 free(path);
653 free(buf);
654 return value;
655 }
657 int xenstore_vm_write(int domid, char *key, char *value)
658 {
659 char *buf = NULL, *path = NULL;
660 int rc = -1;
662 if (xsh == NULL)
663 goto out;
665 path = xs_get_domain_path(xsh, domid);
666 if (path == NULL) {
667 fprintf(logfile, "xs_get_domain_path: error\n");
668 goto out;
669 }
671 pasprintf(&buf, "%s/vm", path);
672 free(path);
673 path = xs_read(xsh, XBT_NULL, buf, NULL);
674 if (path == NULL) {
675 fprintf(logfile, "xs_read(%s): read error\n", buf);
676 goto out;
677 }
679 pasprintf(&buf, "%s/%s", path, key);
680 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
681 if (rc) {
682 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
683 goto out;
684 }
686 out:
687 free(path);
688 free(buf);
689 return rc;
690 }