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