1 /* libxenstat: statistics-collection library for Xen
2  * Copyright (C) International Business Machines Corp., 2005
3  * Authors: Josh Triplett <josh@kernel.org>
4  *          Judy Fischbach <jfisch@cs.pdx.edu>
5  *          David Hendricks <cro_marmot@comcast.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  */
17 
18 /*
19  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
20  * Use is subject to license terms.
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 
28 #include "xenstat_priv.h"
29 
30 /*
31  * Data-collection types
32  */
33 /* Called to collect the information for the node and all the domains on
34  * it. When called, the domain information has already been collected.
35  * Return status is 0 if fatal error occurs, 1 for success. Collectors
36  * may prune a domain from the list if it has been deleted between the
37  * time the list was setup and the time the colector is called */
38 typedef int (*xenstat_collect_func)(xenstat_node * node);
39 /* Called to free the information collected by the collect function.  The free
40  * function will only be called on a xenstat_node if that node includes
41  * information collected by the corresponding collector. */
42 typedef void (*xenstat_free_func)(xenstat_node * node);
43 /* Called to free any information stored in the handle.  Note the lack of a
44  * matching init function; the collect functions should initialize on first
45  * use.  Also, the uninit function must handle the case that the collector has
46  * never been initialized. */
47 typedef void (*xenstat_uninit_func)(xenstat_handle * handle);
48 typedef struct xenstat_collector {
49 	unsigned int flag;
50 	xenstat_collect_func collect;
51 	xenstat_free_func free;
52 	xenstat_uninit_func uninit;
53 } xenstat_collector;
54 
55 static int  xenstat_collect_vcpus(xenstat_node * node);
56 static int  xenstat_collect_xen_version(xenstat_node * node);
57 static void xenstat_free_vcpus(xenstat_node * node);
58 static void xenstat_free_networks(xenstat_node * node);
59 static void xenstat_free_xen_version(xenstat_node * node);
60 static void xenstat_free_vbds(xenstat_node * node);
61 static void xenstat_uninit_vcpus(xenstat_handle * handle);
62 static void xenstat_uninit_xen_version(xenstat_handle * handle);
63 static char *xenstat_get_domain_name(xenstat_handle * handle, unsigned int domain_id);
64 static void xenstat_prune_domain(xenstat_node *node, unsigned int entry);
65 
66 static xenstat_collector collectors[] = {
67 	{ XENSTAT_VCPU, xenstat_collect_vcpus,
68 	  xenstat_free_vcpus, xenstat_uninit_vcpus },
69 	{ XENSTAT_NETWORK, xenstat_collect_networks,
70 	  xenstat_free_networks, xenstat_uninit_networks },
71 	{ XENSTAT_XEN_VERSION, xenstat_collect_xen_version,
72 	  xenstat_free_xen_version, xenstat_uninit_xen_version },
73 	{ XENSTAT_VBD, xenstat_collect_vbds,
74 	  xenstat_free_vbds, xenstat_uninit_vbds }
75 };
76 
77 #define NUM_COLLECTORS (sizeof(collectors)/sizeof(xenstat_collector))
78 
79 /*
80  * libxenstat API
81  */
xenstat_init(void)82 xenstat_handle *xenstat_init(void)
83 {
84 	xenstat_handle *handle;
85 
86 	handle = (xenstat_handle *) calloc(1, sizeof(xenstat_handle));
87 	if (handle == NULL)
88 		return NULL;
89 
90 #if defined(PAGESIZE)
91 	handle->page_size = PAGESIZE;
92 #elif defined(PAGE_SIZE)
93 	handle->page_size = PAGE_SIZE;
94 #else
95 	handle->page_size = sysconf(_SC_PAGE_SIZE);
96 	if (handle->page_size < 0) {
97 		perror("Failed to retrieve page size.");
98 		free(handle);
99 		return NULL;
100 	}
101 #endif
102 
103 	handle->xc_handle = xc_interface_open(0,0,0);
104 	if (!handle->xc_handle) {
105 		perror("xc_interface_open");
106 		free(handle);
107 		return NULL;
108 	}
109 
110 	handle->xshandle = xs_daemon_open_readonly(); /* open handle to xenstore*/
111 	if (handle->xshandle == NULL) {
112 		perror("unable to open xenstore");
113 		xc_interface_close(handle->xc_handle);
114 		free(handle);
115 		return NULL;
116 	}
117 
118 	return handle;
119 }
120 
xenstat_uninit(xenstat_handle * handle)121 void xenstat_uninit(xenstat_handle * handle)
122 {
123 	unsigned int i;
124 	if (handle) {
125 		for (i = 0; i < NUM_COLLECTORS; i++)
126 			collectors[i].uninit(handle);
127 		xc_interface_close(handle->xc_handle);
128 		xs_daemon_close(handle->xshandle);
129 		free(handle->priv);
130 		free(handle);
131 	}
132 }
133 
parse(char * s,char * match)134 static inline unsigned long long parse(char *s, char *match)
135 {
136 	char *s1 = strstr(s,match);
137 	unsigned long long ret;
138 
139 	if ( s1 == NULL )
140 		return 0LL;
141 	s1 += 2;
142 	if ( *s1++ != ':' )
143 		return 0LL;
144 	sscanf(s1,"%llu",&ret);
145 	return ret;
146 }
147 
domain_get_tmem_stats(xenstat_handle * handle,xenstat_domain * domain)148 void domain_get_tmem_stats(xenstat_handle * handle, xenstat_domain * domain)
149 {
150 	char buffer[4096];
151 
152 	if (xc_tmem_control(handle->xc_handle,-1,XEN_SYSCTL_TMEM_OP_LIST,domain->id,
153                         sizeof(buffer),-1,buffer) < 0)
154 		return;
155 	domain->tmem_stats.curr_eph_pages = parse(buffer,"Ec");
156 	domain->tmem_stats.succ_eph_gets = parse(buffer,"Ge");
157 	domain->tmem_stats.succ_pers_puts = parse(buffer,"Pp");
158 	domain->tmem_stats.succ_pers_gets = parse(buffer,"Gp");
159 }
160 
xenstat_get_node(xenstat_handle * handle,unsigned int flags)161 xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags)
162 {
163 #define DOMAIN_CHUNK_SIZE 256
164 	xenstat_node *node;
165 	xc_physinfo_t physinfo = { 0 };
166 	xc_domaininfo_t domaininfo[DOMAIN_CHUNK_SIZE];
167 	int new_domains;
168 	unsigned int i;
169 	int rc;
170 
171 	/* Create the node */
172 	node = (xenstat_node *) calloc(1, sizeof(xenstat_node));
173 	if (node == NULL)
174 		return NULL;
175 
176 	/* Store the handle in the node for later access */
177 	node->handle = handle;
178 
179 	/* Get information about the physical system */
180 	if (xc_physinfo(handle->xc_handle, &physinfo) < 0) {
181 		free(node);
182 		return NULL;
183 	}
184 
185 
186 	node->cpu_hz = ((unsigned long long)physinfo.cpu_khz) * 1000ULL;
187         node->num_cpus = physinfo.nr_cpus;
188 	node->tot_mem = ((unsigned long long)physinfo.total_pages)
189 	    * handle->page_size;
190 	node->free_mem = ((unsigned long long)physinfo.free_pages)
191 	    * handle->page_size;
192 
193 	rc = xc_tmem_control(handle->xc_handle, -1,
194                          XEN_SYSCTL_TMEM_OP_QUERY_FREEABLE_MB, -1, 0, 0, NULL);
195 	node->freeable_mb = (rc < 0) ? 0 : rc;
196 	/* malloc(0) is not portable, so allocate a single domain.  This will
197 	 * be resized below. */
198 	node->domains = malloc(sizeof(xenstat_domain));
199 	if (node->domains == NULL) {
200 		free(node);
201 		return NULL;
202 	}
203 
204 	node->num_domains = 0;
205 	do {
206 		xenstat_domain *domain, *tmp;
207 
208 		new_domains = xc_domain_getinfolist(handle->xc_handle,
209 						    node->num_domains,
210 						    DOMAIN_CHUNK_SIZE,
211 						    domaininfo);
212 		if (new_domains < 0)
213 			goto err;
214 
215 		tmp = realloc(node->domains,
216 			      (node->num_domains + new_domains)
217 			      * sizeof(xenstat_domain));
218 		if (tmp == NULL)
219 			goto err;
220 
221 		node->domains = tmp;
222 
223 		domain = node->domains + node->num_domains;
224 
225 		/* zero out newly allocated memory in case error occurs below */
226 		memset(domain, 0, new_domains * sizeof(xenstat_domain));
227 
228 		for (i = 0; i < new_domains; i++) {
229 			/* Fill in domain using domaininfo[i] */
230 			domain->id = domaininfo[i].domain;
231 			domain->name = xenstat_get_domain_name(handle,
232 							       domain->id);
233 			if (domain->name == NULL) {
234 				if (errno == ENOMEM) {
235 					/* fatal error */
236 					xenstat_free_node(node);
237 					return NULL;
238 				}
239 				else {
240 					/* failed to get name -- this means the
241 					   domain is being destroyed so simply
242 					   ignore this entry */
243 					continue;
244 				}
245 			}
246 			domain->state = domaininfo[i].flags;
247 			domain->cpu_ns = domaininfo[i].cpu_time;
248 			domain->num_vcpus = (domaininfo[i].max_vcpu_id+1);
249 			domain->vcpus = NULL;
250 			domain->cur_mem =
251 			    ((unsigned long long)domaininfo[i].tot_pages)
252 			    * handle->page_size;
253 			domain->max_mem =
254 			    domaininfo[i].max_pages == UINT_MAX
255 			    ? (unsigned long long)-1
256 			    : (unsigned long long)(domaininfo[i].max_pages
257 						   * handle->page_size);
258 			domain->ssid = domaininfo[i].ssidref;
259 			domain->num_networks = 0;
260 			domain->networks = NULL;
261 			domain->num_vbds = 0;
262 			domain->vbds = NULL;
263 			domain_get_tmem_stats(handle,domain);
264 
265 			domain++;
266 			node->num_domains++;
267 		}
268 	} while (new_domains == DOMAIN_CHUNK_SIZE);
269 
270 
271 	/* Run all the extra data collectors requested */
272 	node->flags = 0;
273 	for (i = 0; i < NUM_COLLECTORS; i++) {
274 		if ((flags & collectors[i].flag) == collectors[i].flag) {
275 			node->flags |= collectors[i].flag;
276 			if(collectors[i].collect(node) == 0) {
277 				xenstat_free_node(node);
278 				return NULL;
279 			}
280 		}
281 	}
282 
283 	return node;
284 err:
285 	free(node->domains);
286 	free(node);
287 	return NULL;
288 }
289 
xenstat_free_node(xenstat_node * node)290 void xenstat_free_node(xenstat_node * node)
291 {
292 	int i;
293 
294 	if (node) {
295 		if (node->domains) {
296 			for (i = 0; i < node->num_domains; i++)
297 				free(node->domains[i].name);
298 
299 			for (i = 0; i < NUM_COLLECTORS; i++)
300 				if((node->flags & collectors[i].flag)
301 				   == collectors[i].flag)
302 					collectors[i].free(node);
303 			free(node->domains);
304 		}
305 		free(node);
306 	}
307 }
308 
xenstat_node_domain(xenstat_node * node,unsigned int domid)309 xenstat_domain *xenstat_node_domain(xenstat_node * node, unsigned int domid)
310 {
311 	unsigned int i;
312 
313 	/* FIXME: binary search */
314 	/* Find the appropriate domain entry in the node struct. */
315 	for (i = 0; i < node->num_domains; i++) {
316 		if (node->domains[i].id == domid)
317 			return &(node->domains[i]);
318 	}
319 	return NULL;
320 }
321 
xenstat_node_domain_by_index(xenstat_node * node,unsigned int index)322 xenstat_domain *xenstat_node_domain_by_index(xenstat_node * node,
323 					     unsigned int index)
324 {
325 	if (index < node->num_domains)
326 		return &(node->domains[index]);
327 	return NULL;
328 }
329 
xenstat_node_xen_version(xenstat_node * node)330 const char *xenstat_node_xen_version(xenstat_node * node)
331 {
332 	return node->handle->xen_version;
333 }
334 
xenstat_node_tot_mem(xenstat_node * node)335 unsigned long long xenstat_node_tot_mem(xenstat_node * node)
336 {
337 	return node->tot_mem;
338 }
339 
xenstat_node_free_mem(xenstat_node * node)340 unsigned long long xenstat_node_free_mem(xenstat_node * node)
341 {
342 	return node->free_mem;
343 }
344 
xenstat_node_freeable_mb(xenstat_node * node)345 long xenstat_node_freeable_mb(xenstat_node * node)
346 {
347 	return node->freeable_mb;
348 }
349 
xenstat_node_num_domains(xenstat_node * node)350 unsigned int xenstat_node_num_domains(xenstat_node * node)
351 {
352 	return node->num_domains;
353 }
354 
xenstat_node_num_cpus(xenstat_node * node)355 unsigned int xenstat_node_num_cpus(xenstat_node * node)
356 {
357 	return node->num_cpus;
358 }
359 
360 /* Get information about the CPU speed */
xenstat_node_cpu_hz(xenstat_node * node)361 unsigned long long xenstat_node_cpu_hz(xenstat_node * node)
362 {
363 	return node->cpu_hz;
364 }
365 
366 /* Get the domain ID for this domain */
xenstat_domain_id(xenstat_domain * domain)367 unsigned xenstat_domain_id(xenstat_domain * domain)
368 {
369 	return domain->id;
370 }
371 
372 /* Get the domain name for the domain */
xenstat_domain_name(xenstat_domain * domain)373 char *xenstat_domain_name(xenstat_domain * domain)
374 {
375 	return domain->name;
376 }
377 
378 /* Get information about how much CPU time has been used */
xenstat_domain_cpu_ns(xenstat_domain * domain)379 unsigned long long xenstat_domain_cpu_ns(xenstat_domain * domain)
380 {
381 	return domain->cpu_ns;
382 }
383 
384 /* Find the number of VCPUs for a domain */
xenstat_domain_num_vcpus(xenstat_domain * domain)385 unsigned int xenstat_domain_num_vcpus(xenstat_domain * domain)
386 {
387 	return domain->num_vcpus;
388 }
389 
xenstat_domain_vcpu(xenstat_domain * domain,unsigned int vcpu)390 xenstat_vcpu *xenstat_domain_vcpu(xenstat_domain * domain, unsigned int vcpu)
391 {
392 	if (vcpu < domain->num_vcpus)
393 		return &(domain->vcpus[vcpu]);
394 	return NULL;
395 }
396 
397 /* Find the current memory reservation for this domain */
xenstat_domain_cur_mem(xenstat_domain * domain)398 unsigned long long xenstat_domain_cur_mem(xenstat_domain * domain)
399 {
400 	return domain->cur_mem;
401 }
402 
403 /* Find the maximum memory reservation for this domain */
xenstat_domain_max_mem(xenstat_domain * domain)404 unsigned long long xenstat_domain_max_mem(xenstat_domain * domain)
405 {
406 	return domain->max_mem;
407 }
408 
409 /* Find the domain's SSID */
xenstat_domain_ssid(xenstat_domain * domain)410 unsigned int xenstat_domain_ssid(xenstat_domain * domain)
411 {
412 	return domain->ssid;
413 }
414 
415 /* Get domain states */
xenstat_domain_dying(xenstat_domain * domain)416 unsigned int xenstat_domain_dying(xenstat_domain * domain)
417 {
418 	return (domain->state & XEN_DOMINF_dying) == XEN_DOMINF_dying;
419 }
420 
xenstat_domain_crashed(xenstat_domain * domain)421 unsigned int xenstat_domain_crashed(xenstat_domain * domain)
422 {
423 	return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
424 	    && (((domain->state >> XEN_DOMINF_shutdownshift)
425 		 & XEN_DOMINF_shutdownmask) == SHUTDOWN_crash);
426 }
427 
xenstat_domain_shutdown(xenstat_domain * domain)428 unsigned int xenstat_domain_shutdown(xenstat_domain * domain)
429 {
430 	return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
431 	    && (((domain->state >> XEN_DOMINF_shutdownshift)
432 		 & XEN_DOMINF_shutdownmask) != SHUTDOWN_crash);
433 }
434 
xenstat_domain_paused(xenstat_domain * domain)435 unsigned int xenstat_domain_paused(xenstat_domain * domain)
436 {
437 	return (domain->state & XEN_DOMINF_paused) == XEN_DOMINF_paused;
438 }
439 
xenstat_domain_blocked(xenstat_domain * domain)440 unsigned int xenstat_domain_blocked(xenstat_domain * domain)
441 {
442 	return (domain->state & XEN_DOMINF_blocked) == XEN_DOMINF_blocked;
443 }
444 
xenstat_domain_running(xenstat_domain * domain)445 unsigned int xenstat_domain_running(xenstat_domain * domain)
446 {
447 	return (domain->state & XEN_DOMINF_running) == XEN_DOMINF_running;
448 }
449 
450 /* Get the number of networks for a given domain */
xenstat_domain_num_networks(xenstat_domain * domain)451 unsigned int xenstat_domain_num_networks(xenstat_domain * domain)
452 {
453 	return domain->num_networks;
454 }
455 
456 /* Get the network handle to obtain network stats */
xenstat_domain_network(xenstat_domain * domain,unsigned int network)457 xenstat_network *xenstat_domain_network(xenstat_domain * domain,
458 					unsigned int network)
459 {
460 	if (domain->networks && network < domain->num_networks)
461 		return &(domain->networks[network]);
462 	return NULL;
463 }
464 
465 /* Get the number of VBDs for a given domain */
xenstat_domain_num_vbds(xenstat_domain * domain)466 unsigned int xenstat_domain_num_vbds(xenstat_domain * domain)
467 {
468 	return domain->num_vbds;
469 }
470 
471 /* Get the VBD handle to obtain VBD stats */
xenstat_domain_vbd(xenstat_domain * domain,unsigned int vbd)472 xenstat_vbd *xenstat_domain_vbd(xenstat_domain * domain,
473 				unsigned int vbd)
474 {
475 	if (domain->vbds && vbd < domain->num_vbds)
476 		return &(domain->vbds[vbd]);
477 	return NULL;
478 }
479 
480 /*
481  * VCPU functions
482  */
483 /* Collect information about VCPUs */
xenstat_collect_vcpus(xenstat_node * node)484 static int xenstat_collect_vcpus(xenstat_node * node)
485 {
486 	unsigned int i, vcpu, inc_index;
487 
488 	/* Fill in VCPU information */
489 	for (i = 0; i < node->num_domains; i+=inc_index) {
490 		inc_index = 1; /* default is to increment to next domain */
491 
492 		node->domains[i].vcpus = malloc(node->domains[i].num_vcpus
493 						* sizeof(xenstat_vcpu));
494 		if (node->domains[i].vcpus == NULL)
495 			return 0;
496 
497 		for (vcpu = 0; vcpu < node->domains[i].num_vcpus; vcpu++) {
498 			/* FIXME: need to be using a more efficient mechanism*/
499 			xc_vcpuinfo_t info;
500 
501 			if (xc_vcpu_getinfo(node->handle->xc_handle,
502 					    node->domains[i].id, vcpu, &info) != 0) {
503 				if (errno == ENOMEM) {
504 					/* fatal error */
505 					return 0;
506 				}
507 				else {
508 					/* domain is in transition - remove
509 					   from list */
510 					xenstat_prune_domain(node, i);
511 
512 					/* remember not to increment index! */
513 					inc_index = 0;
514 					break;
515 				}
516 			}
517 			else {
518 				node->domains[i].vcpus[vcpu].online = info.online;
519 				node->domains[i].vcpus[vcpu].ns = info.cpu_time;
520 			}
521 		}
522 	}
523 	return 1;
524 }
525 
526 /* Free VCPU information */
xenstat_free_vcpus(xenstat_node * node)527 static void xenstat_free_vcpus(xenstat_node * node)
528 {
529 	unsigned int i;
530 	for (i = 0; i < node->num_domains; i++)
531 		free(node->domains[i].vcpus);
532 }
533 
534 /* Free VCPU information in handle - nothing to do */
xenstat_uninit_vcpus(xenstat_handle * handle)535 static void xenstat_uninit_vcpus(xenstat_handle * handle)
536 {
537 }
538 
539 /* Get VCPU online status */
xenstat_vcpu_online(xenstat_vcpu * vcpu)540 unsigned int xenstat_vcpu_online(xenstat_vcpu * vcpu)
541 {
542 	return vcpu->online;
543 }
544 
545 /* Get VCPU usage */
xenstat_vcpu_ns(xenstat_vcpu * vcpu)546 unsigned long long xenstat_vcpu_ns(xenstat_vcpu * vcpu)
547 {
548 	return vcpu->ns;
549 }
550 
551 /*
552  * Network functions
553  */
554 
555 /* Free network information */
xenstat_free_networks(xenstat_node * node)556 static void xenstat_free_networks(xenstat_node * node)
557 {
558 	unsigned int i;
559 	for (i = 0; i < node->num_domains; i++)
560 		free(node->domains[i].networks);
561 }
562 
563 /* Get the network ID */
xenstat_network_id(xenstat_network * network)564 unsigned int xenstat_network_id(xenstat_network * network)
565 {
566 	return network->id;
567 }
568 
569 /* Get the number of receive bytes */
xenstat_network_rbytes(xenstat_network * network)570 unsigned long long xenstat_network_rbytes(xenstat_network * network)
571 {
572 	return network->rbytes;
573 }
574 
575 /* Get the number of receive packets */
xenstat_network_rpackets(xenstat_network * network)576 unsigned long long xenstat_network_rpackets(xenstat_network * network)
577 {
578 	return network->rpackets;
579 }
580 
581 /* Get the number of receive errors */
xenstat_network_rerrs(xenstat_network * network)582 unsigned long long xenstat_network_rerrs(xenstat_network * network)
583 {
584 	return network->rerrs;
585 }
586 
587 /* Get the number of receive drops */
xenstat_network_rdrop(xenstat_network * network)588 unsigned long long xenstat_network_rdrop(xenstat_network * network)
589 {
590 	return network->rdrop;
591 }
592 
593 /* Get the number of transmit bytes */
xenstat_network_tbytes(xenstat_network * network)594 unsigned long long xenstat_network_tbytes(xenstat_network * network)
595 {
596 	return network->tbytes;
597 }
598 
599 /* Get the number of transmit packets */
xenstat_network_tpackets(xenstat_network * network)600 unsigned long long xenstat_network_tpackets(xenstat_network * network)
601 {
602 	return network->tpackets;
603 }
604 
605 /* Get the number of transmit errors */
xenstat_network_terrs(xenstat_network * network)606 unsigned long long xenstat_network_terrs(xenstat_network * network)
607 {
608 	return network->terrs;
609 }
610 
611 /* Get the number of transmit dropped packets */
xenstat_network_tdrop(xenstat_network * network)612 unsigned long long xenstat_network_tdrop(xenstat_network * network)
613 {
614 	return network->tdrop;
615 }
616 
617 /*
618  * Xen version functions
619  */
620 
621 /* Collect Xen version information */
xenstat_collect_xen_version(xenstat_node * node)622 static int xenstat_collect_xen_version(xenstat_node * node)
623 {
624 	long vnum = 0;
625 	xen_extraversion_t version;
626 
627 	/* Collect Xen version information if not already collected */
628 	if (node->handle->xen_version[0] == '\0') {
629 		/* Get the Xen version number and extraversion string */
630 		vnum = xc_version(node->handle->xc_handle,
631 			XENVER_version, NULL);
632 
633 		if (vnum < 0)
634 			return 0;
635 
636 		if (xc_version(node->handle->xc_handle, XENVER_extraversion,
637 			&version) < 0)
638 			return 0;
639 		/* Format the version information as a string and store it */
640 		snprintf(node->handle->xen_version, VERSION_SIZE, "%ld.%ld%s",
641 			 ((vnum >> 16) & 0xFFFF), vnum & 0xFFFF, version);
642 	}
643 
644 	return 1;
645 }
646 
647 /* Free Xen version information in node - nothing to do */
xenstat_free_xen_version(xenstat_node * node)648 static void xenstat_free_xen_version(xenstat_node * node)
649 {
650 }
651 
652 /* Free Xen version information in handle - nothing to do */
xenstat_uninit_xen_version(xenstat_handle * handle)653 static void xenstat_uninit_xen_version(xenstat_handle * handle)
654 {
655 }
656 
657 /*
658  * VBD functions
659  */
660 
661 /* Save VBD information */
xenstat_save_vbd(xenstat_domain * domain,xenstat_vbd * vbd)662 xenstat_vbd *xenstat_save_vbd(xenstat_domain *domain, xenstat_vbd *vbd)
663 {
664         xenstat_vbd *vbds = domain->vbds;
665 
666         domain->num_vbds++;
667         domain->vbds = realloc(domain->vbds,
668                                domain->num_vbds *
669                                sizeof(xenstat_vbd));
670 
671         if (domain->vbds == NULL) {
672                 domain->num_vbds = 0;
673                 free(vbds);
674         }
675         else {
676                 domain->vbds[domain->num_vbds - 1] = *vbd;
677         }
678 
679         return domain->vbds;
680 }
681 
682 /* Free VBD information */
xenstat_free_vbds(xenstat_node * node)683 static void xenstat_free_vbds(xenstat_node * node)
684 {
685 	unsigned int i;
686 	for (i = 0; i < node->num_domains; i++)
687 		free(node->domains[i].vbds);
688 }
689 
690 /* Get the back driver type  for Virtual Block Device */
xenstat_vbd_type(xenstat_vbd * vbd)691 unsigned int xenstat_vbd_type(xenstat_vbd * vbd)
692 {
693 	return vbd->back_type;
694 }
695 
696 /* Get the major number of VBD device */
xenstat_vbd_dev(xenstat_vbd * vbd)697 unsigned int xenstat_vbd_dev(xenstat_vbd * vbd)
698 {
699 	return vbd->dev;
700 }
701 
702 /* Get the number of OO(Out of) requests */
xenstat_vbd_oo_reqs(xenstat_vbd * vbd)703 unsigned long long xenstat_vbd_oo_reqs(xenstat_vbd * vbd)
704 {
705 	return vbd->oo_reqs;
706 }
707 
708 /* Get the number of READ requests */
xenstat_vbd_rd_reqs(xenstat_vbd * vbd)709 unsigned long long xenstat_vbd_rd_reqs(xenstat_vbd * vbd)
710 {
711 	return vbd->rd_reqs;
712 }
713 
714 /* Get the number of WRITE requests */
xenstat_vbd_wr_reqs(xenstat_vbd * vbd)715 unsigned long long xenstat_vbd_wr_reqs(xenstat_vbd * vbd)
716 {
717 	return vbd->wr_reqs;
718 }
719 
720 /* Get the number of READ sectors */
xenstat_vbd_rd_sects(xenstat_vbd * vbd)721 unsigned long long xenstat_vbd_rd_sects(xenstat_vbd * vbd)
722 {
723 	return vbd->rd_sects;
724 }
725 
726 /* Get the number of WRITE sectors */
xenstat_vbd_wr_sects(xenstat_vbd * vbd)727 unsigned long long xenstat_vbd_wr_sects(xenstat_vbd * vbd)
728 {
729 	return vbd->wr_sects;
730 }
731 
732 /*
733  * Tmem functions
734  */
735 
xenstat_domain_tmem(xenstat_domain * domain)736 xenstat_tmem *xenstat_domain_tmem(xenstat_domain * domain)
737 {
738 	return &domain->tmem_stats;
739 }
740 
741 /* Get the current number of ephemeral pages */
xenstat_tmem_curr_eph_pages(xenstat_tmem * tmem)742 unsigned long long xenstat_tmem_curr_eph_pages(xenstat_tmem *tmem)
743 {
744 	return tmem->curr_eph_pages;
745 }
746 
747 /* Get the number of successful ephemeral gets */
xenstat_tmem_succ_eph_gets(xenstat_tmem * tmem)748 unsigned long long xenstat_tmem_succ_eph_gets(xenstat_tmem *tmem)
749 {
750 	return tmem->succ_eph_gets;
751 }
752 
753 /* Get the number of successful persistent puts */
xenstat_tmem_succ_pers_puts(xenstat_tmem * tmem)754 unsigned long long xenstat_tmem_succ_pers_puts(xenstat_tmem *tmem)
755 {
756 	return tmem->succ_pers_puts;
757 }
758 
759 /* Get the number of successful persistent gets */
xenstat_tmem_succ_pers_gets(xenstat_tmem * tmem)760 unsigned long long xenstat_tmem_succ_pers_gets(xenstat_tmem *tmem)
761 {
762 	return tmem->succ_pers_gets;
763 }
764 
765 
xenstat_get_domain_name(xenstat_handle * handle,unsigned int domain_id)766 static char *xenstat_get_domain_name(xenstat_handle *handle, unsigned int domain_id)
767 {
768 	char path[80];
769 
770 	snprintf(path, sizeof(path),"/local/domain/%i/name", domain_id);
771 
772 	return xs_read(handle->xshandle, XBT_NULL, path, NULL);
773 }
774 
775 /* Remove specified entry from list of domains */
xenstat_prune_domain(xenstat_node * node,unsigned int entry)776 static void xenstat_prune_domain(xenstat_node *node, unsigned int entry)
777 {
778 	/* nothing to do if array is empty or entry is beyond end */
779 	if (node->num_domains == 0 || entry >= node->num_domains)
780 		return;
781 
782 	/* decrement count of domains */
783 	node->num_domains--;
784 
785 	/* shift entries following specified entry up by one */
786 	if (entry < node->num_domains) {
787 		xenstat_domain *domain = &node->domains[entry];
788 		memmove(domain,domain+1,(node->num_domains - entry) * sizeof(xenstat_domain) );
789 	}
790 
791 	/* zero out original last entry from node -- not
792 	   strictly necessary but safer! */
793 	memset(&node->domains[node->num_domains], 0, sizeof(xenstat_domain));
794 }
795