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 
xenstat_get_node(xenstat_handle * handle,unsigned int flags)134 xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags)
135 {
136 #define DOMAIN_CHUNK_SIZE 256
137 	xenstat_node *node;
138 	xc_physinfo_t physinfo = { 0 };
139 	xc_domaininfo_t domaininfo[DOMAIN_CHUNK_SIZE];
140 	int new_domains;
141 	unsigned int i;
142 
143 	/* Create the node */
144 	node = (xenstat_node *) calloc(1, sizeof(xenstat_node));
145 	if (node == NULL)
146 		return NULL;
147 
148 	/* Store the handle in the node for later access */
149 	node->handle = handle;
150 
151 	/* Get information about the physical system */
152 	if (xc_physinfo(handle->xc_handle, &physinfo) < 0) {
153 		free(node);
154 		return NULL;
155 	}
156 
157 
158 	node->cpu_hz = ((unsigned long long)physinfo.cpu_khz) * 1000ULL;
159         node->num_cpus = physinfo.nr_cpus;
160 	node->tot_mem = ((unsigned long long)physinfo.total_pages)
161 	    * handle->page_size;
162 	node->free_mem = ((unsigned long long)physinfo.free_pages)
163 	    * handle->page_size;
164 
165 	node->freeable_mb = 0;
166 	/* malloc(0) is not portable, so allocate a single domain.  This will
167 	 * be resized below. */
168 	node->domains = malloc(sizeof(xenstat_domain));
169 	if (node->domains == NULL) {
170 		free(node);
171 		return NULL;
172 	}
173 
174 	node->num_domains = 0;
175 	do {
176 		xenstat_domain *domain, *tmp;
177 
178 		new_domains = xc_domain_getinfolist(handle->xc_handle,
179 						    node->num_domains,
180 						    DOMAIN_CHUNK_SIZE,
181 						    domaininfo);
182 		if (new_domains < 0)
183 			goto err;
184 
185 		tmp = realloc(node->domains,
186 			      (node->num_domains + new_domains)
187 			      * sizeof(xenstat_domain));
188 		if (tmp == NULL)
189 			goto err;
190 
191 		node->domains = tmp;
192 
193 		domain = node->domains + node->num_domains;
194 
195 		/* zero out newly allocated memory in case error occurs below */
196 		memset(domain, 0, new_domains * sizeof(xenstat_domain));
197 
198 		for (i = 0; i < new_domains; i++) {
199 			/* Fill in domain using domaininfo[i] */
200 			domain->id = domaininfo[i].domain;
201 			domain->name = xenstat_get_domain_name(handle,
202 							       domain->id);
203 			if (domain->name == NULL) {
204 				if (errno == ENOMEM) {
205 					/* fatal error */
206 					xenstat_free_node(node);
207 					return NULL;
208 				}
209 				else {
210 					/* failed to get name -- this means the
211 					   domain is being destroyed so simply
212 					   ignore this entry */
213 					continue;
214 				}
215 			}
216 			domain->state = domaininfo[i].flags;
217 			domain->cpu_ns = domaininfo[i].cpu_time;
218 			domain->num_vcpus = (domaininfo[i].max_vcpu_id+1);
219 			domain->vcpus = NULL;
220 			domain->cur_mem =
221 			    ((unsigned long long)domaininfo[i].tot_pages)
222 			    * handle->page_size;
223 			domain->max_mem =
224 			    domaininfo[i].max_pages == UINT_MAX
225 			    ? (unsigned long long)-1
226 			    : (unsigned long long)(domaininfo[i].max_pages
227 						   * handle->page_size);
228 			domain->ssid = domaininfo[i].ssidref;
229 			domain->num_networks = 0;
230 			domain->networks = NULL;
231 			domain->num_vbds = 0;
232 			domain->vbds = NULL;
233 
234 			domain++;
235 			node->num_domains++;
236 		}
237 	} while (new_domains == DOMAIN_CHUNK_SIZE);
238 
239 
240 	/* Run all the extra data collectors requested */
241 	node->flags = 0;
242 	for (i = 0; i < NUM_COLLECTORS; i++) {
243 		if ((flags & collectors[i].flag) == collectors[i].flag) {
244 			node->flags |= collectors[i].flag;
245 			if(collectors[i].collect(node) == 0) {
246 				xenstat_free_node(node);
247 				return NULL;
248 			}
249 		}
250 	}
251 
252 	return node;
253 err:
254 	free(node->domains);
255 	free(node);
256 	return NULL;
257 }
258 
xenstat_free_node(xenstat_node * node)259 void xenstat_free_node(xenstat_node * node)
260 {
261 	int i;
262 
263 	if (node) {
264 		if (node->domains) {
265 			for (i = 0; i < node->num_domains; i++)
266 				free(node->domains[i].name);
267 
268 			for (i = 0; i < NUM_COLLECTORS; i++)
269 				if((node->flags & collectors[i].flag)
270 				   == collectors[i].flag)
271 					collectors[i].free(node);
272 			free(node->domains);
273 		}
274 		free(node);
275 	}
276 }
277 
xenstat_node_domain(xenstat_node * node,unsigned int domid)278 xenstat_domain *xenstat_node_domain(xenstat_node * node, unsigned int domid)
279 {
280 	unsigned int i;
281 
282 	/* FIXME: binary search */
283 	/* Find the appropriate domain entry in the node struct. */
284 	for (i = 0; i < node->num_domains; i++) {
285 		if (node->domains[i].id == domid)
286 			return &(node->domains[i]);
287 	}
288 	return NULL;
289 }
290 
xenstat_node_domain_by_index(xenstat_node * node,unsigned int index)291 xenstat_domain *xenstat_node_domain_by_index(xenstat_node * node,
292 					     unsigned int index)
293 {
294 	if (index < node->num_domains)
295 		return &(node->domains[index]);
296 	return NULL;
297 }
298 
xenstat_node_xen_version(xenstat_node * node)299 const char *xenstat_node_xen_version(xenstat_node * node)
300 {
301 	return node->handle->xen_version;
302 }
303 
xenstat_node_tot_mem(xenstat_node * node)304 unsigned long long xenstat_node_tot_mem(xenstat_node * node)
305 {
306 	return node->tot_mem;
307 }
308 
xenstat_node_free_mem(xenstat_node * node)309 unsigned long long xenstat_node_free_mem(xenstat_node * node)
310 {
311 	return node->free_mem;
312 }
313 
xenstat_node_freeable_mb(xenstat_node * node)314 long xenstat_node_freeable_mb(xenstat_node * node)
315 {
316 	return node->freeable_mb;
317 }
318 
xenstat_node_num_domains(xenstat_node * node)319 unsigned int xenstat_node_num_domains(xenstat_node * node)
320 {
321 	return node->num_domains;
322 }
323 
xenstat_node_num_cpus(xenstat_node * node)324 unsigned int xenstat_node_num_cpus(xenstat_node * node)
325 {
326 	return node->num_cpus;
327 }
328 
329 /* Get information about the CPU speed */
xenstat_node_cpu_hz(xenstat_node * node)330 unsigned long long xenstat_node_cpu_hz(xenstat_node * node)
331 {
332 	return node->cpu_hz;
333 }
334 
335 /* Get the domain ID for this domain */
xenstat_domain_id(xenstat_domain * domain)336 unsigned xenstat_domain_id(xenstat_domain * domain)
337 {
338 	return domain->id;
339 }
340 
341 /* Get the domain name for the domain */
xenstat_domain_name(xenstat_domain * domain)342 char *xenstat_domain_name(xenstat_domain * domain)
343 {
344 	return domain->name;
345 }
346 
347 /* Get information about how much CPU time has been used */
xenstat_domain_cpu_ns(xenstat_domain * domain)348 unsigned long long xenstat_domain_cpu_ns(xenstat_domain * domain)
349 {
350 	return domain->cpu_ns;
351 }
352 
353 /* Find the number of VCPUs for a domain */
xenstat_domain_num_vcpus(xenstat_domain * domain)354 unsigned int xenstat_domain_num_vcpus(xenstat_domain * domain)
355 {
356 	return domain->num_vcpus;
357 }
358 
xenstat_domain_vcpu(xenstat_domain * domain,unsigned int vcpu)359 xenstat_vcpu *xenstat_domain_vcpu(xenstat_domain * domain, unsigned int vcpu)
360 {
361 	if (vcpu < domain->num_vcpus)
362 		return &(domain->vcpus[vcpu]);
363 	return NULL;
364 }
365 
366 /* Find the current memory reservation for this domain */
xenstat_domain_cur_mem(xenstat_domain * domain)367 unsigned long long xenstat_domain_cur_mem(xenstat_domain * domain)
368 {
369 	return domain->cur_mem;
370 }
371 
372 /* Find the maximum memory reservation for this domain */
xenstat_domain_max_mem(xenstat_domain * domain)373 unsigned long long xenstat_domain_max_mem(xenstat_domain * domain)
374 {
375 	return domain->max_mem;
376 }
377 
378 /* Find the domain's SSID */
xenstat_domain_ssid(xenstat_domain * domain)379 unsigned int xenstat_domain_ssid(xenstat_domain * domain)
380 {
381 	return domain->ssid;
382 }
383 
384 /* Get domain states */
xenstat_domain_dying(xenstat_domain * domain)385 unsigned int xenstat_domain_dying(xenstat_domain * domain)
386 {
387 	return (domain->state & XEN_DOMINF_dying) == XEN_DOMINF_dying;
388 }
389 
xenstat_domain_crashed(xenstat_domain * domain)390 unsigned int xenstat_domain_crashed(xenstat_domain * domain)
391 {
392 	return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
393 	    && (((domain->state >> XEN_DOMINF_shutdownshift)
394 		 & XEN_DOMINF_shutdownmask) == SHUTDOWN_crash);
395 }
396 
xenstat_domain_shutdown(xenstat_domain * domain)397 unsigned int xenstat_domain_shutdown(xenstat_domain * domain)
398 {
399 	return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
400 	    && (((domain->state >> XEN_DOMINF_shutdownshift)
401 		 & XEN_DOMINF_shutdownmask) != SHUTDOWN_crash);
402 }
403 
xenstat_domain_paused(xenstat_domain * domain)404 unsigned int xenstat_domain_paused(xenstat_domain * domain)
405 {
406 	return (domain->state & XEN_DOMINF_paused) == XEN_DOMINF_paused;
407 }
408 
xenstat_domain_blocked(xenstat_domain * domain)409 unsigned int xenstat_domain_blocked(xenstat_domain * domain)
410 {
411 	return (domain->state & XEN_DOMINF_blocked) == XEN_DOMINF_blocked;
412 }
413 
xenstat_domain_running(xenstat_domain * domain)414 unsigned int xenstat_domain_running(xenstat_domain * domain)
415 {
416 	return (domain->state & XEN_DOMINF_running) == XEN_DOMINF_running;
417 }
418 
419 /* Get the number of networks for a given domain */
xenstat_domain_num_networks(xenstat_domain * domain)420 unsigned int xenstat_domain_num_networks(xenstat_domain * domain)
421 {
422 	return domain->num_networks;
423 }
424 
425 /* Get the network handle to obtain network stats */
xenstat_domain_network(xenstat_domain * domain,unsigned int network)426 xenstat_network *xenstat_domain_network(xenstat_domain * domain,
427 					unsigned int network)
428 {
429 	if (domain->networks && network < domain->num_networks)
430 		return &(domain->networks[network]);
431 	return NULL;
432 }
433 
434 /* Get the number of VBDs for a given domain */
xenstat_domain_num_vbds(xenstat_domain * domain)435 unsigned int xenstat_domain_num_vbds(xenstat_domain * domain)
436 {
437 	return domain->num_vbds;
438 }
439 
440 /* Get the VBD handle to obtain VBD stats */
xenstat_domain_vbd(xenstat_domain * domain,unsigned int vbd)441 xenstat_vbd *xenstat_domain_vbd(xenstat_domain * domain,
442 				unsigned int vbd)
443 {
444 	if (domain->vbds && vbd < domain->num_vbds)
445 		return &(domain->vbds[vbd]);
446 	return NULL;
447 }
448 
449 /*
450  * VCPU functions
451  */
452 /* Collect information about VCPUs */
xenstat_collect_vcpus(xenstat_node * node)453 static int xenstat_collect_vcpus(xenstat_node * node)
454 {
455 	unsigned int i, vcpu, inc_index;
456 
457 	/* Fill in VCPU information */
458 	for (i = 0; i < node->num_domains; i+=inc_index) {
459 		inc_index = 1; /* default is to increment to next domain */
460 
461 		node->domains[i].vcpus = malloc(node->domains[i].num_vcpus
462 						* sizeof(xenstat_vcpu));
463 		if (node->domains[i].vcpus == NULL)
464 			return 0;
465 
466 		for (vcpu = 0; vcpu < node->domains[i].num_vcpus; vcpu++) {
467 			/* FIXME: need to be using a more efficient mechanism*/
468 			xc_vcpuinfo_t info;
469 
470 			if (xc_vcpu_getinfo(node->handle->xc_handle,
471 					    node->domains[i].id, vcpu, &info) != 0) {
472 				if (errno == ENOMEM) {
473 					/* fatal error */
474 					return 0;
475 				}
476 				else {
477 					/* domain is in transition - remove
478 					   from list */
479 					xenstat_prune_domain(node, i);
480 
481 					/* remember not to increment index! */
482 					inc_index = 0;
483 					break;
484 				}
485 			}
486 			else {
487 				node->domains[i].vcpus[vcpu].online = info.online;
488 				node->domains[i].vcpus[vcpu].ns = info.cpu_time;
489 			}
490 		}
491 	}
492 	return 1;
493 }
494 
495 /* Free VCPU information */
xenstat_free_vcpus(xenstat_node * node)496 static void xenstat_free_vcpus(xenstat_node * node)
497 {
498 	unsigned int i;
499 	for (i = 0; i < node->num_domains; i++)
500 		free(node->domains[i].vcpus);
501 }
502 
503 /* Free VCPU information in handle - nothing to do */
xenstat_uninit_vcpus(xenstat_handle * handle)504 static void xenstat_uninit_vcpus(xenstat_handle * handle)
505 {
506 }
507 
508 /* Get VCPU online status */
xenstat_vcpu_online(xenstat_vcpu * vcpu)509 unsigned int xenstat_vcpu_online(xenstat_vcpu * vcpu)
510 {
511 	return vcpu->online;
512 }
513 
514 /* Get VCPU usage */
xenstat_vcpu_ns(xenstat_vcpu * vcpu)515 unsigned long long xenstat_vcpu_ns(xenstat_vcpu * vcpu)
516 {
517 	return vcpu->ns;
518 }
519 
520 /*
521  * Network functions
522  */
523 
524 /* Free network information */
xenstat_free_networks(xenstat_node * node)525 static void xenstat_free_networks(xenstat_node * node)
526 {
527 	unsigned int i;
528 	for (i = 0; i < node->num_domains; i++)
529 		free(node->domains[i].networks);
530 }
531 
532 /* Get the network ID */
xenstat_network_id(xenstat_network * network)533 unsigned int xenstat_network_id(xenstat_network * network)
534 {
535 	return network->id;
536 }
537 
538 /* Get the number of receive bytes */
xenstat_network_rbytes(xenstat_network * network)539 unsigned long long xenstat_network_rbytes(xenstat_network * network)
540 {
541 	return network->rbytes;
542 }
543 
544 /* Get the number of receive packets */
xenstat_network_rpackets(xenstat_network * network)545 unsigned long long xenstat_network_rpackets(xenstat_network * network)
546 {
547 	return network->rpackets;
548 }
549 
550 /* Get the number of receive errors */
xenstat_network_rerrs(xenstat_network * network)551 unsigned long long xenstat_network_rerrs(xenstat_network * network)
552 {
553 	return network->rerrs;
554 }
555 
556 /* Get the number of receive drops */
xenstat_network_rdrop(xenstat_network * network)557 unsigned long long xenstat_network_rdrop(xenstat_network * network)
558 {
559 	return network->rdrop;
560 }
561 
562 /* Get the number of transmit bytes */
xenstat_network_tbytes(xenstat_network * network)563 unsigned long long xenstat_network_tbytes(xenstat_network * network)
564 {
565 	return network->tbytes;
566 }
567 
568 /* Get the number of transmit packets */
xenstat_network_tpackets(xenstat_network * network)569 unsigned long long xenstat_network_tpackets(xenstat_network * network)
570 {
571 	return network->tpackets;
572 }
573 
574 /* Get the number of transmit errors */
xenstat_network_terrs(xenstat_network * network)575 unsigned long long xenstat_network_terrs(xenstat_network * network)
576 {
577 	return network->terrs;
578 }
579 
580 /* Get the number of transmit dropped packets */
xenstat_network_tdrop(xenstat_network * network)581 unsigned long long xenstat_network_tdrop(xenstat_network * network)
582 {
583 	return network->tdrop;
584 }
585 
586 /*
587  * Xen version functions
588  */
589 
590 /* Collect Xen version information */
xenstat_collect_xen_version(xenstat_node * node)591 static int xenstat_collect_xen_version(xenstat_node * node)
592 {
593 	long vnum = 0;
594 	xen_extraversion_t version;
595 
596 	/* Collect Xen version information if not already collected */
597 	if (node->handle->xen_version[0] == '\0') {
598 		/* Get the Xen version number and extraversion string */
599 		vnum = xc_version(node->handle->xc_handle,
600 			XENVER_version, NULL);
601 
602 		if (vnum < 0)
603 			return 0;
604 
605 		if (xc_version(node->handle->xc_handle, XENVER_extraversion,
606 			&version) < 0)
607 			return 0;
608 		/* Format the version information as a string and store it */
609 		snprintf(node->handle->xen_version, VERSION_SIZE, "%ld.%ld%s",
610 			 ((vnum >> 16) & 0xFFFF), vnum & 0xFFFF, version);
611 	}
612 
613 	return 1;
614 }
615 
616 /* Free Xen version information in node - nothing to do */
xenstat_free_xen_version(xenstat_node * node)617 static void xenstat_free_xen_version(xenstat_node * node)
618 {
619 }
620 
621 /* Free Xen version information in handle - nothing to do */
xenstat_uninit_xen_version(xenstat_handle * handle)622 static void xenstat_uninit_xen_version(xenstat_handle * handle)
623 {
624 }
625 
626 /*
627  * VBD functions
628  */
629 
630 /* Save VBD information */
xenstat_save_vbd(xenstat_domain * domain,xenstat_vbd * vbd)631 xenstat_vbd *xenstat_save_vbd(xenstat_domain *domain, xenstat_vbd *vbd)
632 {
633         xenstat_vbd *vbds = domain->vbds;
634 
635         domain->num_vbds++;
636         domain->vbds = realloc(domain->vbds,
637                                domain->num_vbds *
638                                sizeof(xenstat_vbd));
639 
640         if (domain->vbds == NULL) {
641                 domain->num_vbds = 0;
642                 free(vbds);
643         }
644         else {
645                 domain->vbds[domain->num_vbds - 1] = *vbd;
646         }
647 
648         return domain->vbds;
649 }
650 
651 /* Free VBD information */
xenstat_free_vbds(xenstat_node * node)652 static void xenstat_free_vbds(xenstat_node * node)
653 {
654 	unsigned int i;
655 	for (i = 0; i < node->num_domains; i++)
656 		free(node->domains[i].vbds);
657 }
658 
659 /* Get the back driver type  for Virtual Block Device */
xenstat_vbd_type(xenstat_vbd * vbd)660 unsigned int xenstat_vbd_type(xenstat_vbd * vbd)
661 {
662 	return vbd->back_type;
663 }
664 
665 /* Get the major number of VBD device */
xenstat_vbd_dev(xenstat_vbd * vbd)666 unsigned int xenstat_vbd_dev(xenstat_vbd * vbd)
667 {
668 	return vbd->dev;
669 }
670 
671 /* Get the number of OO(Out of) requests */
xenstat_vbd_oo_reqs(xenstat_vbd * vbd)672 unsigned long long xenstat_vbd_oo_reqs(xenstat_vbd * vbd)
673 {
674 	return vbd->oo_reqs;
675 }
676 
677 /* Get the number of READ requests */
xenstat_vbd_rd_reqs(xenstat_vbd * vbd)678 unsigned long long xenstat_vbd_rd_reqs(xenstat_vbd * vbd)
679 {
680 	return vbd->rd_reqs;
681 }
682 
683 /* Get the number of WRITE requests */
xenstat_vbd_wr_reqs(xenstat_vbd * vbd)684 unsigned long long xenstat_vbd_wr_reqs(xenstat_vbd * vbd)
685 {
686 	return vbd->wr_reqs;
687 }
688 
689 /* Get the number of READ sectors */
xenstat_vbd_rd_sects(xenstat_vbd * vbd)690 unsigned long long xenstat_vbd_rd_sects(xenstat_vbd * vbd)
691 {
692 	return vbd->rd_sects;
693 }
694 
695 /* Get the number of WRITE sectors */
xenstat_vbd_wr_sects(xenstat_vbd * vbd)696 unsigned long long xenstat_vbd_wr_sects(xenstat_vbd * vbd)
697 {
698 	return vbd->wr_sects;
699 }
700 
701 /* Returns error while getting stats (1 if error happened, 0 otherwise) */
xenstat_vbd_error(xenstat_vbd * vbd)702 bool xenstat_vbd_error(xenstat_vbd * vbd)
703 {
704 	return vbd->error;
705 }
706 
xenstat_get_domain_name(xenstat_handle * handle,unsigned int domain_id)707 static char *xenstat_get_domain_name(xenstat_handle *handle, unsigned int domain_id)
708 {
709 	char path[80];
710 
711 	snprintf(path, sizeof(path),"/local/domain/%i/name", domain_id);
712 
713 	return xs_read(handle->xshandle, XBT_NULL, path, NULL);
714 }
715 
716 /* Remove specified entry from list of domains */
xenstat_prune_domain(xenstat_node * node,unsigned int entry)717 static void xenstat_prune_domain(xenstat_node *node, unsigned int entry)
718 {
719 	/* nothing to do if array is empty or entry is beyond end */
720 	if (node->num_domains == 0 || entry >= node->num_domains)
721 		return;
722 
723 	/* decrement count of domains */
724 	node->num_domains--;
725 
726 	/* shift entries following specified entry up by one */
727 	if (entry < node->num_domains) {
728 		xenstat_domain *domain = &node->domains[entry];
729 		memmove(domain,domain+1,(node->num_domains - entry) * sizeof(xenstat_domain) );
730 	}
731 
732 	/* zero out original last entry from node -- not
733 	   strictly necessary but safer! */
734 	memset(&node->domains[node->num_domains], 0, sizeof(xenstat_domain));
735 }
736