1e92324a2SMatthew Dillon /* 2e92324a2SMatthew Dillon * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 3ae3a37adSRobert Watson * Copyright (c) 2001, Thomas Moestl 4e92324a2SMatthew Dillon * 5e92324a2SMatthew Dillon * Redistribution and use in source and binary forms, with or without 6e92324a2SMatthew Dillon * modification, are permitted provided under the terms of the BSD 7e92324a2SMatthew Dillon * Copyright as found in /usr/src/COPYRIGHT in the FreeBSD source tree. 8e92324a2SMatthew Dillon */ 9e92324a2SMatthew Dillon 10e92324a2SMatthew Dillon #ifndef lint 11e92324a2SMatthew Dillon static const char copyright[] = 12e92324a2SMatthew Dillon "@(#) Copyright (c) 1999\n" 13e92324a2SMatthew Dillon "Matthew Dillon. All rights reserved.\n"; 14e92324a2SMatthew Dillon #endif /* not lint */ 15e92324a2SMatthew Dillon 16e92324a2SMatthew Dillon #ifndef lint 17e92324a2SMatthew Dillon static const char rcsid[] = 187f3dea24SPeter Wemm "$FreeBSD$"; 19e92324a2SMatthew Dillon #endif /* not lint */ 20e92324a2SMatthew Dillon 21e92324a2SMatthew Dillon #include <sys/param.h> 2282633431SMark Murray #include <sys/lock.h> 2382633431SMark Murray #include <sys/mutex.h> 24e92324a2SMatthew Dillon #include <sys/time.h> 25e92324a2SMatthew Dillon #include <sys/stat.h> 26e92324a2SMatthew Dillon #include <sys/conf.h> 27e92324a2SMatthew Dillon #include <sys/blist.h> 28ae3a37adSRobert Watson #include <sys/sysctl.h> 29e92324a2SMatthew Dillon 30e04a7c4aSThomas Moestl #include <vm/vm_param.h> 31e04a7c4aSThomas Moestl 32e92324a2SMatthew Dillon #include <err.h> 33e04a7c4aSThomas Moestl #include <errno.h> 34e92324a2SMatthew Dillon #include <fcntl.h> 35e92324a2SMatthew Dillon #include <kvm.h> 36e92324a2SMatthew Dillon #include <nlist.h> 371a37aa56SDavid E. O'Brien #include <paths.h> 38e92324a2SMatthew Dillon #include <stdio.h> 39e92324a2SMatthew Dillon #include <stdlib.h> 40e92324a2SMatthew Dillon #include <string.h> 41e92324a2SMatthew Dillon #include <unistd.h> 42ae3a37adSRobert Watson #include <limits.h> 43ae3a37adSRobert Watson 44ae3a37adSRobert Watson #include "kvm_private.h" 45e92324a2SMatthew Dillon 46e92324a2SMatthew Dillon static struct nlist kvm_swap_nl[] = { 47e92324a2SMatthew Dillon { "_swapblist" }, /* new radix swap list */ 48e92324a2SMatthew Dillon { "_swdevt" }, /* list of swap devices and sizes */ 49e92324a2SMatthew Dillon { "_nswdev" }, /* number of swap devices */ 50e92324a2SMatthew Dillon { "_dmmax" }, /* maximum size of a swap block */ 51e92324a2SMatthew Dillon { "" } 52e92324a2SMatthew Dillon }; 53e92324a2SMatthew Dillon 54bf0e1ee3SPeter Wemm #define NL_SWAPBLIST 0 55bf0e1ee3SPeter Wemm #define NL_SWDEVT 1 56bf0e1ee3SPeter Wemm #define NL_NSWDEV 2 57bf0e1ee3SPeter Wemm #define NL_DMMAX 3 58e92324a2SMatthew Dillon 59e92324a2SMatthew Dillon static int kvm_swap_nl_cached = 0; 60e92324a2SMatthew Dillon static int nswdev; 61ae3a37adSRobert Watson static int unswdev; /* number of found swap dev's */ 62e92324a2SMatthew Dillon static int dmmax; 63e92324a2SMatthew Dillon 6445908a6aSBruce Evans static void getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, 6545908a6aSBruce Evans int swap_max, int flags); 66ae3a37adSRobert Watson static int kvm_getswapinfo2(kvm_t *kd, struct kvm_swap *swap_ary, 67ae3a37adSRobert Watson int swap_max, int flags); 68ae3a37adSRobert Watson static int kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int); 69ae3a37adSRobert Watson static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); 70ae3a37adSRobert Watson static int nlist_init(kvm_t *); 71e04a7c4aSThomas Moestl static int getsysctl(kvm_t *, char *, void *, size_t); 72e92324a2SMatthew Dillon 73e92324a2SMatthew Dillon #define SVAR(var) __STRING(var) /* to force expansion */ 74e92324a2SMatthew Dillon #define KGET(idx, var) \ 75e92324a2SMatthew Dillon KGET1(idx, &var, sizeof(var), SVAR(var)) 76e92324a2SMatthew Dillon #define KGET1(idx, p, s, msg) \ 77e92324a2SMatthew Dillon KGET2(kvm_swap_nl[idx].n_value, p, s, msg) 78e92324a2SMatthew Dillon #define KGET2(addr, p, s, msg) \ 79e92324a2SMatthew Dillon if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 80e92324a2SMatthew Dillon warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 81e92324a2SMatthew Dillon #define KGETN(idx, var) \ 82e92324a2SMatthew Dillon KGET1N(idx, &var, sizeof(var), SVAR(var)) 83e92324a2SMatthew Dillon #define KGET1N(idx, p, s, msg) \ 84e92324a2SMatthew Dillon KGET2N(kvm_swap_nl[idx].n_value, p, s, msg) 85e92324a2SMatthew Dillon #define KGET2N(addr, p, s, msg) \ 86e92324a2SMatthew Dillon ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 87e92324a2SMatthew Dillon #define KGETRET(addr, p, s, msg) \ 88e92324a2SMatthew Dillon if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 89e92324a2SMatthew Dillon warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 90e92324a2SMatthew Dillon return (0); \ 91e92324a2SMatthew Dillon } 92e92324a2SMatthew Dillon 93ae3a37adSRobert Watson #define GETSWDEVNAME(dev, str, flags) \ 94ae3a37adSRobert Watson if (dev == NODEV) { \ 95ae3a37adSRobert Watson strlcpy(str, "[NFS swap]", sizeof(str)); \ 96ae3a37adSRobert Watson } else { \ 97ae3a37adSRobert Watson snprintf( \ 98ae3a37adSRobert Watson str, sizeof(str),"%s%s", \ 99ae3a37adSRobert Watson ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \ 100ae3a37adSRobert Watson devname(dev, S_IFCHR) \ 101ae3a37adSRobert Watson ); \ 102ae3a37adSRobert Watson } 103ae3a37adSRobert Watson 104e92324a2SMatthew Dillon int 105e92324a2SMatthew Dillon kvm_getswapinfo( 106e92324a2SMatthew Dillon kvm_t *kd, 107e92324a2SMatthew Dillon struct kvm_swap *swap_ary, 108e92324a2SMatthew Dillon int swap_max, 109e92324a2SMatthew Dillon int flags 110e92324a2SMatthew Dillon ) { 111ae3a37adSRobert Watson int rv; 112ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 113ae3a37adSRobert Watson int i; 114ae3a37adSRobert Watson #endif 115e92324a2SMatthew Dillon 116e92324a2SMatthew Dillon /* 117e92324a2SMatthew Dillon * clear cache 118e92324a2SMatthew Dillon */ 119e92324a2SMatthew Dillon if (kd == NULL) { 120e92324a2SMatthew Dillon kvm_swap_nl_cached = 0; 121e92324a2SMatthew Dillon return(0); 122e92324a2SMatthew Dillon } 123e92324a2SMatthew Dillon 124ae3a37adSRobert Watson rv = kvm_getswapinfo2(kd, swap_ary, swap_max, flags); 125ae3a37adSRobert Watson 126ae3a37adSRobert Watson /* This is only called when the tree shall be dumped. It needs kvm. */ 127ae3a37adSRobert Watson if (flags & SWIF_DUMP_TREE) { 128ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 129ae3a37adSRobert Watson /* 130ae3a37adSRobert Watson * sanity check: Sizes must be equal - used field must be 131ae3a37adSRobert Watson * 0 after this. Fill it with total-used before, where 132ae3a37adSRobert Watson * getswapinfo_radix will subtrat total-used. 133ae3a37adSRobert Watson * This will of course only work if there is no swap activity 134ae3a37adSRobert Watson * while we are working, so this code is normally not active. 135ae3a37adSRobert Watson */ 136ae3a37adSRobert Watson for (i = 0; i < unswdev; i++) { 137ae3a37adSRobert Watson swap_ary[i].ksw_used = swap_ary[i].ksw_total - 138ae3a37adSRobert Watson swap_ary[i].ksw_used; 139ae3a37adSRobert Watson } 140ae3a37adSRobert Watson #endif 141ae3a37adSRobert Watson getswapinfo_radix(kd, swap_ary, swap_max, flags); 142ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 143ae3a37adSRobert Watson for (i = 0; i < unswdev; i++) { 144ae3a37adSRobert Watson if (swap_ary[i].ksw_used != 0) { 145ae3a37adSRobert Watson fprintf(stderr, "kvm_getswapinfo: swap size " 146ae3a37adSRobert Watson "mismatch (%d blocks)!\n", 147ae3a37adSRobert Watson swap_ary[i].ksw_used 148ae3a37adSRobert Watson ); 149ae3a37adSRobert Watson } 150ae3a37adSRobert Watson } 151ae3a37adSRobert Watson /* This is fast enough now, so just do it again. */ 152ae3a37adSRobert Watson rv = kvm_getswapinfo2(kd, swap_ary, swap_max, flags); 153ae3a37adSRobert Watson #endif 154ae3a37adSRobert Watson } 155ae3a37adSRobert Watson 156ae3a37adSRobert Watson return rv; 157ae3a37adSRobert Watson } 158ae3a37adSRobert Watson 159ae3a37adSRobert Watson static int 160ae3a37adSRobert Watson kvm_getswapinfo2( 161ae3a37adSRobert Watson kvm_t *kd, 162ae3a37adSRobert Watson struct kvm_swap *swap_ary, 163ae3a37adSRobert Watson int swap_max, 164ae3a37adSRobert Watson int flags 165ae3a37adSRobert Watson ) { 166ae3a37adSRobert Watson if (ISALIVE(kd)) { 167ae3a37adSRobert Watson return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); 168ae3a37adSRobert Watson } else { 169ae3a37adSRobert Watson return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags); 170ae3a37adSRobert Watson } 171ae3a37adSRobert Watson } 172ae3a37adSRobert Watson 173ae3a37adSRobert Watson int 174ae3a37adSRobert Watson kvm_getswapinfo_kvm( 175ae3a37adSRobert Watson kvm_t *kd, 176ae3a37adSRobert Watson struct kvm_swap *swap_ary, 177ae3a37adSRobert Watson int swap_max, 178ae3a37adSRobert Watson int flags 179ae3a37adSRobert Watson ) { 180ae3a37adSRobert Watson int ti = 0; 181ae3a37adSRobert Watson 182e92324a2SMatthew Dillon /* 183e92324a2SMatthew Dillon * namelist 184e92324a2SMatthew Dillon */ 185ae3a37adSRobert Watson if (!nlist_init(kd)) 186e92324a2SMatthew Dillon return (-1); 187e92324a2SMatthew Dillon 188e92324a2SMatthew Dillon { 189e92324a2SMatthew Dillon struct swdevt *sw; 190e92324a2SMatthew Dillon int i; 191e92324a2SMatthew Dillon 192e92324a2SMatthew Dillon ti = unswdev; 193e92324a2SMatthew Dillon if (ti >= swap_max) 194e92324a2SMatthew Dillon ti = swap_max - 1; 195e92324a2SMatthew Dillon 196e92324a2SMatthew Dillon if (ti >= 0) 197e92324a2SMatthew Dillon bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1)); 198e92324a2SMatthew Dillon 199e92324a2SMatthew Dillon KGET(NL_SWDEVT, sw); 200e92324a2SMatthew Dillon for (i = 0; i < unswdev; ++i) { 201e92324a2SMatthew Dillon struct swdevt swinfo; 202e92324a2SMatthew Dillon int ttl; 203e92324a2SMatthew Dillon 204e92324a2SMatthew Dillon KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo"); 205e92324a2SMatthew Dillon 206e92324a2SMatthew Dillon /* 207e92324a2SMatthew Dillon * old style: everything in DEV_BSIZE'd chunks, 208e92324a2SMatthew Dillon * convert to pages. 209e92324a2SMatthew Dillon * 210e92324a2SMatthew Dillon * new style: swinfo in DEV_BSIZE'd chunks but dmmax 211e92324a2SMatthew Dillon * in pages. 212bd54ec1eSDmitrij Tejblum * 213bd54ec1eSDmitrij Tejblum * The first dmmax is never allocating to avoid 214bd54ec1eSDmitrij Tejblum * trashing the disklabels 215e92324a2SMatthew Dillon */ 216e92324a2SMatthew Dillon 217bd54ec1eSDmitrij Tejblum ttl = swinfo.sw_nblks - dmmax; 218e92324a2SMatthew Dillon 219e92324a2SMatthew Dillon if (ttl == 0) 220e92324a2SMatthew Dillon continue; 221e92324a2SMatthew Dillon 222e92324a2SMatthew Dillon if (i < ti) { 223e92324a2SMatthew Dillon swap_ary[i].ksw_total = ttl; 224ae3a37adSRobert Watson swap_ary[i].ksw_used = swinfo.sw_used; 225e92324a2SMatthew Dillon swap_ary[i].ksw_flags = swinfo.sw_flags; 226ae3a37adSRobert Watson GETSWDEVNAME(swinfo.sw_dev, 227ae3a37adSRobert Watson swap_ary[i].ksw_devname, flags 228e92324a2SMatthew Dillon ); 229e92324a2SMatthew Dillon } 230e92324a2SMatthew Dillon if (ti >= 0) { 231e92324a2SMatthew Dillon swap_ary[ti].ksw_total += ttl; 232ae3a37adSRobert Watson swap_ary[ti].ksw_used += swinfo.sw_used; 233e92324a2SMatthew Dillon } 234e92324a2SMatthew Dillon } 235e92324a2SMatthew Dillon } 236e92324a2SMatthew Dillon 237e92324a2SMatthew Dillon return(ti); 238e92324a2SMatthew Dillon } 239e92324a2SMatthew Dillon 240e92324a2SMatthew Dillon /* 241e92324a2SMatthew Dillon * scanradix() - support routine for radix scanner 242e92324a2SMatthew Dillon */ 243e92324a2SMatthew Dillon 244e92324a2SMatthew Dillon #define TABME tab, tab, "" 245e92324a2SMatthew Dillon 246e92324a2SMatthew Dillon static int 247e92324a2SMatthew Dillon scanradix( 248e92324a2SMatthew Dillon blmeta_t *scan, 249e92324a2SMatthew Dillon daddr_t blk, 250e92324a2SMatthew Dillon daddr_t radix, 251e92324a2SMatthew Dillon daddr_t skip, 252e92324a2SMatthew Dillon daddr_t count, 253e92324a2SMatthew Dillon kvm_t *kd, 254e92324a2SMatthew Dillon int dmmax, 255e92324a2SMatthew Dillon int nswdev, 25645908a6aSBruce Evans struct kvm_swap *swap_ary, 257e92324a2SMatthew Dillon int swap_max, 258e92324a2SMatthew Dillon int tab, 259e92324a2SMatthew Dillon int flags 260e92324a2SMatthew Dillon ) { 261e92324a2SMatthew Dillon blmeta_t meta; 262ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 263e92324a2SMatthew Dillon int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 264ae3a37adSRobert Watson #endif 265e92324a2SMatthew Dillon 266e92324a2SMatthew Dillon KGET2(scan, &meta, sizeof(meta), "blmeta_t"); 267e92324a2SMatthew Dillon 268e92324a2SMatthew Dillon /* 269e92324a2SMatthew Dillon * Terminator 270e92324a2SMatthew Dillon */ 271e92324a2SMatthew Dillon if (meta.bm_bighint == (daddr_t)-1) { 272e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 273e92324a2SMatthew Dillon printf("%*.*s(0x%06x,%d) Terminator\n", 274e92324a2SMatthew Dillon TABME, 275e92324a2SMatthew Dillon blk, 276e92324a2SMatthew Dillon radix 277e92324a2SMatthew Dillon ); 278e92324a2SMatthew Dillon } 279e92324a2SMatthew Dillon return(-1); 280e92324a2SMatthew Dillon } 281e92324a2SMatthew Dillon 282e92324a2SMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 283e92324a2SMatthew Dillon /* 284e92324a2SMatthew Dillon * Leaf bitmap 285e92324a2SMatthew Dillon */ 286ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 287e92324a2SMatthew Dillon int i; 288ae3a37adSRobert Watson #endif 289e92324a2SMatthew Dillon 290e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 291e92324a2SMatthew Dillon printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n", 292e92324a2SMatthew Dillon TABME, 293e92324a2SMatthew Dillon blk, 294e92324a2SMatthew Dillon radix, 295e92324a2SMatthew Dillon (int)meta.u.bmu_bitmap, 296e92324a2SMatthew Dillon meta.bm_bighint 297e92324a2SMatthew Dillon ); 298e92324a2SMatthew Dillon } 299e92324a2SMatthew Dillon 300ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 301e92324a2SMatthew Dillon /* 302e92324a2SMatthew Dillon * If not all allocated, count. 303e92324a2SMatthew Dillon */ 304e92324a2SMatthew Dillon if (meta.u.bmu_bitmap != 0) { 305e92324a2SMatthew Dillon for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) { 306e92324a2SMatthew Dillon /* 307e92324a2SMatthew Dillon * A 0 bit means allocated 308e92324a2SMatthew Dillon */ 309e92324a2SMatthew Dillon if ((meta.u.bmu_bitmap & (1 << i))) { 310e92324a2SMatthew Dillon int t = 0; 311e92324a2SMatthew Dillon 312e92324a2SMatthew Dillon if (nswdev) 313e92324a2SMatthew Dillon t = (blk + i) / dmmax % nswdev; 314e92324a2SMatthew Dillon if (t < ti) 315e92324a2SMatthew Dillon --swap_ary[t].ksw_used; 316e92324a2SMatthew Dillon if (ti >= 0) 317e92324a2SMatthew Dillon --swap_ary[ti].ksw_used; 318e92324a2SMatthew Dillon } 319e92324a2SMatthew Dillon } 320e92324a2SMatthew Dillon } 321ae3a37adSRobert Watson #endif 322e92324a2SMatthew Dillon } else if (meta.u.bmu_avail == radix) { 323e92324a2SMatthew Dillon /* 324e92324a2SMatthew Dillon * Meta node if all free 325e92324a2SMatthew Dillon */ 326e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 327e92324a2SMatthew Dillon printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n", 328e92324a2SMatthew Dillon TABME, 329e92324a2SMatthew Dillon blk, 330b7875890SDavid E. O'Brien radix 331e92324a2SMatthew Dillon ); 332e92324a2SMatthew Dillon } 333ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO 334e92324a2SMatthew Dillon /* 335e92324a2SMatthew Dillon * Note: both dmmax and radix are powers of 2. However, dmmax 336e92324a2SMatthew Dillon * may be larger then radix so use a smaller increment if 337e92324a2SMatthew Dillon * necessary. 338e92324a2SMatthew Dillon */ 339e92324a2SMatthew Dillon { 340e92324a2SMatthew Dillon int t; 341e92324a2SMatthew Dillon int tinc = dmmax; 342e92324a2SMatthew Dillon 343e92324a2SMatthew Dillon while (tinc > radix) 344e92324a2SMatthew Dillon tinc >>= 1; 345e92324a2SMatthew Dillon 346e92324a2SMatthew Dillon for (t = blk; t < blk + radix; t += tinc) { 347e92324a2SMatthew Dillon int u = (nswdev) ? (t / dmmax % nswdev) : 0; 348e92324a2SMatthew Dillon 349e92324a2SMatthew Dillon if (u < ti) 350e92324a2SMatthew Dillon swap_ary[u].ksw_used -= tinc; 351e92324a2SMatthew Dillon if (ti >= 0) 352e92324a2SMatthew Dillon swap_ary[ti].ksw_used -= tinc; 353e92324a2SMatthew Dillon } 354e92324a2SMatthew Dillon } 355ae3a37adSRobert Watson #endif 356e92324a2SMatthew Dillon } else if (meta.u.bmu_avail == 0) { 357e92324a2SMatthew Dillon /* 358e92324a2SMatthew Dillon * Meta node if all used 359e92324a2SMatthew Dillon */ 360e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 361e92324a2SMatthew Dillon printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n", 362e92324a2SMatthew Dillon TABME, 363e92324a2SMatthew Dillon blk, 364b7875890SDavid E. O'Brien radix 365e92324a2SMatthew Dillon ); 366e92324a2SMatthew Dillon } 367e92324a2SMatthew Dillon } else { 368e92324a2SMatthew Dillon /* 369e92324a2SMatthew Dillon * Meta node if not all free 370e92324a2SMatthew Dillon */ 371e92324a2SMatthew Dillon int i; 372e92324a2SMatthew Dillon int next_skip; 373e92324a2SMatthew Dillon 374e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 375e92324a2SMatthew Dillon printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n", 376e92324a2SMatthew Dillon TABME, 377e92324a2SMatthew Dillon blk, 378e92324a2SMatthew Dillon radix, 379e92324a2SMatthew Dillon (int)meta.u.bmu_avail, 380e92324a2SMatthew Dillon meta.bm_bighint 381e92324a2SMatthew Dillon ); 382e92324a2SMatthew Dillon } 383e92324a2SMatthew Dillon 384876c5c11SMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 385876c5c11SMatthew Dillon next_skip = skip >> BLIST_META_RADIX_SHIFT; 386876c5c11SMatthew Dillon 387e92324a2SMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 388e92324a2SMatthew Dillon int r; 389e92324a2SMatthew Dillon daddr_t vcount = (count > radix) ? radix : count; 390e92324a2SMatthew Dillon 391e92324a2SMatthew Dillon r = scanradix( 392e92324a2SMatthew Dillon &scan[i], 393e92324a2SMatthew Dillon blk, 394e92324a2SMatthew Dillon radix, 395e92324a2SMatthew Dillon next_skip - 1, 396e92324a2SMatthew Dillon vcount, 397e92324a2SMatthew Dillon kd, 398e92324a2SMatthew Dillon dmmax, 399e92324a2SMatthew Dillon nswdev, 400e92324a2SMatthew Dillon swap_ary, 401e92324a2SMatthew Dillon swap_max, 402e92324a2SMatthew Dillon tab + 4, 403e92324a2SMatthew Dillon flags 404e92324a2SMatthew Dillon ); 405e92324a2SMatthew Dillon if (r < 0) 406e92324a2SMatthew Dillon break; 407e92324a2SMatthew Dillon blk += radix; 408e92324a2SMatthew Dillon } 409e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 410e92324a2SMatthew Dillon printf("%*.*s}\n", TABME); 411e92324a2SMatthew Dillon } 412e92324a2SMatthew Dillon } 413e92324a2SMatthew Dillon return(0); 414e92324a2SMatthew Dillon } 415e92324a2SMatthew Dillon 416e92324a2SMatthew Dillon static void 41745908a6aSBruce Evans getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 418e92324a2SMatthew Dillon { 419e92324a2SMatthew Dillon struct blist *swapblist = NULL; 420e92324a2SMatthew Dillon struct blist blcopy = { 0 }; 421e92324a2SMatthew Dillon 422ae3a37adSRobert Watson if (!nlist_init(kd)) { 423ae3a37adSRobert Watson fprintf(stderr, "radix tree: nlist_init failed!\n"); 424ae3a37adSRobert Watson return; 425ae3a37adSRobert Watson } 426ae3a37adSRobert Watson 427e92324a2SMatthew Dillon KGET(NL_SWAPBLIST, swapblist); 428f3401d0cSMatthew Dillon 429f3401d0cSMatthew Dillon if (swapblist == NULL) { 430f3401d0cSMatthew Dillon if (flags & SWIF_DUMP_TREE) 431f3401d0cSMatthew Dillon printf("radix tree: NULL - no swap in system\n"); 432f3401d0cSMatthew Dillon return; 433f3401d0cSMatthew Dillon } 434f3401d0cSMatthew Dillon 435e92324a2SMatthew Dillon KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist"); 436e92324a2SMatthew Dillon 437e92324a2SMatthew Dillon if (flags & SWIF_DUMP_TREE) { 438e92324a2SMatthew Dillon printf("radix tree: %d/%d/%d blocks, %dK wired\n", 439e92324a2SMatthew Dillon blcopy.bl_free, 440e92324a2SMatthew Dillon blcopy.bl_blocks, 441e92324a2SMatthew Dillon blcopy.bl_radix, 442b7875890SDavid E. O'Brien (int)((blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/ 443b7875890SDavid E. O'Brien 1024) 444e92324a2SMatthew Dillon ); 445e92324a2SMatthew Dillon } 446e92324a2SMatthew Dillon scanradix( 447e92324a2SMatthew Dillon blcopy.bl_root, 448e92324a2SMatthew Dillon 0, 449e92324a2SMatthew Dillon blcopy.bl_radix, 450e92324a2SMatthew Dillon blcopy.bl_skip, 451e92324a2SMatthew Dillon blcopy.bl_rootblks, 452e92324a2SMatthew Dillon kd, 453e92324a2SMatthew Dillon dmmax, 454e92324a2SMatthew Dillon nswdev, 455e92324a2SMatthew Dillon swap_ary, 456e92324a2SMatthew Dillon swap_max, 457e92324a2SMatthew Dillon 0, 458e92324a2SMatthew Dillon flags 459e92324a2SMatthew Dillon ); 460e92324a2SMatthew Dillon } 461ae3a37adSRobert Watson 462ae3a37adSRobert Watson #define GETSYSCTL(kd, name, var) \ 463ae3a37adSRobert Watson getsysctl(kd, name, &(var), sizeof(var)) 464e04a7c4aSThomas Moestl 465e04a7c4aSThomas Moestl /* The maximum MIB length for vm.swap_info and an additional device number */ 466e04a7c4aSThomas Moestl #define SWI_MAXMIB 3 467ae3a37adSRobert Watson 468ae3a37adSRobert Watson int 469ae3a37adSRobert Watson kvm_getswapinfo_sysctl( 470ae3a37adSRobert Watson kvm_t *kd, 471ae3a37adSRobert Watson struct kvm_swap *swap_ary, 472ae3a37adSRobert Watson int swap_max, 473ae3a37adSRobert Watson int flags 474ae3a37adSRobert Watson ) { 475e04a7c4aSThomas Moestl int ti, ttl; 476e04a7c4aSThomas Moestl size_t mibi, len; 477e04a7c4aSThomas Moestl int soid[SWI_MAXMIB]; 478e04a7c4aSThomas Moestl struct xswdev xsd; 479e04a7c4aSThomas Moestl struct kvm_swap tot; 480ae3a37adSRobert Watson 481ae3a37adSRobert Watson if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 482ae3a37adSRobert Watson return -1; 483ae3a37adSRobert Watson 484e04a7c4aSThomas Moestl mibi = SWI_MAXMIB - 1; 485e04a7c4aSThomas Moestl if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 486e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 487e04a7c4aSThomas Moestl strerror(errno)); 488e04a7c4aSThomas Moestl return -1; 489e04a7c4aSThomas Moestl } 490e04a7c4aSThomas Moestl bzero(&tot, sizeof(tot)); 491e04a7c4aSThomas Moestl for (unswdev = 0;; unswdev++) { 492e04a7c4aSThomas Moestl soid[mibi] = unswdev; 493e04a7c4aSThomas Moestl len = sizeof(xsd); 494e04a7c4aSThomas Moestl if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 495e04a7c4aSThomas Moestl if (errno == ENOENT) 496e04a7c4aSThomas Moestl break; 497e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 498e04a7c4aSThomas Moestl strerror(errno)); 499e04a7c4aSThomas Moestl return -1; 500e04a7c4aSThomas Moestl } 501e04a7c4aSThomas Moestl if (len != sizeof(xsd)) { 502e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "struct xswdev has unexpected " 503e04a7c4aSThomas Moestl "size; kernel and libkvm out of sync?"); 504e04a7c4aSThomas Moestl return -1; 505e04a7c4aSThomas Moestl } 506e04a7c4aSThomas Moestl if (xsd.xsw_version != XSWDEV_VERSION) { 507e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "struct xswdev version " 508e04a7c4aSThomas Moestl "mismatch; kernel and libkvm out of sync?"); 509ae3a37adSRobert Watson return -1; 510ae3a37adSRobert Watson } 511ae3a37adSRobert Watson 512e04a7c4aSThomas Moestl ttl = xsd.xsw_nblks - dmmax; 513e04a7c4aSThomas Moestl if (unswdev < swap_max - 1) { 514e04a7c4aSThomas Moestl bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 515e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_total = ttl; 516e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_used = xsd.xsw_used; 517e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 518e04a7c4aSThomas Moestl GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 519e04a7c4aSThomas Moestl flags); 520e04a7c4aSThomas Moestl } 521e04a7c4aSThomas Moestl tot.ksw_total += ttl; 522e04a7c4aSThomas Moestl tot.ksw_used += xsd.xsw_used; 523e04a7c4aSThomas Moestl } 524ae3a37adSRobert Watson 525e04a7c4aSThomas Moestl ti = unswdev; 526e04a7c4aSThomas Moestl if (ti >= swap_max) 527e04a7c4aSThomas Moestl ti = swap_max - 1; 528e04a7c4aSThomas Moestl if (ti >= 0) 529e04a7c4aSThomas Moestl swap_ary[ti] = tot; 530ae3a37adSRobert Watson 531ae3a37adSRobert Watson return(ti); 532ae3a37adSRobert Watson } 533ae3a37adSRobert Watson 534ae3a37adSRobert Watson static int 535ae3a37adSRobert Watson nlist_init ( 536ae3a37adSRobert Watson kvm_t *kd 537ae3a37adSRobert Watson ) { 538ae3a37adSRobert Watson struct swdevt *sw; 539ae3a37adSRobert Watson 540ae3a37adSRobert Watson if (kvm_swap_nl_cached) 541ae3a37adSRobert Watson return (1); 542ae3a37adSRobert Watson 543ae3a37adSRobert Watson if (kvm_nlist(kd, kvm_swap_nl) < 0) 544ae3a37adSRobert Watson return (0); 545ae3a37adSRobert Watson 546ae3a37adSRobert Watson /* 547ae3a37adSRobert Watson * required entries 548ae3a37adSRobert Watson */ 549ae3a37adSRobert Watson if ( 550ae3a37adSRobert Watson kvm_swap_nl[NL_SWDEVT].n_value == 0 || 551ae3a37adSRobert Watson kvm_swap_nl[NL_NSWDEV].n_value == 0 || 552ae3a37adSRobert Watson kvm_swap_nl[NL_DMMAX].n_value == 0 || 553ae3a37adSRobert Watson kvm_swap_nl[NL_SWAPBLIST].n_type == 0 554ae3a37adSRobert Watson ) { 555ae3a37adSRobert Watson return (0); 556ae3a37adSRobert Watson } 557ae3a37adSRobert Watson 558ae3a37adSRobert Watson /* 559ae3a37adSRobert Watson * get globals, type of swap 560ae3a37adSRobert Watson */ 561ae3a37adSRobert Watson KGET(NL_NSWDEV, nswdev); 562ae3a37adSRobert Watson KGET(NL_DMMAX, dmmax); 563ae3a37adSRobert Watson 564ae3a37adSRobert Watson /* 565ae3a37adSRobert Watson * figure out how many actual swap devices are enabled 566ae3a37adSRobert Watson */ 567ae3a37adSRobert Watson KGET(NL_SWDEVT, sw); 568ae3a37adSRobert Watson for (unswdev = nswdev - 1; unswdev >= 0; --unswdev) { 569ae3a37adSRobert Watson struct swdevt swinfo; 570ae3a37adSRobert Watson 571ae3a37adSRobert Watson KGET2(&sw[unswdev], &swinfo, sizeof(swinfo), "swinfo"); 572ae3a37adSRobert Watson if (swinfo.sw_nblks) 573ae3a37adSRobert Watson break; 574ae3a37adSRobert Watson } 575ae3a37adSRobert Watson ++unswdev; 576ae3a37adSRobert Watson 577ae3a37adSRobert Watson kvm_swap_nl_cached = 1; 578ae3a37adSRobert Watson return (1); 579ae3a37adSRobert Watson } 580ae3a37adSRobert Watson 581ae3a37adSRobert Watson static int 582ae3a37adSRobert Watson getsysctl ( 583ae3a37adSRobert Watson kvm_t *kd, 584ae3a37adSRobert Watson char *name, 585ae3a37adSRobert Watson void *ptr, 586e04a7c4aSThomas Moestl size_t len 587ae3a37adSRobert Watson ) { 588e04a7c4aSThomas Moestl size_t nlen = len; 589ae3a37adSRobert Watson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 590e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 591e04a7c4aSThomas Moestl strerror(errno)); 592ae3a37adSRobert Watson return (0); 593ae3a37adSRobert Watson } 594ae3a37adSRobert Watson if (nlen != len) { 595ae3a37adSRobert Watson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 596ae3a37adSRobert Watson return (0); 597ae3a37adSRobert Watson } 598ae3a37adSRobert Watson return (1); 599ae3a37adSRobert Watson } 600