📄 io.c
字号:
if (dom->xce_handle == -1) { err = errno; goto out; } rc = xc_evtchn_bind_interdomain(dom->xce_handle, dom->domid, remote_port); if (rc == -1) { err = errno; xc_evtchn_close(dom->xce_handle); dom->xce_handle = -1; goto out; } dom->local_port = rc; dom->remote_port = remote_port; if (dom->master_fd == -1) { if (!domain_create_tty(dom)) { err = errno; xc_evtchn_close(dom->xce_handle); dom->xce_handle = -1; dom->local_port = -1; dom->remote_port = -1; goto out; } } if (log_guest) dom->log_fd = create_domain_log(dom); out: return err;}static bool watch_domain(struct domain *dom, bool watch){ char domid_str[3 + MAX_STRLEN(dom->domid)]; bool success; snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid); if (watch) { success = xs_watch(xs, dom->serialpath, domid_str); if (success) { success = xs_watch(xs, dom->conspath, domid_str); if (success) domain_create_ring(dom); else xs_unwatch(xs, dom->serialpath, domid_str); } } else { success = xs_unwatch(xs, dom->serialpath, domid_str); success = xs_unwatch(xs, dom->conspath, domid_str); } return success;}static struct domain *create_domain(int domid){ struct domain *dom; char *s; struct timeval tv; if (gettimeofday(&tv, NULL) < 0) { dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", __FILE__, __FUNCTION__, __LINE__); return NULL; } dom = (struct domain *)malloc(sizeof(struct domain)); if (dom == NULL) { dolog(LOG_ERR, "Out of memory %s:%s():L%d", __FILE__, __FUNCTION__, __LINE__); exit(ENOMEM); } dom->domid = domid; dom->serialpath = xs_get_domain_path(xs, dom->domid); s = realloc(dom->serialpath, strlen(dom->serialpath) + strlen("/serial/0") + 1); if (s == NULL) goto out; dom->serialpath = s; strcat(dom->serialpath, "/serial/0"); dom->conspath = xs_get_domain_path(xs, dom->domid); s = realloc(dom->conspath, strlen(dom->conspath) + strlen("/console") + 1); if (s == NULL) goto out; dom->conspath = s; strcat(dom->conspath, "/console"); dom->master_fd = -1; dom->slave_fd = -1; dom->log_fd = -1; dom->is_dead = false; dom->buffer.data = 0; dom->buffer.consumed = 0; dom->buffer.size = 0; dom->buffer.capacity = 0; dom->buffer.max_capacity = 0; dom->event_count = 0; dom->next_period = (tv.tv_sec * 1000) + (tv.tv_usec / 1000) + RATE_LIMIT_PERIOD; dom->next = NULL; dom->ring_ref = -1; dom->local_port = -1; dom->remote_port = -1; dom->interface = NULL; dom->xce_handle = -1; if (!watch_domain(dom, true)) goto out; dom->next = dom_head; dom_head = dom; dolog(LOG_DEBUG, "New domain %d", domid); return dom; out: free(dom->serialpath); free(dom->conspath); free(dom); return NULL;}static struct domain *lookup_domain(int domid){ struct domain *dom; for (dom = dom_head; dom; dom = dom->next) if (dom->domid == domid) return dom; return NULL;}static void remove_domain(struct domain *dom){ struct domain **pp; dolog(LOG_DEBUG, "Removing domain-%d", dom->domid); for (pp = &dom_head; *pp; pp = &(*pp)->next) { if (dom == *pp) { *pp = dom->next; free(dom); break; } }}static void cleanup_domain(struct domain *d){ domain_close_tty(d); free(d->buffer.data); d->buffer.data = NULL; free(d->serialpath); d->serialpath = NULL; free(d->conspath); d->conspath = NULL; remove_domain(d);}static void shutdown_domain(struct domain *d){ d->is_dead = true; watch_domain(d, false); if (d->interface != NULL) munmap(d->interface, getpagesize()); d->interface = NULL; if (d->xce_handle != -1) xc_evtchn_close(d->xce_handle); d->xce_handle = -1;}void enum_domains(void){ int domid = 1; xc_dominfo_t dominfo; struct domain *dom; while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) { dom = lookup_domain(dominfo.domid); if (dominfo.dying) { if (dom) shutdown_domain(dom); } else { if (dom == NULL) create_domain(dominfo.domid); } domid = dominfo.domid + 1; }}static int ring_free_bytes(struct domain *dom){ struct xencons_interface *intf = dom->interface; XENCONS_RING_IDX cons, prod, space; cons = intf->in_cons; prod = intf->in_prod; mb(); space = prod - cons; if (space > sizeof(intf->in)) return 0; /* ring is screwed: ignore it */ return (sizeof(intf->in) - space);}static void handle_tty_read(struct domain *dom){ ssize_t len = 0; char msg[80]; int i; struct xencons_interface *intf = dom->interface; XENCONS_RING_IDX prod; if (dom->is_dead) return; len = ring_free_bytes(dom); if (len == 0) return; if (len > sizeof(msg)) len = sizeof(msg); len = read(dom->master_fd, msg, len); /* * Note: on Solaris, len == 0 means the slave closed, and this * is no problem, but Linux can't handle this usefully, so we * keep the slave open for the duration. */ if (len < 0) { domain_close_tty(dom); if (domain_is_valid(dom->domid)) { domain_create_tty(dom); } else { shutdown_domain(dom); } } else if (domain_is_valid(dom->domid)) { prod = intf->in_prod; for (i = 0; i < len; i++) { intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = msg[i]; } wmb(); intf->in_prod = prod; xc_evtchn_notify(dom->xce_handle, dom->local_port); } else { domain_close_tty(dom); shutdown_domain(dom); }}static void handle_tty_write(struct domain *dom){ ssize_t len; if (dom->is_dead) return; len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed, dom->buffer.size - dom->buffer.consumed); if (len < 1) { dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n", dom->domid, len, errno); domain_close_tty(dom); if (domain_is_valid(dom->domid)) { domain_create_tty(dom); } else { shutdown_domain(dom); } } else { buffer_advance(&dom->buffer, len); }}static void handle_ring_read(struct domain *dom){ evtchn_port_or_error_t port; if (dom->is_dead) return; if ((port = xc_evtchn_pending(dom->xce_handle)) == -1) return; dom->event_count++; buffer_append(dom); if (dom->event_count < RATE_LIMIT_ALLOWANCE) (void)xc_evtchn_unmask(dom->xce_handle, port);}static void handle_xs(void){ char **vec; int domid; struct domain *dom; unsigned int num; vec = xs_read_watch(xs, &num); if (!vec) return; if (!strcmp(vec[XS_WATCH_TOKEN], "domlist")) enum_domains(); else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) { dom = lookup_domain(domid); /* We may get watches firing for domains that have recently been removed, so dom may be NULL here. */ if (dom && dom->is_dead == false) domain_create_ring(dom); } free(vec);}static void handle_hv_logs(void){ char buffer[1024*16]; char *bufptr = buffer; unsigned int size = sizeof(buffer); static uint32_t index = 0; evtchn_port_or_error_t port; if ((port = xc_evtchn_pending(xce_handle)) == -1) return; if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0 && size > 0) { int logret; if (log_time_hv) logret = write_with_timestamp(log_hv_fd, buffer, size, &log_time_hv_needts); else logret = write_all(log_hv_fd, buffer, size); if (logret < 0) dolog(LOG_ERR, "Failed to write hypervisor log: " "%d (%s)", errno, strerror(errno)); } (void)xc_evtchn_unmask(xce_handle, port);}static void handle_log_reload(void){ if (log_guest) { struct domain *d; for (d = dom_head; d; d = d->next) { if (d->log_fd != -1) close(d->log_fd); d->log_fd = create_domain_log(d); } } if (log_hv) { if (log_hv_fd != -1) close(log_hv_fd); log_hv_fd = create_hv_log(); }}void handle_io(void){ fd_set readfds, writefds; int ret; if (log_hv) { xc_handle = xc_interface_open(); if (xc_handle == -1) { dolog(LOG_ERR, "Failed to open xc handle: %d (%s)", errno, strerror(errno)); goto out; } xce_handle = xc_evtchn_open(); if (xce_handle == -1) { dolog(LOG_ERR, "Failed to open xce handle: %d (%s)", errno, strerror(errno)); goto out; } log_hv_fd = create_hv_log(); if (log_hv_fd == -1) goto out; log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING); if (log_hv_evtchn == -1) { dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: " "%d (%s)", errno, strerror(errno)); goto out; } } for (;;) { struct domain *d, *n; int max_fd = -1; struct timeval timeout; struct timeval tv; long long now, next_timeout = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(xs_fileno(xs), &readfds); max_fd = MAX(xs_fileno(xs), max_fd); if (log_hv) { FD_SET(xc_evtchn_fd(xce_handle), &readfds); max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd); } if (gettimeofday(&tv, NULL) < 0) return; now = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); /* Re-calculate any event counter allowances & unblock domains with new allowance */ for (d = dom_head; d; d = d->next) { /* Add 5ms of fuzz since select() often returns a couple of ms sooner than requested. Without the fuzz we typically do an extra spin in select() with a 1/2 ms timeout every other iteration */ if ((now+5) > d->next_period) { d->next_period = now + RATE_LIMIT_PERIOD; if (d->event_count >= RATE_LIMIT_ALLOWANCE) { (void)xc_evtchn_unmask(d->xce_handle, d->local_port); } d->event_count = 0; } } for (d = dom_head; d; d = d->next) { if (d->event_count >= RATE_LIMIT_ALLOWANCE) { /* Determine if we're going to be the next time slice to expire */ if (!next_timeout || d->next_period < next_timeout) next_timeout = d->next_period; } else if (d->xce_handle != -1) { int evtchn_fd = xc_evtchn_fd(d->xce_handle); FD_SET(evtchn_fd, &readfds); max_fd = MAX(evtchn_fd, max_fd); } if (d->master_fd != -1) { if (!d->is_dead && ring_free_bytes(d)) FD_SET(d->master_fd, &readfds); if (!buffer_empty(&d->buffer)) FD_SET(d->master_fd, &writefds); max_fd = MAX(d->master_fd, max_fd); } } /* If any domain has been rate limited, we need to work out what timeout to supply to select */ if (next_timeout) { long long duration = (next_timeout - now); if (duration <= 0) /* sanity check */ duration = 1; timeout.tv_sec = duration / 1000; timeout.tv_usec = ((duration - (timeout.tv_sec * 1000)) * 1000); } ret = select(max_fd + 1, &readfds, &writefds, 0, next_timeout ? &timeout : NULL); if (log_reload) { handle_log_reload(); log_reload = 0; } /* Abort if select failed, except for EINTR cases which indicate a possible log reload */ if (ret == -1) { if (errno == EINTR) continue; dolog(LOG_ERR, "Failure in select: %d (%s)", errno, strerror(errno)); break; } if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds)) handle_hv_logs(); if (ret <= 0) continue; if (FD_ISSET(xs_fileno(xs), &readfds)) handle_xs(); for (d = dom_head; d; d = n) { n = d->next; if (d->event_count < RATE_LIMIT_ALLOWANCE) { if (d->xce_handle != -1 && FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds)) handle_ring_read(d); } if (d->master_fd != -1 && FD_ISSET(d->master_fd, &readfds)) handle_tty_read(d); if (d->master_fd != -1 && FD_ISSET(d->master_fd, &writefds)) handle_tty_write(d); if (d->is_dead) cleanup_domain(d); } } out: if (log_hv_fd != -1) { close(log_hv_fd); log_hv_fd = -1; } if (xc_handle != -1) { xc_interface_close(xc_handle); xc_handle = -1; } if (xce_handle != -1) { xc_evtchn_close(xce_handle); xce_handle = -1; } log_hv_evtchn = -1;}/* * Local variables: * c-file-style: "linux" * indent-tabs-mode: t * c-indent-level: 8 * c-basic-offset: 8 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -