ia64/xen-unstable

view tools/ioemu/xenstore.c @ 16863:6496ad18c3e2

ioemu: cache the BlockDriverState pointer
This actually fixes a bug in the scsi case.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 23 18:02:48 2008 +0000 (2008-01-23)
parents dfe9c0c10a2c
children 05e36e506c09
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, *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 || !strcmp(image, bs_table[hd_index]->filename))
445 goto out; /* gone or identical */
447 do_eject(0, vec[XS_WATCH_TOKEN]);
448 bs_table[hd_index]->filename[0] = 0;
449 if (media_filename[hd_index]) {
450 free(media_filename[hd_index]);
451 media_filename[hd_index] = NULL;
452 }
454 if (image[0]) {
455 media_filename[hd_index] = strdup(image);
456 xenstore_check_new_media_present(5000);
457 }
459 out:
460 free(image);
461 free(vec);
462 }
464 void xenstore_write_vncport(int display)
465 {
466 char *buf = NULL, *path;
467 char *portstr = NULL;
469 if (xsh == NULL)
470 return;
472 path = xs_get_domain_path(xsh, domid);
473 if (path == NULL) {
474 fprintf(logfile, "xs_get_domain_path() error\n");
475 goto out;
476 }
478 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
479 goto out;
481 if (pasprintf(&portstr, "%d", display) == -1)
482 goto out;
484 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
485 fprintf(logfile, "xs_write() vncport failed\n");
487 out:
488 free(portstr);
489 free(buf);
490 }
492 int xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
493 {
494 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
495 unsigned int i, len, rc = 0;
497 if (xsh == NULL) {
498 return -1;
499 }
501 path = xs_get_domain_path(xsh, domid);
502 if (path == NULL) {
503 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
504 return -1;
505 }
507 pasprintf(&buf, "%s/vm", path);
508 uuid = xs_read(xsh, XBT_NULL, buf, &len);
509 if (uuid == NULL) {
510 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
511 free(path);
512 return -1;
513 }
515 pasprintf(&buf, "%s/vncpasswd", uuid);
516 passwd = xs_read(xsh, XBT_NULL, buf, &len);
517 if (passwd == NULL) {
518 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
519 pwbuf[0] = '\0';
520 free(uuid);
521 free(path);
522 return rc;
523 }
525 for (i=0; i<len && i<pwbuflen; i++) {
526 pwbuf[i] = passwd[i];
527 }
528 pwbuf[len < (pwbuflen-1) ? len : (pwbuflen-1)] = '\0';
529 passwd[0] = '\0';
530 pasprintf(&buf, "%s/vncpasswd", uuid);
531 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
532 fprintf(logfile, "xs_write() vncpasswd failed.\n");
533 rc = -1;
534 }
536 free(passwd);
537 free(uuid);
538 free(path);
540 return rc;
541 }
544 /*
545 * get all device instances of a certain type
546 */
547 char **xenstore_domain_get_devices(struct xs_handle *handle,
548 const char *devtype, unsigned int *num)
549 {
550 char *path;
551 char *buf = NULL;
552 char **e = NULL;
554 path = xs_get_domain_path(handle, domid);
555 if (path == NULL)
556 goto out;
558 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
559 goto out;
561 e = xs_directory(handle, XBT_NULL, buf, num);
563 out:
564 free(path);
565 free(buf);
566 return e;
567 }
569 /*
570 * Check whether a domain has devices of the given type
571 */
572 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
573 {
574 int rc = 0;
575 unsigned int num;
576 char **e = xenstore_domain_get_devices(handle, devtype, &num);
577 if (e)
578 rc = 1;
579 free(e);
580 return rc;
581 }
583 /*
584 * Function that creates a path to a variable of an instance of a
585 * certain device
586 */
587 static char *get_device_variable_path(const char *devtype, const char *inst,
588 const char *var)
589 {
590 char *buf = NULL;
591 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
592 devtype,
593 domid,
594 inst,
595 var) == -1) {
596 free(buf);
597 buf = NULL;
598 }
599 return buf;
600 }
602 char *xenstore_backend_read_variable(struct xs_handle *handle,
603 const char *devtype, const char *inst,
604 const char *var)
605 {
606 char *value = NULL;
607 char *buf = NULL;
608 unsigned int len;
610 buf = get_device_variable_path(devtype, inst, var);
611 if (NULL == buf)
612 goto out;
614 value = xs_read(handle, XBT_NULL, buf, &len);
616 free(buf);
618 out:
619 return value;
620 }
622 /*
623 Read the hotplug status variable from the backend given the type
624 of device and its instance.
625 */
626 char *xenstore_read_hotplug_status(struct xs_handle *handle,
627 const char *devtype, const char *inst)
628 {
629 return xenstore_backend_read_variable(handle, devtype, inst,
630 "hotplug-status");
631 }
633 /*
634 Subscribe to the hotplug status of a device given the type of device and
635 its instance.
636 In case an error occurrs, a negative number is returned.
637 */
638 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
639 const char *devtype,
640 const char *inst,
641 const char *token)
642 {
643 int rc = 0;
644 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
646 if (path == NULL)
647 return -1;
649 if (0 == xs_watch(handle, path, token))
650 rc = -2;
652 free(path);
654 return rc;
655 }
657 /*
658 * Unsubscribe from a subscription to the status of a hotplug variable of
659 * a device.
660 */
661 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
662 const char *devtype,
663 const char *inst,
664 const char *token)
665 {
666 int rc = 0;
667 char *path;
668 path = get_device_variable_path(devtype, inst, "hotplug-status");
669 if (path == NULL)
670 return -1;
672 if (0 == xs_unwatch(handle, path, token))
673 rc = -2;
675 free(path);
677 return rc;
678 }
680 char *xenstore_vm_read(int domid, char *key, unsigned int *len)
681 {
682 char *buf = NULL, *path = NULL, *value = NULL;
684 if (xsh == NULL)
685 goto out;
687 path = xs_get_domain_path(xsh, domid);
688 if (path == NULL) {
689 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
690 goto out;
691 }
693 pasprintf(&buf, "%s/vm", path);
694 free(path);
695 path = xs_read(xsh, XBT_NULL, buf, NULL);
696 if (path == NULL) {
697 fprintf(logfile, "xs_read(%s): read error\n", buf);
698 goto out;
699 }
701 pasprintf(&buf, "%s/%s", path, key);
702 value = xs_read(xsh, XBT_NULL, buf, len);
703 if (value == NULL) {
704 fprintf(logfile, "xs_read(%s): read error\n", buf);
705 goto out;
706 }
708 out:
709 free(path);
710 free(buf);
711 return value;
712 }
714 int xenstore_vm_write(int domid, char *key, char *value)
715 {
716 char *buf = NULL, *path = NULL;
717 int rc = -1;
719 if (xsh == NULL)
720 goto out;
722 path = xs_get_domain_path(xsh, domid);
723 if (path == NULL) {
724 fprintf(logfile, "xs_get_domain_path: error\n");
725 goto out;
726 }
728 pasprintf(&buf, "%s/vm", path);
729 free(path);
730 path = xs_read(xsh, XBT_NULL, buf, NULL);
731 if (path == NULL) {
732 fprintf(logfile, "xs_read(%s): read error\n", buf);
733 goto out;
734 }
736 pasprintf(&buf, "%s/%s", path, key);
737 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
738 if (rc == 0) {
739 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
740 goto out;
741 }
743 out:
744 free(path);
745 free(buf);
746 return rc;
747 }