⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -