kvm_getswapinfo.c revision 44021
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 "$Id: kvm_getswapinfo.c,v 1.5 1999/02/06 06:31:57 dillon Exp $"; 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/rlist.h> 27#include <sys/blist.h> 28 29#include <err.h> 30#include <fcntl.h> 31#include <kvm.h> 32#include <limits.h> 33#include <nlist.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <unistd.h> 38 39static struct nlist kvm_swap_nl[] = { 40 { "_swaplist" }, /* old style swap list */ 41 { "_swapblist" }, /* new radix swap list */ 42 { "_swdevt" }, /* list of swap devices and sizes */ 43 { "_nswdev" }, /* number of swap devices */ 44 { "_dmmax" }, /* maximum size of a swap block */ 45 { "" } 46}; 47 48#define NL_SWAPLIST 0 49#define NL_SWAPBLIST 1 50#define NL_SWDEVT 2 51#define NL_NSWDEV 3 52#define NL_DMMAX 4 53 54static int kvm_swap_nl_cached = 0; 55static int nswdev; 56static int unswdev; 57static int dmmax; 58static int type; 59 60static void getswapinfo_old(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 61 int flags); 62static void getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, 63 int swap_max, int flags); 64 65#define SVAR(var) __STRING(var) /* to force expansion */ 66#define KGET(idx, var) \ 67 KGET1(idx, &var, sizeof(var), SVAR(var)) 68#define KGET1(idx, p, s, msg) \ 69 KGET2(kvm_swap_nl[idx].n_value, p, s, msg) 70#define KGET2(addr, p, s, msg) \ 71 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 72 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 73#define KGETN(idx, var) \ 74 KGET1N(idx, &var, sizeof(var), SVAR(var)) 75#define KGET1N(idx, p, s, msg) \ 76 KGET2N(kvm_swap_nl[idx].n_value, p, s, msg) 77#define KGET2N(addr, p, s, msg) \ 78 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 79#define KGETRET(addr, p, s, msg) \ 80 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 81 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 82 return (0); \ 83 } 84 85int 86kvm_getswapinfo( 87 kvm_t *kd, 88 struct kvm_swap *swap_ary, 89 int swap_max, 90 int flags 91) { 92 int ti = 0; 93 94 /* 95 * clear cache 96 */ 97 if (kd == NULL) { 98 kvm_swap_nl_cached = 0; 99 return(0); 100 } 101 102 /* 103 * namelist 104 */ 105 if (kvm_swap_nl_cached == 0) { 106 struct swdevt *sw; 107 108 if (kvm_nlist(kd, kvm_swap_nl) < 0) 109 return(-1); 110 111 /* 112 * required entries 113 */ 114 115 if ( 116 kvm_swap_nl[NL_SWDEVT].n_value == 0 || 117 kvm_swap_nl[NL_NSWDEV].n_value == 0 || 118 kvm_swap_nl[NL_DMMAX].n_value == 0 119 ) { 120 return(-1); 121 } 122 123 /* 124 * get globals, type of swap 125 */ 126 127 KGET(NL_NSWDEV, nswdev); 128 KGET(NL_DMMAX, dmmax); 129 130 if (kvm_swap_nl[NL_SWAPLIST].n_type != N_UNDF) 131 type = 1; 132 133 if (kvm_swap_nl[NL_SWAPBLIST].n_type != N_UNDF) 134 type = 2; 135 136 /* 137 * figure out how many actual swap devices are enabled 138 */ 139 140 KGET(NL_SWDEVT, sw); 141 for (unswdev = nswdev - 1; unswdev >= 0; --unswdev) { 142 struct swdevt swinfo; 143 144 KGET2(&sw[unswdev], &swinfo, sizeof(swinfo), "swinfo"); 145 if (swinfo.sw_nblks) 146 break; 147 } 148 ++unswdev; 149 150 kvm_swap_nl_cached = 1; 151 } 152 153 154 { 155 struct swdevt *sw; 156 int i; 157 158 ti = unswdev; 159 if (ti >= swap_max) 160 ti = swap_max - 1; 161 162 if (ti >= 0) 163 bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1)); 164 165 KGET(NL_SWDEVT, sw); 166 for (i = 0; i < unswdev; ++i) { 167 struct swdevt swinfo; 168 int ttl; 169 170 KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo"); 171 172 /* 173 * old style: everything in DEV_BSIZE'd chunks, 174 * convert to pages. 175 * 176 * new style: swinfo in DEV_BSIZE'd chunks but dmmax 177 * in pages. 178 * 179 * The first dmmax is never allocating to avoid 180 * trashing the disklabels 181 */ 182 183 if (type == 1) 184 ttl = dbtoc(swinfo.sw_nblks - dmmax); 185 else 186 ttl = swinfo.sw_nblks - dmmax; 187 188 if (ttl == 0) 189 continue; 190 191 if (i < ti) { 192 swap_ary[i].ksw_total = ttl; 193 swap_ary[i].ksw_used = ttl; 194 swap_ary[i].ksw_flags = swinfo.sw_flags; 195 if (swinfo.sw_dev == NODEV) { 196 snprintf( 197 swap_ary[i].ksw_devname, 198 sizeof(swap_ary[i].ksw_devname), 199 "%s", 200 "[NFS swap]" 201 ); 202 } else { 203 snprintf( 204 swap_ary[i].ksw_devname, 205 sizeof(swap_ary[i].ksw_devname), 206 "%s%s", 207 ((flags & SWIF_DEV_PREFIX) ? "/dev/" : ""), 208 devname(swinfo.sw_dev, S_IFBLK) 209 ); 210 } 211 } 212 if (ti >= 0) { 213 swap_ary[ti].ksw_total += ttl; 214 swap_ary[ti].ksw_used += ttl; 215 } 216 } 217 } 218 219 switch(type) { 220 case 1: 221 getswapinfo_old(kd, swap_ary, swap_max, flags); 222 break; 223 case 2: 224 getswapinfo_radix(kd, swap_ary, swap_max, flags); 225 break; 226 default: 227 ti = -1; 228 break; 229 } 230 return(ti); 231} 232 233/* 234 * scanradix() - support routine for radix scanner 235 */ 236 237#define TABME tab, tab, "" 238 239static int 240scanradix( 241 blmeta_t *scan, 242 daddr_t blk, 243 daddr_t radix, 244 daddr_t skip, 245 daddr_t count, 246 kvm_t *kd, 247 int dmmax, 248 int nswdev, 249 struct kvm_swap *swap_ary, 250 int swap_max, 251 int tab, 252 int flags 253) { 254 blmeta_t meta; 255 int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 256 257 KGET2(scan, &meta, sizeof(meta), "blmeta_t"); 258 259 /* 260 * Terminator 261 */ 262 if (meta.bm_bighint == (daddr_t)-1) { 263 if (flags & SWIF_DUMP_TREE) { 264 printf("%*.*s(0x%06x,%d) Terminator\n", 265 TABME, 266 blk, 267 radix 268 ); 269 } 270 return(-1); 271 } 272 273 if (radix == BLIST_BMAP_RADIX) { 274 /* 275 * Leaf bitmap 276 */ 277 int i; 278 279 if (flags & SWIF_DUMP_TREE) { 280 printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n", 281 TABME, 282 blk, 283 radix, 284 (int)meta.u.bmu_bitmap, 285 meta.bm_bighint 286 ); 287 } 288 289 /* 290 * If not all allocated, count. 291 */ 292 if (meta.u.bmu_bitmap != 0) { 293 for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) { 294 /* 295 * A 0 bit means allocated 296 */ 297 if ((meta.u.bmu_bitmap & (1 << i))) { 298 int t = 0; 299 300 if (nswdev) 301 t = (blk + i) / dmmax % nswdev; 302 if (t < ti) 303 --swap_ary[t].ksw_used; 304 if (ti >= 0) 305 --swap_ary[ti].ksw_used; 306 } 307 } 308 } 309 } else if (meta.u.bmu_avail == radix) { 310 /* 311 * Meta node if all free 312 */ 313 if (flags & SWIF_DUMP_TREE) { 314 printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n", 315 TABME, 316 blk, 317 radix, 318 (int)meta.u.bmu_avail, 319 meta.bm_bighint 320 ); 321 } 322 /* 323 * Note: both dmmax and radix are powers of 2. However, dmmax 324 * may be larger then radix so use a smaller increment if 325 * necessary. 326 */ 327 { 328 int t; 329 int tinc = dmmax; 330 331 while (tinc > radix) 332 tinc >>= 1; 333 334 for (t = blk; t < blk + radix; t += tinc) { 335 int u = (nswdev) ? (t / dmmax % nswdev) : 0; 336 337 if (u < ti) 338 swap_ary[u].ksw_used -= tinc; 339 if (ti >= 0) 340 swap_ary[ti].ksw_used -= tinc; 341 } 342 } 343 } else if (meta.u.bmu_avail == 0) { 344 /* 345 * Meta node if all used 346 */ 347 if (flags & SWIF_DUMP_TREE) { 348 printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n", 349 TABME, 350 blk, 351 radix, 352 (int)meta.u.bmu_avail, 353 meta.bm_bighint 354 ); 355 } 356 } else { 357 /* 358 * Meta node if not all free 359 */ 360 int i; 361 int next_skip; 362 363 if (flags & SWIF_DUMP_TREE) { 364 printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n", 365 TABME, 366 blk, 367 radix, 368 (int)meta.u.bmu_avail, 369 meta.bm_bighint 370 ); 371 } 372 373 radix >>= BLIST_META_RADIX_SHIFT; 374 next_skip = skip >> BLIST_META_RADIX_SHIFT; 375 376 for (i = 1; i <= skip; i += next_skip) { 377 int r; 378 daddr_t vcount = (count > radix) ? radix : count; 379 380 r = scanradix( 381 &scan[i], 382 blk, 383 radix, 384 next_skip - 1, 385 vcount, 386 kd, 387 dmmax, 388 nswdev, 389 swap_ary, 390 swap_max, 391 tab + 4, 392 flags 393 ); 394 if (r < 0) 395 break; 396 blk += radix; 397 } 398 if (flags & SWIF_DUMP_TREE) { 399 printf("%*.*s}\n", TABME); 400 } 401 } 402 return(0); 403} 404 405static void 406getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 407{ 408 struct blist *swapblist = NULL; 409 struct blist blcopy = { 0 }; 410 411 KGET(NL_SWAPBLIST, swapblist); 412 413 if (swapblist == NULL) { 414 if (flags & SWIF_DUMP_TREE) 415 printf("radix tree: NULL - no swap in system\n"); 416 return; 417 } 418 419 KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist"); 420 421 if (flags & SWIF_DUMP_TREE) { 422 printf("radix tree: %d/%d/%d blocks, %dK wired\n", 423 blcopy.bl_free, 424 blcopy.bl_blocks, 425 blcopy.bl_radix, 426 (blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/ 427 1024 428 ); 429 } 430 scanradix( 431 blcopy.bl_root, 432 0, 433 blcopy.bl_radix, 434 blcopy.bl_skip, 435 blcopy.bl_rootblks, 436 kd, 437 dmmax, 438 nswdev, 439 swap_ary, 440 swap_max, 441 0, 442 flags 443 ); 444} 445 446static void 447getswapinfo_old(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 448{ 449 struct rlist *swapptr; 450 struct rlisthdr swaplist; 451 int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 452 453 KGET(NL_SWAPLIST, swaplist); 454 455 swapptr = swaplist.rlh_list; 456 457 while (swapptr) { 458 int top; 459 int bottom; 460 int next_block; 461 int t; 462 int v; 463 struct rlist head; 464 465 KGET2(swapptr, &head, sizeof(head), "swapptr"); 466 467 top = head.rl_end; 468 bottom = head.rl_start; 469 470 /* 471 * Handle interleave indexing 472 */ 473 474 while (top / dmmax != bottom / dmmax) { 475 next_block = ((bottom + dmmax) / dmmax); 476 477 t = (bottom / dmmax) % nswdev; 478 v = next_block * dmmax - bottom; 479 480 if (t < ti) 481 swap_ary[t].ksw_used -= dbtoc(v); 482 if (ti >= 0) 483 swap_ary[ti].ksw_used -= dbtoc(v); 484 485 bottom = next_block * dmmax; 486 } 487 488 t = (bottom / dmmax) % nswdev; 489 v = top - bottom + 1; 490 491 if (t < ti) 492 swap_ary[t].ksw_used -= dbtoc(v); 493 if (ti >= 0) 494 swap_ary[ti].ksw_used -= dbtoc(v); 495 496 swapptr = head.rl_next; 497 } 498} 499 500