kvm_getswapinfo.c revision 58642
1/* 2 * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided under the terms of the BSD 6 * Copyright as found in /usr/src/COPYRIGHT in the FreeBSD source tree. 7 */ 8 9#ifndef lint 10static const char copyright[] = 11 "@(#) Copyright (c) 1999\n" 12 "Matthew Dillon. All rights reserved.\n"; 13#endif /* not lint */ 14 15#ifndef lint 16static const char rcsid[] = 17 "$FreeBSD: head/lib/libkvm/kvm_getswapinfo.c 58642 2000-03-27 00:33:45Z obrien $"; 18#endif /* not lint */ 19 20#include <sys/param.h> 21#include <sys/time.h> 22#include <sys/vnode.h> 23#include <sys/ucred.h> 24#include <sys/stat.h> 25#include <sys/conf.h> 26#include <sys/blist.h> 27 28#include <err.h> 29#include <fcntl.h> 30#include <kvm.h> 31#include <nlist.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <unistd.h> 36 37static struct nlist kvm_swap_nl[] = { 38 { "_swapblist" }, /* new radix swap list */ 39 { "_swdevt" }, /* list of swap devices and sizes */ 40 { "_nswdev" }, /* number of swap devices */ 41 { "_dmmax" }, /* maximum size of a swap block */ 42 { "" } 43}; 44 45#define NL_SWAPBLIST 0 46#define NL_SWDEVT 1 47#define NL_NSWDEV 2 48#define NL_DMMAX 3 49 50static int kvm_swap_nl_cached = 0; 51static int nswdev; 52static int unswdev; 53static int dmmax; 54 55static void getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, 56 int swap_max, int flags); 57 58#define SVAR(var) __STRING(var) /* to force expansion */ 59#define KGET(idx, var) \ 60 KGET1(idx, &var, sizeof(var), SVAR(var)) 61#define KGET1(idx, p, s, msg) \ 62 KGET2(kvm_swap_nl[idx].n_value, p, s, msg) 63#define KGET2(addr, p, s, msg) \ 64 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 65 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 66#define KGETN(idx, var) \ 67 KGET1N(idx, &var, sizeof(var), SVAR(var)) 68#define KGET1N(idx, p, s, msg) \ 69 KGET2N(kvm_swap_nl[idx].n_value, p, s, msg) 70#define KGET2N(addr, p, s, msg) \ 71 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 72#define KGETRET(addr, p, s, msg) \ 73 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 74 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 75 return (0); \ 76 } 77 78int 79kvm_getswapinfo( 80 kvm_t *kd, 81 struct kvm_swap *swap_ary, 82 int swap_max, 83 int flags 84) { 85 int ti = 0; 86 87 /* 88 * clear cache 89 */ 90 if (kd == NULL) { 91 kvm_swap_nl_cached = 0; 92 return(0); 93 } 94 95 /* 96 * namelist 97 */ 98 if (kvm_swap_nl_cached == 0) { 99 struct swdevt *sw; 100 101 if (kvm_nlist(kd, kvm_swap_nl) < 0) 102 return(-1); 103 104 /* 105 * required entries 106 */ 107 108 if ( 109 kvm_swap_nl[NL_SWDEVT].n_value == 0 || 110 kvm_swap_nl[NL_NSWDEV].n_value == 0 || 111 kvm_swap_nl[NL_DMMAX].n_value == 0 || 112 kvm_swap_nl[NL_SWAPBLIST].n_type == 0 113 ) { 114 return(-1); 115 } 116 117 /* 118 * get globals, type of swap 119 */ 120 121 KGET(NL_NSWDEV, nswdev); 122 KGET(NL_DMMAX, dmmax); 123 124 /* 125 * figure out how many actual swap devices are enabled 126 */ 127 128 KGET(NL_SWDEVT, sw); 129 for (unswdev = nswdev - 1; unswdev >= 0; --unswdev) { 130 struct swdevt swinfo; 131 132 KGET2(&sw[unswdev], &swinfo, sizeof(swinfo), "swinfo"); 133 if (swinfo.sw_nblks) 134 break; 135 } 136 ++unswdev; 137 138 kvm_swap_nl_cached = 1; 139 } 140 141 142 { 143 struct swdevt *sw; 144 int i; 145 146 ti = unswdev; 147 if (ti >= swap_max) 148 ti = swap_max - 1; 149 150 if (ti >= 0) 151 bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1)); 152 153 KGET(NL_SWDEVT, sw); 154 for (i = 0; i < unswdev; ++i) { 155 struct swdevt swinfo; 156 int ttl; 157 158 KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo"); 159 160 /* 161 * old style: everything in DEV_BSIZE'd chunks, 162 * convert to pages. 163 * 164 * new style: swinfo in DEV_BSIZE'd chunks but dmmax 165 * in pages. 166 * 167 * The first dmmax is never allocating to avoid 168 * trashing the disklabels 169 */ 170 171 ttl = swinfo.sw_nblks - dmmax; 172 173 if (ttl == 0) 174 continue; 175 176 if (i < ti) { 177 swap_ary[i].ksw_total = ttl; 178 swap_ary[i].ksw_used = ttl; 179 swap_ary[i].ksw_flags = swinfo.sw_flags; 180 if (swinfo.sw_dev == NODEV) { 181 snprintf( 182 swap_ary[i].ksw_devname, 183 sizeof(swap_ary[i].ksw_devname), 184 "%s", 185 "[NFS swap]" 186 ); 187 } else { 188 snprintf( 189 swap_ary[i].ksw_devname, 190 sizeof(swap_ary[i].ksw_devname), 191 "%s%s", 192 ((flags & SWIF_DEV_PREFIX) ? "/dev/" : ""), 193 devname(swinfo.sw_dev, S_IFCHR) 194 ); 195 } 196 } 197 if (ti >= 0) { 198 swap_ary[ti].ksw_total += ttl; 199 swap_ary[ti].ksw_used += ttl; 200 } 201 } 202 } 203 204 getswapinfo_radix(kd, swap_ary, swap_max, flags); 205 return(ti); 206} 207 208/* 209 * scanradix() - support routine for radix scanner 210 */ 211 212#define TABME tab, tab, "" 213 214static int 215scanradix( 216 blmeta_t *scan, 217 daddr_t blk, 218 daddr_t radix, 219 daddr_t skip, 220 daddr_t count, 221 kvm_t *kd, 222 int dmmax, 223 int nswdev, 224 struct kvm_swap *swap_ary, 225 int swap_max, 226 int tab, 227 int flags 228) { 229 blmeta_t meta; 230 int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 231 232 KGET2(scan, &meta, sizeof(meta), "blmeta_t"); 233 234 /* 235 * Terminator 236 */ 237 if (meta.bm_bighint == (daddr_t)-1) { 238 if (flags & SWIF_DUMP_TREE) { 239 printf("%*.*s(0x%06x,%d) Terminator\n", 240 TABME, 241 blk, 242 radix 243 ); 244 } 245 return(-1); 246 } 247 248 if (radix == BLIST_BMAP_RADIX) { 249 /* 250 * Leaf bitmap 251 */ 252 int i; 253 254 if (flags & SWIF_DUMP_TREE) { 255 printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n", 256 TABME, 257 blk, 258 radix, 259 (int)meta.u.bmu_bitmap, 260 meta.bm_bighint 261 ); 262 } 263 264 /* 265 * If not all allocated, count. 266 */ 267 if (meta.u.bmu_bitmap != 0) { 268 for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) { 269 /* 270 * A 0 bit means allocated 271 */ 272 if ((meta.u.bmu_bitmap & (1 << i))) { 273 int t = 0; 274 275 if (nswdev) 276 t = (blk + i) / dmmax % nswdev; 277 if (t < ti) 278 --swap_ary[t].ksw_used; 279 if (ti >= 0) 280 --swap_ary[ti].ksw_used; 281 } 282 } 283 } 284 } else if (meta.u.bmu_avail == radix) { 285 /* 286 * Meta node if all free 287 */ 288 if (flags & SWIF_DUMP_TREE) { 289 printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n", 290 TABME, 291 blk, 292 radix 293 ); 294 } 295 /* 296 * Note: both dmmax and radix are powers of 2. However, dmmax 297 * may be larger then radix so use a smaller increment if 298 * necessary. 299 */ 300 { 301 int t; 302 int tinc = dmmax; 303 304 while (tinc > radix) 305 tinc >>= 1; 306 307 for (t = blk; t < blk + radix; t += tinc) { 308 int u = (nswdev) ? (t / dmmax % nswdev) : 0; 309 310 if (u < ti) 311 swap_ary[u].ksw_used -= tinc; 312 if (ti >= 0) 313 swap_ary[ti].ksw_used -= tinc; 314 } 315 } 316 } else if (meta.u.bmu_avail == 0) { 317 /* 318 * Meta node if all used 319 */ 320 if (flags & SWIF_DUMP_TREE) { 321 printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n", 322 TABME, 323 blk, 324 radix 325 ); 326 } 327 } else { 328 /* 329 * Meta node if not all free 330 */ 331 int i; 332 int next_skip; 333 334 if (flags & SWIF_DUMP_TREE) { 335 printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n", 336 TABME, 337 blk, 338 radix, 339 (int)meta.u.bmu_avail, 340 meta.bm_bighint 341 ); 342 } 343 344 radix >>= BLIST_META_RADIX_SHIFT; 345 next_skip = skip >> BLIST_META_RADIX_SHIFT; 346 347 for (i = 1; i <= skip; i += next_skip) { 348 int r; 349 daddr_t vcount = (count > radix) ? radix : count; 350 351 r = scanradix( 352 &scan[i], 353 blk, 354 radix, 355 next_skip - 1, 356 vcount, 357 kd, 358 dmmax, 359 nswdev, 360 swap_ary, 361 swap_max, 362 tab + 4, 363 flags 364 ); 365 if (r < 0) 366 break; 367 blk += radix; 368 } 369 if (flags & SWIF_DUMP_TREE) { 370 printf("%*.*s}\n", TABME); 371 } 372 } 373 return(0); 374} 375 376static void 377getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 378{ 379 struct blist *swapblist = NULL; 380 struct blist blcopy = { 0 }; 381 382 KGET(NL_SWAPBLIST, swapblist); 383 384 if (swapblist == NULL) { 385 if (flags & SWIF_DUMP_TREE) 386 printf("radix tree: NULL - no swap in system\n"); 387 return; 388 } 389 390 KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist"); 391 392 if (flags & SWIF_DUMP_TREE) { 393 printf("radix tree: %d/%d/%d blocks, %dK wired\n", 394 blcopy.bl_free, 395 blcopy.bl_blocks, 396 blcopy.bl_radix, 397 (int)((blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/ 398 1024) 399 ); 400 } 401 scanradix( 402 blcopy.bl_root, 403 0, 404 blcopy.bl_radix, 405 blcopy.bl_skip, 406 blcopy.bl_rootblks, 407 kd, 408 dmmax, 409 nswdev, 410 swap_ary, 411 swap_max, 412 0, 413 flags 414 ); 415} 416