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