xref: /freebsd/lib/libkvm/kvm_getswapinfo.c (revision 9e749cc9c5cfca9f9258878a0af6183708585f2c)
1e92324a2SMatthew Dillon /*
2e92324a2SMatthew Dillon  * Copyright (c) 1999, Matthew Dillon.  All Rights Reserved.
39e749cc9SWarner Losh  * Copyright (c) 2001, Thomas Moestl.  All Rights Reserved.
4e92324a2SMatthew Dillon  *
5e92324a2SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
69e749cc9SWarner Losh  * modification, are permitted provided that the following conditions
79e749cc9SWarner Losh  * are met:
89e749cc9SWarner Losh  * 1. Redistributions of source code must retain the above copyright
99e749cc9SWarner Losh  *    notice, this list of conditions and the following disclaimer.
109e749cc9SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
119e749cc9SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
129e749cc9SWarner Losh  *    documentation and/or other materials provided with the distribution.
139e749cc9SWarner Losh  *
149e749cc9SWarner Losh  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
159e749cc9SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
169e749cc9SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
179e749cc9SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
189e749cc9SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199e749cc9SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
209e749cc9SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219e749cc9SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
229e749cc9SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
239e749cc9SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
249e749cc9SWarner Losh  * SUCH DAMAGE.
25e92324a2SMatthew Dillon  */
26e92324a2SMatthew Dillon 
27e67f5b9fSMatthew Dillon #include <sys/cdefs.h>
28e67f5b9fSMatthew Dillon __FBSDID("$FreeBSD$");
29e92324a2SMatthew Dillon 
30e92324a2SMatthew Dillon #include <sys/param.h>
31e92324a2SMatthew Dillon #include <sys/time.h>
32e92324a2SMatthew Dillon #include <sys/stat.h>
33e92324a2SMatthew Dillon #include <sys/blist.h>
34ae3a37adSRobert Watson #include <sys/sysctl.h>
35e92324a2SMatthew Dillon 
36e04a7c4aSThomas Moestl #include <vm/vm_param.h>
37e04a7c4aSThomas Moestl 
38e92324a2SMatthew Dillon #include <err.h>
39e04a7c4aSThomas Moestl #include <errno.h>
40e92324a2SMatthew Dillon #include <fcntl.h>
41e92324a2SMatthew Dillon #include <kvm.h>
42e92324a2SMatthew Dillon #include <nlist.h>
431a37aa56SDavid E. O'Brien #include <paths.h>
44e92324a2SMatthew Dillon #include <stdio.h>
45e92324a2SMatthew Dillon #include <stdlib.h>
46e92324a2SMatthew Dillon #include <string.h>
47e92324a2SMatthew Dillon #include <unistd.h>
48ae3a37adSRobert Watson #include <limits.h>
49ae3a37adSRobert Watson 
50ae3a37adSRobert Watson #include "kvm_private.h"
51e92324a2SMatthew Dillon 
52bf0e1ee3SPeter Wemm #define NL_SWAPBLIST	0
53bf0e1ee3SPeter Wemm #define NL_SWDEVT	1
54bf0e1ee3SPeter Wemm #define NL_NSWDEV	2
55bf0e1ee3SPeter Wemm #define NL_DMMAX	3
56e92324a2SMatthew Dillon 
57e92324a2SMatthew Dillon static int kvm_swap_nl_cached = 0;
58ae3a37adSRobert Watson static int unswdev;  /* number of found swap dev's */
59e92324a2SMatthew Dillon static int dmmax;
60e92324a2SMatthew Dillon 
61ae3a37adSRobert Watson static int  kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int);
62e04a7c4aSThomas Moestl static int  getsysctl(kvm_t *, char *, void *, size_t);
63e92324a2SMatthew Dillon 
64ae3a37adSRobert Watson #define GETSWDEVNAME(dev, str, flags)					\
65ae3a37adSRobert Watson 	if (dev == NODEV) {						\
66ae3a37adSRobert Watson 		strlcpy(str, "[NFS swap]", sizeof(str));		\
67ae3a37adSRobert Watson 	} else {							\
68ae3a37adSRobert Watson 		snprintf(						\
69ae3a37adSRobert Watson 		    str, sizeof(str),"%s%s",				\
70ae3a37adSRobert Watson 		    ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""),	\
71ae3a37adSRobert Watson 		    devname(dev, S_IFCHR)				\
72ae3a37adSRobert Watson 		);							\
73ae3a37adSRobert Watson 	}
74ae3a37adSRobert Watson 
75e92324a2SMatthew Dillon int
76e92324a2SMatthew Dillon kvm_getswapinfo(
77e92324a2SMatthew Dillon 	kvm_t *kd,
78e92324a2SMatthew Dillon 	struct kvm_swap *swap_ary,
79e92324a2SMatthew Dillon 	int swap_max,
80e92324a2SMatthew Dillon 	int flags
81e92324a2SMatthew Dillon ) {
82e92324a2SMatthew Dillon 
83e92324a2SMatthew Dillon 	/*
84e92324a2SMatthew Dillon 	 * clear cache
85e92324a2SMatthew Dillon 	 */
86e92324a2SMatthew Dillon 	if (kd == NULL) {
87e92324a2SMatthew Dillon 		kvm_swap_nl_cached = 0;
88e92324a2SMatthew Dillon 		return(0);
89e92324a2SMatthew Dillon 	}
90e92324a2SMatthew Dillon 
91ae3a37adSRobert Watson 	if (ISALIVE(kd)) {
92ae3a37adSRobert Watson 		return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags);
93ae3a37adSRobert Watson 	} else {
945d6fec5bSPoul-Henning Kamp 		return -1;
95ae3a37adSRobert Watson 	}
96ae3a37adSRobert Watson }
97ae3a37adSRobert Watson 
98ae3a37adSRobert Watson #define	GETSYSCTL(kd, name, var)					\
99ae3a37adSRobert Watson 	    getsysctl(kd, name, &(var), sizeof(var))
100e04a7c4aSThomas Moestl 
101e04a7c4aSThomas Moestl /* The maximum MIB length for vm.swap_info and an additional device number */
102e04a7c4aSThomas Moestl #define	SWI_MAXMIB	3
103ae3a37adSRobert Watson 
104ae3a37adSRobert Watson int
105ae3a37adSRobert Watson kvm_getswapinfo_sysctl(
106ae3a37adSRobert Watson 	kvm_t *kd,
107ae3a37adSRobert Watson 	struct kvm_swap *swap_ary,
108ae3a37adSRobert Watson 	int swap_max,
109ae3a37adSRobert Watson 	int flags
110ae3a37adSRobert Watson ) {
111e04a7c4aSThomas Moestl 	int ti, ttl;
112e04a7c4aSThomas Moestl 	size_t mibi, len;
113e04a7c4aSThomas Moestl 	int soid[SWI_MAXMIB];
114e04a7c4aSThomas Moestl 	struct xswdev xsd;
115e04a7c4aSThomas Moestl 	struct kvm_swap tot;
116ae3a37adSRobert Watson 
117ae3a37adSRobert Watson 	if (!GETSYSCTL(kd, "vm.dmmax", dmmax))
118ae3a37adSRobert Watson 		return -1;
119ae3a37adSRobert Watson 
120e04a7c4aSThomas Moestl 	mibi = SWI_MAXMIB - 1;
121e04a7c4aSThomas Moestl 	if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
122e04a7c4aSThomas Moestl 		_kvm_err(kd, kd->program, "sysctlnametomib failed: %s",
123e04a7c4aSThomas Moestl 		    strerror(errno));
124e04a7c4aSThomas Moestl 		return -1;
125e04a7c4aSThomas Moestl 	}
126e04a7c4aSThomas Moestl 	bzero(&tot, sizeof(tot));
127e04a7c4aSThomas Moestl 	for (unswdev = 0;; unswdev++) {
128e04a7c4aSThomas Moestl 		soid[mibi] = unswdev;
129e04a7c4aSThomas Moestl 		len = sizeof(xsd);
130e04a7c4aSThomas Moestl 		if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
131e04a7c4aSThomas Moestl 			if (errno == ENOENT)
132e04a7c4aSThomas Moestl 				break;
133e04a7c4aSThomas Moestl 			_kvm_err(kd, kd->program, "cannot read sysctl: %s.",
134e04a7c4aSThomas Moestl 			    strerror(errno));
135e04a7c4aSThomas Moestl 			return -1;
136e04a7c4aSThomas Moestl 		}
137e04a7c4aSThomas Moestl 		if (len != sizeof(xsd)) {
138e04a7c4aSThomas Moestl 			_kvm_err(kd, kd->program, "struct xswdev has unexpected "
139e04a7c4aSThomas Moestl 			    "size;  kernel and libkvm out of sync?");
140e04a7c4aSThomas Moestl 			return -1;
141e04a7c4aSThomas Moestl 		}
142e04a7c4aSThomas Moestl 		if (xsd.xsw_version != XSWDEV_VERSION) {
143e04a7c4aSThomas Moestl 			_kvm_err(kd, kd->program, "struct xswdev version "
144e04a7c4aSThomas Moestl 			    "mismatch; kernel and libkvm out of sync?");
145ae3a37adSRobert Watson 			return -1;
146ae3a37adSRobert Watson 		}
147ae3a37adSRobert Watson 
148e04a7c4aSThomas Moestl 		ttl = xsd.xsw_nblks - dmmax;
149e04a7c4aSThomas Moestl 		if (unswdev < swap_max - 1) {
150e04a7c4aSThomas Moestl 			bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
151e04a7c4aSThomas Moestl 			swap_ary[unswdev].ksw_total = ttl;
152e04a7c4aSThomas Moestl 			swap_ary[unswdev].ksw_used = xsd.xsw_used;
153e04a7c4aSThomas Moestl 			swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
154e04a7c4aSThomas Moestl 			GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname,
155e04a7c4aSThomas Moestl 			     flags);
156e04a7c4aSThomas Moestl 		}
157e04a7c4aSThomas Moestl 		tot.ksw_total += ttl;
158e04a7c4aSThomas Moestl 		tot.ksw_used += xsd.xsw_used;
159e04a7c4aSThomas Moestl 	}
160ae3a37adSRobert Watson 
161e04a7c4aSThomas Moestl 	ti = unswdev;
162e04a7c4aSThomas Moestl 	if (ti >= swap_max)
163e04a7c4aSThomas Moestl 		ti = swap_max - 1;
164e04a7c4aSThomas Moestl 	if (ti >= 0)
165e04a7c4aSThomas Moestl 		swap_ary[ti] = tot;
166ae3a37adSRobert Watson 
167ae3a37adSRobert Watson         return(ti);
168ae3a37adSRobert Watson }
169ae3a37adSRobert Watson 
170ae3a37adSRobert Watson static int
171ae3a37adSRobert Watson getsysctl (
172ae3a37adSRobert Watson 	kvm_t *kd,
173ae3a37adSRobert Watson 	char *name,
174ae3a37adSRobert Watson 	void *ptr,
175e04a7c4aSThomas Moestl 	size_t len
176ae3a37adSRobert Watson ) {
177e04a7c4aSThomas Moestl 	size_t nlen = len;
178ae3a37adSRobert Watson 	if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
179e04a7c4aSThomas Moestl 		_kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name,
180e04a7c4aSThomas Moestl 		    strerror(errno));
181ae3a37adSRobert Watson 		return (0);
182ae3a37adSRobert Watson 	}
183ae3a37adSRobert Watson 	if (nlen != len) {
184ae3a37adSRobert Watson 		_kvm_err(kd, kd->program, "sysctl %s has unexpected size", name);
185ae3a37adSRobert Watson 		return (0);
186ae3a37adSRobert Watson 	}
187ae3a37adSRobert Watson 	return (1);
188ae3a37adSRobert Watson }
189