debuggers.hg

view tools/console/daemon/io.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 60782cefa154
children
line source
1 /*
2 * Copyright (C) International Business Machines Corp., 2005
3 * Author(s): Anthony Liguori <aliguori@us.ibm.com>
4 *
5 * Xen Console Daemon
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; under version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 #define _GNU_SOURCE
23 #include "utils.h"
24 #include "io.h"
25 #include <xs.h>
26 #include <xen/io/console.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/select.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <termios.h>
35 #include <stdarg.h>
36 #include <sys/mman.h>
37 #include <time.h>
38 #include <assert.h>
39 #if defined(__NetBSD__) || defined(__OpenBSD__)
40 #include <util.h>
41 #elif defined(__linux__)
42 #include <pty.h>
43 #elif defined(__sun__)
44 #include <stropts.h>
45 #endif
47 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
48 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
50 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
51 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
53 /* How many events are allowed in each time period */
54 #define RATE_LIMIT_ALLOWANCE 30
55 /* Duration of each time period in ms */
56 #define RATE_LIMIT_PERIOD 200
58 extern int log_reload;
59 extern int log_guest;
60 extern int log_hv;
61 extern int log_time_hv;
62 extern int log_time_guest;
63 extern char *log_dir;
64 extern int discard_overflowed_data;
66 static int log_time_hv_needts = 1;
67 static int log_time_guest_needts = 1;
68 static int log_hv_fd = -1;
69 static evtchn_port_or_error_t log_hv_evtchn = -1;
70 static xc_interface *xch; /* why does xenconsoled have two xc handles ? */
71 static xc_evtchn *xce_handle = NULL;
73 struct buffer {
74 char *data;
75 size_t consumed;
76 size_t size;
77 size_t capacity;
78 size_t max_capacity;
79 };
81 struct domain {
82 int domid;
83 int master_fd;
84 int slave_fd;
85 int log_fd;
86 bool is_dead;
87 struct buffer buffer;
88 struct domain *next;
89 char *conspath;
90 int ring_ref;
91 evtchn_port_or_error_t local_port;
92 evtchn_port_or_error_t remote_port;
93 xc_evtchn *xce_handle;
94 struct xencons_interface *interface;
95 int event_count;
96 long long next_period;
97 };
99 static struct domain *dom_head;
101 static int write_all(int fd, const char* buf, size_t len)
102 {
103 while (len) {
104 ssize_t ret = write(fd, buf, len);
105 if (ret == -1 && errno == EINTR)
106 continue;
107 if (ret <= 0)
108 return -1;
109 len -= ret;
110 buf += ret;
111 }
113 return 0;
114 }
116 static int write_with_timestamp(int fd, const char *data, size_t sz,
117 int *needts)
118 {
119 char ts[32];
120 time_t now = time(NULL);
121 const struct tm *tmnow = localtime(&now);
122 size_t tslen = strftime(ts, sizeof(ts), "[%Y-%m-%d %H:%M:%S] ", tmnow);
123 const char *last_byte = data + sz - 1;
125 while (data <= last_byte) {
126 const char *nl = memchr(data, '\n', last_byte + 1 - data);
127 int found_nl = (nl != NULL);
128 if (!found_nl)
129 nl = last_byte;
131 if ((*needts && write_all(fd, ts, tslen))
132 || write_all(fd, data, nl + 1 - data))
133 return -1;
135 *needts = found_nl;
136 data = nl + 1;
137 if (found_nl) {
138 // If we printed a newline, strip all \r following it
139 while (data <= last_byte && *data == '\r')
140 data++;
141 }
142 }
144 return 0;
145 }
147 static void buffer_append(struct domain *dom)
148 {
149 struct buffer *buffer = &dom->buffer;
150 XENCONS_RING_IDX cons, prod, size;
151 struct xencons_interface *intf = dom->interface;
153 cons = intf->out_cons;
154 prod = intf->out_prod;
155 xen_mb();
157 size = prod - cons;
158 if ((size == 0) || (size > sizeof(intf->out)))
159 return;
161 if ((buffer->capacity - buffer->size) < size) {
162 buffer->capacity += (size + 1024);
163 buffer->data = realloc(buffer->data, buffer->capacity);
164 if (buffer->data == NULL) {
165 dolog(LOG_ERR, "Memory allocation failed");
166 exit(ENOMEM);
167 }
168 }
170 while (cons != prod)
171 buffer->data[buffer->size++] = intf->out[
172 MASK_XENCONS_IDX(cons++, intf->out)];
174 xen_mb();
175 intf->out_cons = cons;
176 xc_evtchn_notify(dom->xce_handle, dom->local_port);
178 /* Get the data to the logfile as early as possible because if
179 * no one is listening on the console pty then it will fill up
180 * and handle_tty_write will stop being called.
181 */
182 if (dom->log_fd != -1) {
183 int logret;
184 if (log_time_guest) {
185 logret = write_with_timestamp(
186 dom->log_fd,
187 buffer->data + buffer->size - size,
188 size, &log_time_guest_needts);
189 } else {
190 logret = write_all(
191 dom->log_fd,
192 buffer->data + buffer->size - size,
193 size);
194 }
195 if (logret < 0)
196 dolog(LOG_ERR, "Write to log failed "
197 "on domain %d: %d (%s)\n",
198 dom->domid, errno, strerror(errno));
199 }
201 if (discard_overflowed_data && buffer->max_capacity &&
202 buffer->size > 5 * buffer->max_capacity / 4) {
203 if (buffer->consumed > buffer->max_capacity / 4) {
204 /* Move data up in buffer, since beginning has
205 * been output. Only needed because buffer is
206 * not a ring buffer *sigh* */
207 memmove(buffer->data,
208 buffer->data + buffer->consumed,
209 buffer->size - buffer->consumed);
210 buffer->size -= buffer->consumed;
211 buffer->consumed = 0;
212 } else {
213 /* Discard the middle of the data. */
214 size_t over = buffer->size - buffer->max_capacity;
216 memmove(buffer->data + buffer->max_capacity / 2,
217 buffer->data + buffer->max_capacity,
218 over);
219 buffer->size = buffer->max_capacity / 2 + over;
220 }
221 }
222 }
224 static bool buffer_empty(struct buffer *buffer)
225 {
226 return buffer->size == 0;
227 }
229 static void buffer_advance(struct buffer *buffer, size_t len)
230 {
231 buffer->consumed += len;
232 if (buffer->consumed == buffer->size) {
233 buffer->consumed = 0;
234 buffer->size = 0;
235 if (buffer->max_capacity &&
236 buffer->capacity > buffer->max_capacity) {
237 buffer->data = realloc(buffer->data, buffer->max_capacity);
238 buffer->capacity = buffer->max_capacity;
239 }
240 }
241 }
243 static bool domain_is_valid(int domid)
244 {
245 bool ret;
246 xc_dominfo_t info;
248 ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&
249 info.domid == domid);
251 return ret;
252 }
254 static int create_hv_log(void)
255 {
256 char logfile[PATH_MAX];
257 int fd;
258 snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
259 logfile[PATH_MAX-1] = '\0';
261 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
262 if (fd == -1)
263 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
264 logfile, errno, strerror(errno));
265 if (fd != -1 && log_time_hv) {
266 if (write_with_timestamp(fd, "Logfile Opened",
267 strlen("Logfile Opened"),
268 &log_time_hv_needts) < 0) {
269 dolog(LOG_ERR, "Failed to log opening timestamp "
270 "in %s: %d (%s)", logfile, errno,
271 strerror(errno));
272 return -1;
273 }
274 }
275 return fd;
276 }
278 static int create_domain_log(struct domain *dom)
279 {
280 char logfile[PATH_MAX];
281 char *namepath, *data, *s;
282 int fd;
283 unsigned int len;
285 namepath = xs_get_domain_path(xs, dom->domid);
286 s = realloc(namepath, strlen(namepath) + 6);
287 if (s == NULL) {
288 free(namepath);
289 return -1;
290 }
291 namepath = s;
292 strcat(namepath, "/name");
293 data = xs_read(xs, XBT_NULL, namepath, &len);
294 free(namepath);
295 if (!data)
296 return -1;
297 if (!len) {
298 free(data);
299 return -1;
300 }
302 snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
303 free(data);
304 logfile[PATH_MAX-1] = '\0';
306 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
307 if (fd == -1)
308 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
309 logfile, errno, strerror(errno));
310 if (fd != -1 && log_time_guest) {
311 if (write_with_timestamp(fd, "Logfile Opened",
312 strlen("Logfile Opened"),
313 &log_time_guest_needts) < 0) {
314 dolog(LOG_ERR, "Failed to log opening timestamp "
315 "in %s: %d (%s)", logfile, errno,
316 strerror(errno));
317 return -1;
318 }
319 }
320 return fd;
321 }
323 static void domain_close_tty(struct domain *dom)
324 {
325 if (dom->master_fd != -1) {
326 close(dom->master_fd);
327 dom->master_fd = -1;
328 }
330 if (dom->slave_fd != -1) {
331 close(dom->slave_fd);
332 dom->slave_fd = -1;
333 }
334 }
336 #ifdef __sun__
337 static int openpty(int *amaster, int *aslave, char *name,
338 struct termios *termp, struct winsize *winp)
339 {
340 const char *slave;
341 int mfd = -1, sfd = -1;
343 *amaster = *aslave = -1;
345 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
346 if (mfd < 0)
347 goto err;
349 if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
350 goto err;
352 if ((slave = ptsname(mfd)) == NULL)
353 goto err;
355 if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
356 goto err;
358 if (ioctl(sfd, I_PUSH, "ptem") == -1)
359 goto err;
361 if (amaster)
362 *amaster = mfd;
363 if (aslave)
364 *aslave = sfd;
365 if (winp)
366 ioctl(sfd, TIOCSWINSZ, winp);
368 if (termp)
369 tcsetattr(sfd, TCSAFLUSH, termp);
371 assert(name == NULL);
373 return 0;
375 err:
376 if (sfd != -1)
377 close(sfd);
378 close(mfd);
379 return -1;
380 }
382 void cfmakeraw(struct termios *termios_p)
383 {
384 termios_p->c_iflag &=
385 ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
386 termios_p->c_oflag &= ~OPOST;
387 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
388 termios_p->c_cflag &= ~(CSIZE|PARENB);
389 termios_p->c_cflag |= CS8;
391 termios_p->c_cc[VMIN] = 0;
392 termios_p->c_cc[VTIME] = 0;
393 }
394 #endif /* __sun__ */
396 static int domain_create_tty(struct domain *dom)
397 {
398 const char *slave;
399 char *path;
400 int err;
401 bool success;
402 char *data;
403 unsigned int len;
404 struct termios term;
406 assert(dom->slave_fd == -1);
407 assert(dom->master_fd == -1);
409 if (openpty(&dom->master_fd, &dom->slave_fd, NULL, NULL, NULL) < 0) {
410 err = errno;
411 dolog(LOG_ERR, "Failed to create tty for domain-%d "
412 "(errno = %i, %s)",
413 dom->domid, err, strerror(err));
414 return 0;
415 }
417 if (tcgetattr(dom->slave_fd, &term) < 0) {
418 err = errno;
419 dolog(LOG_ERR, "Failed to get tty attributes for domain-%d "
420 "(errno = %i, %s)",
421 dom->domid, err, strerror(err));
422 goto out;
423 }
424 cfmakeraw(&term);
425 if (tcsetattr(dom->slave_fd, TCSANOW, &term) < 0) {
426 err = errno;
427 dolog(LOG_ERR, "Failed to set tty attributes for domain-%d "
428 "(errno = %i, %s)",
429 dom->domid, err, strerror(err));
430 goto out;
431 }
433 if ((slave = ptsname(dom->master_fd)) == NULL) {
434 err = errno;
435 dolog(LOG_ERR, "Failed to get slave name for domain-%d "
436 "(errno = %i, %s)",
437 dom->domid, err, strerror(err));
438 goto out;
439 }
441 success = asprintf(&path, "%s/limit", dom->conspath) !=
442 -1;
443 if (!success)
444 goto out;
445 data = xs_read(xs, XBT_NULL, path, &len);
446 if (data) {
447 dom->buffer.max_capacity = strtoul(data, 0, 0);
448 free(data);
449 }
450 free(path);
452 success = (asprintf(&path, "%s/tty", dom->conspath) != -1);
453 if (!success)
454 goto out;
455 success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
456 free(path);
457 if (!success)
458 goto out;
460 if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1)
461 goto out;
463 return 1;
464 out:
465 domain_close_tty(dom);
466 return 0;
467 }
469 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
470 static int xs_gather(struct xs_handle *xs, const char *dir, ...)
471 {
472 va_list ap;
473 const char *name;
474 char *path;
475 int ret = 0;
477 va_start(ap, dir);
478 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
479 const char *fmt = va_arg(ap, char *);
480 void *result = va_arg(ap, void *);
481 char *p;
483 if (asprintf(&path, "%s/%s", dir, name) == -1) {
484 ret = ENOMEM;
485 break;
486 }
487 p = xs_read(xs, XBT_NULL, path, NULL);
488 free(path);
489 if (p == NULL) {
490 ret = ENOENT;
491 break;
492 }
493 if (fmt) {
494 if (sscanf(p, fmt, result) == 0)
495 ret = EINVAL;
496 free(p);
497 } else
498 *(char **)result = p;
499 }
500 va_end(ap);
501 return ret;
502 }
504 static int domain_create_ring(struct domain *dom)
505 {
506 int err, remote_port, ring_ref, rc;
507 char *type, path[PATH_MAX];
509 err = xs_gather(xs, dom->conspath,
510 "ring-ref", "%u", &ring_ref,
511 "port", "%i", &remote_port,
512 NULL);
513 if (err)
514 goto out;
516 snprintf(path, sizeof(path), "%s/type", dom->conspath);
517 type = xs_read(xs, XBT_NULL, path, NULL);
518 if (type && strcmp(type, "xenconsoled") != 0) {
519 free(type);
520 return 0;
521 }
522 free(type);
524 if (ring_ref != dom->ring_ref) {
525 if (dom->interface != NULL)
526 munmap(dom->interface, getpagesize());
527 dom->interface = xc_map_foreign_range(
528 xc, dom->domid, getpagesize(),
529 PROT_READ|PROT_WRITE,
530 (unsigned long)ring_ref);
531 if (dom->interface == NULL) {
532 err = EINVAL;
533 goto out;
534 }
535 dom->ring_ref = ring_ref;
536 }
538 /* Go no further if port has not changed and we are still bound. */
539 if (remote_port == dom->remote_port) {
540 xc_evtchn_status_t status = {
541 .dom = DOMID_SELF,
542 .port = dom->local_port };
543 if ((xc_evtchn_status(xc, &status) == 0) &&
544 (status.status == EVTCHNSTAT_interdomain))
545 goto out;
546 }
548 dom->local_port = -1;
549 dom->remote_port = -1;
550 if (dom->xce_handle != NULL)
551 xc_evtchn_close(dom->xce_handle);
553 /* Opening evtchn independently for each console is a bit
554 * wasteful, but that's how the code is structured... */
555 dom->xce_handle = xc_evtchn_open(NULL, 0);
556 if (dom->xce_handle == NULL) {
557 err = errno;
558 goto out;
559 }
561 rc = xc_evtchn_bind_interdomain(dom->xce_handle,
562 dom->domid, remote_port);
564 if (rc == -1) {
565 err = errno;
566 xc_evtchn_close(dom->xce_handle);
567 dom->xce_handle = NULL;
568 goto out;
569 }
570 dom->local_port = rc;
571 dom->remote_port = remote_port;
573 if (dom->master_fd == -1) {
574 if (!domain_create_tty(dom)) {
575 err = errno;
576 xc_evtchn_close(dom->xce_handle);
577 dom->xce_handle = NULL;
578 dom->local_port = -1;
579 dom->remote_port = -1;
580 goto out;
581 }
582 }
584 if (log_guest && (dom->log_fd == -1))
585 dom->log_fd = create_domain_log(dom);
587 out:
588 return err;
589 }
591 static bool watch_domain(struct domain *dom, bool watch)
592 {
593 char domid_str[3 + MAX_STRLEN(dom->domid)];
594 bool success;
596 snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
597 if (watch) {
598 success = xs_watch(xs, dom->conspath, domid_str);
599 if (success)
600 domain_create_ring(dom);
601 else
602 xs_unwatch(xs, dom->conspath, domid_str);
603 } else {
604 success = xs_unwatch(xs, dom->conspath, domid_str);
605 }
607 return success;
608 }
611 static struct domain *create_domain(int domid)
612 {
613 struct domain *dom;
614 char *s;
615 struct timespec ts;
617 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
618 dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
619 __FILE__, __FUNCTION__, __LINE__);
620 return NULL;
621 }
623 dom = (struct domain *)malloc(sizeof(struct domain));
624 if (dom == NULL) {
625 dolog(LOG_ERR, "Out of memory %s:%s():L%d",
626 __FILE__, __FUNCTION__, __LINE__);
627 exit(ENOMEM);
628 }
630 dom->domid = domid;
632 dom->conspath = xs_get_domain_path(xs, dom->domid);
633 s = realloc(dom->conspath, strlen(dom->conspath) +
634 strlen("/console") + 1);
635 if (s == NULL)
636 goto out;
637 dom->conspath = s;
638 strcat(dom->conspath, "/console");
640 dom->master_fd = -1;
641 dom->slave_fd = -1;
642 dom->log_fd = -1;
644 dom->is_dead = false;
645 dom->buffer.data = 0;
646 dom->buffer.consumed = 0;
647 dom->buffer.size = 0;
648 dom->buffer.capacity = 0;
649 dom->buffer.max_capacity = 0;
650 dom->event_count = 0;
651 dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
652 dom->next = NULL;
654 dom->ring_ref = -1;
655 dom->local_port = -1;
656 dom->remote_port = -1;
657 dom->interface = NULL;
658 dom->xce_handle = NULL;
660 if (!watch_domain(dom, true))
661 goto out;
663 dom->next = dom_head;
664 dom_head = dom;
666 dolog(LOG_DEBUG, "New domain %d", domid);
668 return dom;
669 out:
670 free(dom->conspath);
671 free(dom);
672 return NULL;
673 }
675 static struct domain *lookup_domain(int domid)
676 {
677 struct domain *dom;
679 for (dom = dom_head; dom; dom = dom->next)
680 if (dom->domid == domid)
681 return dom;
682 return NULL;
683 }
685 static void remove_domain(struct domain *dom)
686 {
687 struct domain **pp;
689 dolog(LOG_DEBUG, "Removing domain-%d", dom->domid);
691 for (pp = &dom_head; *pp; pp = &(*pp)->next) {
692 if (dom == *pp) {
693 *pp = dom->next;
694 free(dom);
695 break;
696 }
697 }
698 }
700 static void cleanup_domain(struct domain *d)
701 {
702 domain_close_tty(d);
704 if (d->log_fd != -1) {
705 close(d->log_fd);
706 d->log_fd = -1;
707 }
709 free(d->buffer.data);
710 d->buffer.data = NULL;
712 free(d->conspath);
713 d->conspath = NULL;
715 remove_domain(d);
716 }
718 static void shutdown_domain(struct domain *d)
719 {
720 d->is_dead = true;
721 watch_domain(d, false);
722 if (d->interface != NULL)
723 munmap(d->interface, getpagesize());
724 d->interface = NULL;
725 if (d->xce_handle != NULL)
726 xc_evtchn_close(d->xce_handle);
727 d->xce_handle = NULL;
728 }
730 void enum_domains(void)
731 {
732 int domid = 1;
733 xc_dominfo_t dominfo;
734 struct domain *dom;
736 while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
737 dom = lookup_domain(dominfo.domid);
738 if (dominfo.dying) {
739 if (dom)
740 shutdown_domain(dom);
741 } else {
742 if (dom == NULL)
743 create_domain(dominfo.domid);
744 }
745 domid = dominfo.domid + 1;
746 }
747 }
749 static int ring_free_bytes(struct domain *dom)
750 {
751 struct xencons_interface *intf = dom->interface;
752 XENCONS_RING_IDX cons, prod, space;
754 cons = intf->in_cons;
755 prod = intf->in_prod;
756 xen_mb();
758 space = prod - cons;
759 if (space > sizeof(intf->in))
760 return 0; /* ring is screwed: ignore it */
762 return (sizeof(intf->in) - space);
763 }
765 static void handle_tty_read(struct domain *dom)
766 {
767 ssize_t len = 0;
768 char msg[80];
769 int i;
770 struct xencons_interface *intf = dom->interface;
771 XENCONS_RING_IDX prod;
773 if (dom->is_dead)
774 return;
776 len = ring_free_bytes(dom);
777 if (len == 0)
778 return;
780 if (len > sizeof(msg))
781 len = sizeof(msg);
783 len = read(dom->master_fd, msg, len);
784 /*
785 * Note: on Solaris, len == 0 means the slave closed, and this
786 * is no problem, but Linux can't handle this usefully, so we
787 * keep the slave open for the duration.
788 */
789 if (len < 0) {
790 domain_close_tty(dom);
792 if (domain_is_valid(dom->domid)) {
793 domain_create_tty(dom);
794 } else {
795 shutdown_domain(dom);
796 }
797 } else if (domain_is_valid(dom->domid)) {
798 prod = intf->in_prod;
799 for (i = 0; i < len; i++) {
800 intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
801 msg[i];
802 }
803 xen_wmb();
804 intf->in_prod = prod;
805 xc_evtchn_notify(dom->xce_handle, dom->local_port);
806 } else {
807 domain_close_tty(dom);
808 shutdown_domain(dom);
809 }
810 }
812 static void handle_tty_write(struct domain *dom)
813 {
814 ssize_t len;
816 if (dom->is_dead)
817 return;
819 len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed,
820 dom->buffer.size - dom->buffer.consumed);
821 if (len < 1) {
822 dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
823 dom->domid, len, errno);
825 domain_close_tty(dom);
827 if (domain_is_valid(dom->domid)) {
828 domain_create_tty(dom);
829 } else {
830 shutdown_domain(dom);
831 }
832 } else {
833 buffer_advance(&dom->buffer, len);
834 }
835 }
837 static void handle_ring_read(struct domain *dom)
838 {
839 evtchn_port_or_error_t port;
841 if (dom->is_dead)
842 return;
844 if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
845 return;
847 dom->event_count++;
849 buffer_append(dom);
851 if (dom->event_count < RATE_LIMIT_ALLOWANCE)
852 (void)xc_evtchn_unmask(dom->xce_handle, port);
853 }
855 static void handle_xs(void)
856 {
857 char **vec;
858 int domid;
859 struct domain *dom;
860 unsigned int num;
862 vec = xs_read_watch(xs, &num);
863 if (!vec)
864 return;
866 if (!strcmp(vec[XS_WATCH_TOKEN], "domlist"))
867 enum_domains();
868 else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) {
869 dom = lookup_domain(domid);
870 /* We may get watches firing for domains that have recently
871 been removed, so dom may be NULL here. */
872 if (dom && dom->is_dead == false)
873 domain_create_ring(dom);
874 }
876 free(vec);
877 }
879 static void handle_hv_logs(void)
880 {
881 char buffer[1024*16];
882 char *bufptr = buffer;
883 unsigned int size = sizeof(buffer);
884 static uint32_t index = 0;
885 evtchn_port_or_error_t port;
887 if ((port = xc_evtchn_pending(xce_handle)) == -1)
888 return;
890 if (xc_readconsolering(xch, bufptr, &size, 0, 1, &index) == 0 && size > 0) {
891 int logret;
892 if (log_time_hv)
893 logret = write_with_timestamp(log_hv_fd, buffer, size,
894 &log_time_hv_needts);
895 else
896 logret = write_all(log_hv_fd, buffer, size);
898 if (logret < 0)
899 dolog(LOG_ERR, "Failed to write hypervisor log: "
900 "%d (%s)", errno, strerror(errno));
901 }
903 (void)xc_evtchn_unmask(xce_handle, port);
904 }
906 static void handle_log_reload(void)
907 {
908 if (log_guest) {
909 struct domain *d;
910 for (d = dom_head; d; d = d->next) {
911 if (d->log_fd != -1)
912 close(d->log_fd);
913 d->log_fd = create_domain_log(d);
914 }
915 }
917 if (log_hv) {
918 if (log_hv_fd != -1)
919 close(log_hv_fd);
920 log_hv_fd = create_hv_log();
921 }
922 }
924 void handle_io(void)
925 {
926 fd_set readfds, writefds;
927 int ret;
929 if (log_hv) {
930 xch = xc_interface_open(0,0,0);
931 if (!xch) {
932 dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
933 errno, strerror(errno));
934 goto out;
935 }
936 xce_handle = xc_evtchn_open(NULL, 0);
937 if (xce_handle == NULL) {
938 dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
939 errno, strerror(errno));
940 goto out;
941 }
942 log_hv_fd = create_hv_log();
943 if (log_hv_fd == -1)
944 goto out;
945 log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING);
946 if (log_hv_evtchn == -1) {
947 dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
948 "%d (%s)", errno, strerror(errno));
949 goto out;
950 }
951 }
953 for (;;) {
954 struct domain *d, *n;
955 int max_fd = -1;
956 struct timeval timeout;
957 struct timespec ts;
958 long long now, next_timeout = 0;
960 FD_ZERO(&readfds);
961 FD_ZERO(&writefds);
963 FD_SET(xs_fileno(xs), &readfds);
964 max_fd = MAX(xs_fileno(xs), max_fd);
966 if (log_hv) {
967 FD_SET(xc_evtchn_fd(xce_handle), &readfds);
968 max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
969 }
971 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
972 return;
973 now = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
975 /* Re-calculate any event counter allowances & unblock
976 domains with new allowance */
977 for (d = dom_head; d; d = d->next) {
978 /* Add 5ms of fuzz since select() often returns
979 a couple of ms sooner than requested. Without
980 the fuzz we typically do an extra spin in select()
981 with a 1/2 ms timeout every other iteration */
982 if ((now+5) > d->next_period) {
983 d->next_period = now + RATE_LIMIT_PERIOD;
984 if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
985 (void)xc_evtchn_unmask(d->xce_handle, d->local_port);
986 }
987 d->event_count = 0;
988 }
989 }
991 for (d = dom_head; d; d = d->next) {
992 if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
993 /* Determine if we're going to be the next time slice to expire */
994 if (!next_timeout ||
995 d->next_period < next_timeout)
996 next_timeout = d->next_period;
997 } else if (d->xce_handle != NULL) {
998 if (discard_overflowed_data ||
999 !d->buffer.max_capacity ||
1000 d->buffer.size < d->buffer.max_capacity) {
1001 int evtchn_fd = xc_evtchn_fd(d->xce_handle);
1002 FD_SET(evtchn_fd, &readfds);
1003 max_fd = MAX(evtchn_fd, max_fd);
1007 if (d->master_fd != -1) {
1008 if (!d->is_dead && ring_free_bytes(d))
1009 FD_SET(d->master_fd, &readfds);
1011 if (!buffer_empty(&d->buffer))
1012 FD_SET(d->master_fd, &writefds);
1013 max_fd = MAX(d->master_fd, max_fd);
1017 /* If any domain has been rate limited, we need to work
1018 out what timeout to supply to select */
1019 if (next_timeout) {
1020 long long duration = (next_timeout - now);
1021 if (duration <= 0) /* sanity check */
1022 duration = 1;
1023 timeout.tv_sec = duration / 1000;
1024 timeout.tv_usec = ((duration - (timeout.tv_sec * 1000))
1025 * 1000);
1028 ret = select(max_fd + 1, &readfds, &writefds, 0,
1029 next_timeout ? &timeout : NULL);
1031 if (log_reload) {
1032 handle_log_reload();
1033 log_reload = 0;
1036 /* Abort if select failed, except for EINTR cases
1037 which indicate a possible log reload */
1038 if (ret == -1) {
1039 if (errno == EINTR)
1040 continue;
1041 dolog(LOG_ERR, "Failure in select: %d (%s)",
1042 errno, strerror(errno));
1043 break;
1046 if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds))
1047 handle_hv_logs();
1049 if (ret <= 0)
1050 continue;
1052 if (FD_ISSET(xs_fileno(xs), &readfds))
1053 handle_xs();
1055 for (d = dom_head; d; d = n) {
1056 n = d->next;
1057 if (d->event_count < RATE_LIMIT_ALLOWANCE) {
1058 if (d->xce_handle != NULL &&
1059 FD_ISSET(xc_evtchn_fd(d->xce_handle),
1060 &readfds))
1061 handle_ring_read(d);
1064 if (d->master_fd != -1 && FD_ISSET(d->master_fd,
1065 &readfds))
1066 handle_tty_read(d);
1068 if (d->master_fd != -1 && FD_ISSET(d->master_fd,
1069 &writefds))
1070 handle_tty_write(d);
1072 if (d->is_dead)
1073 cleanup_domain(d);
1077 out:
1078 if (log_hv_fd != -1) {
1079 close(log_hv_fd);
1080 log_hv_fd = -1;
1082 if (xch) {
1083 xc_interface_close(xch);
1084 xch = 0;
1086 if (xce_handle != NULL) {
1087 xc_evtchn_close(xce_handle);
1088 xce_handle = NULL;
1090 log_hv_evtchn = -1;
1093 /*
1094 * Local variables:
1095 * c-file-style: "linux"
1096 * indent-tabs-mode: t
1097 * c-indent-level: 8
1098 * c-basic-offset: 8
1099 * tab-width: 8
1100 * End:
1101 */