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