2 * Copyright (c) 1999, Matthew Dillon. All Rights Reserved.
3 * Copyright (c) 2001, Thomas Moestl. All Rights Reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
33 #include <sys/blist.h>
34 #include <sys/sysctl.h>
36 #include <vm/swap_pager.h>
37 #include <vm/vm_param.h>
51 #include "kvm_private.h"
53 static struct nlist kvm_swap_nl
[] = {
54 { "_swtailq" }, /* list of swap devices and sizes */
55 { "_dmmax" }, /* maximum size of a swap block */
62 static int kvm_swap_nl_cached
= 0;
63 static int unswdev
; /* number of found swap dev's */
66 static int kvm_getswapinfo_kvm(kvm_t
*, struct kvm_swap
*, int, int);
67 static int kvm_getswapinfo_sysctl(kvm_t
*, struct kvm_swap
*, int, int);
68 static int nlist_init(kvm_t
*);
69 static int getsysctl(kvm_t
*, char *, void *, size_t);
71 #define KREAD(kd, addr, obj) \
72 (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
73 #define KGET(idx, var) \
74 KGET2(kvm_swap_nl[(idx)].n_value, var, kvm_swap_nl[(idx)].n_name)
75 #define KGET2(addr, var, msg) \
76 if (KREAD(kd, (u_long)(addr), (var))) { \
77 _kvm_err(kd, kd->program, "cannot read %s", msg); \
81 #define GETSWDEVNAME(dev, str, flags) \
83 strlcpy(str, "[NFS swap]", sizeof(str)); \
86 str, sizeof(str),"%s%s", \
87 ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \
88 devname(dev, S_IFCHR) \
95 struct kvm_swap
*swap_ary
,
104 kvm_swap_nl_cached
= 0;
109 return kvm_getswapinfo_sysctl(kd
, swap_ary
, swap_max
, flags
);
111 return kvm_getswapinfo_kvm(kd
, swap_ary
, swap_max
, flags
);
118 struct kvm_swap
*swap_ary
,
123 TAILQ_HEAD(, swdevt
) swtailq
;
124 struct swdevt
*sp
, swinfo
;
130 bzero(&tot
, sizeof(tot
));
131 KGET(NL_SWTAILQ
, &swtailq
);
132 sp
= TAILQ_FIRST(&swtailq
);
133 for (i
= 0; sp
!= NULL
; i
++) {
134 KGET2(sp
, &swinfo
, "swinfo");
135 ttl
= swinfo
.sw_nblks
- dmmax
;
136 if (i
< swap_max
- 1) {
137 bzero(&swap_ary
[i
], sizeof(swap_ary
[i
]));
138 swap_ary
[i
].ksw_total
= ttl
;
139 swap_ary
[i
].ksw_used
= swinfo
.sw_used
;
140 swap_ary
[i
].ksw_flags
= swinfo
.sw_flags
;
141 GETSWDEVNAME(swinfo
.sw_dev
, swap_ary
[i
].ksw_devname
,
144 tot
.ksw_total
+= ttl
;
145 tot
.ksw_used
+= swinfo
.sw_used
;
146 sp
= TAILQ_NEXT(&swinfo
, sw_list
);
157 #define GETSYSCTL(kd, name, var) \
158 getsysctl(kd, name, &(var), sizeof(var))
160 /* The maximum MIB length for vm.swap_info and an additional device number */
164 kvm_getswapinfo_sysctl(
166 struct kvm_swap
*swap_ary
,
172 int soid
[SWI_MAXMIB
];
176 if (!GETSYSCTL(kd
, "vm.dmmax", dmmax
))
179 mibi
= SWI_MAXMIB
- 1;
180 if (sysctlnametomib("vm.swap_info", soid
, &mibi
) == -1) {
181 _kvm_err(kd
, kd
->program
, "sysctlnametomib failed: %s",
185 bzero(&tot
, sizeof(tot
));
186 for (unswdev
= 0;; unswdev
++) {
187 soid
[mibi
] = unswdev
;
189 if (sysctl(soid
, mibi
+ 1, &xsd
, &len
, NULL
, 0) == -1) {
192 _kvm_err(kd
, kd
->program
, "cannot read sysctl: %s.",
196 if (len
!= sizeof(xsd
)) {
197 _kvm_err(kd
, kd
->program
, "struct xswdev has unexpected "
198 "size; kernel and libkvm out of sync?");
201 if (xsd
.xsw_version
!= XSWDEV_VERSION
) {
202 _kvm_err(kd
, kd
->program
, "struct xswdev version "
203 "mismatch; kernel and libkvm out of sync?");
207 ttl
= xsd
.xsw_nblks
- dmmax
;
208 if (unswdev
< swap_max
- 1) {
209 bzero(&swap_ary
[unswdev
], sizeof(swap_ary
[unswdev
]));
210 swap_ary
[unswdev
].ksw_total
= ttl
;
211 swap_ary
[unswdev
].ksw_used
= xsd
.xsw_used
;
212 swap_ary
[unswdev
].ksw_flags
= xsd
.xsw_flags
;
213 GETSWDEVNAME(xsd
.xsw_dev
, swap_ary
[unswdev
].ksw_devname
,
216 tot
.ksw_total
+= ttl
;
217 tot
.ksw_used
+= xsd
.xsw_used
;
230 nlist_init(kvm_t
*kd
)
232 TAILQ_HEAD(, swdevt
) swtailq
;
233 struct swdevt
*sp
, swinfo
;
235 if (kvm_swap_nl_cached
)
238 if (kvm_nlist(kd
, kvm_swap_nl
) < 0)
241 /* Required entries */
242 if (kvm_swap_nl
[NL_SWTAILQ
].n_value
== 0) {
243 _kvm_err(kd
, kd
->program
, "unable to find swtailq");
247 if (kvm_swap_nl
[NL_DMMAX
].n_value
== 0) {
248 _kvm_err(kd
, kd
->program
, "unable to find dmmax");
252 /* Get globals, type of swap */
253 KGET(NL_DMMAX
, &dmmax
);
255 kvm_swap_nl_cached
= 1;
267 if (sysctlbyname(name
, ptr
, &nlen
, NULL
, 0) == -1) {
268 _kvm_err(kd
, kd
->program
, "cannot read sysctl %s:%s", name
,
273 _kvm_err(kd
, kd
->program
, "sysctl %s has unexpected size", name
);