1 /* 2 * VMPAGEINFO.C 3 * 4 * cc -I/usr/src/sys vmpageinfo.c -o /usr/local/bin/vmpageinfo -lkvm 5 * 6 * vmpageinfo 7 * 8 * Validate the vm_page_buckets[] hash array against the vm_page_array 9 * 10 * 11 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 12 * 13 * This code is derived from software contributed to The DragonFly Project 14 * by Matthew Dillon <dillon@backplane.com> 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in 24 * the documentation and/or other materials provided with the 25 * distribution. 26 * 3. Neither the name of The DragonFly Project nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific, prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 36 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 38 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 39 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 40 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 * 43 * $DragonFly: src/test/debug/vmpageinfo.c,v 1.2 2006/05/23 01:00:05 dillon Exp $ 44 */ 45 46 #define _KERNEL_STRUCTURES_ 47 #include <sys/param.h> 48 #include <sys/user.h> 49 #include <sys/malloc.h> 50 #include <sys/signalvar.h> 51 #include <sys/vnode.h> 52 #include <sys/namecache.h> 53 54 #include <vm/vm.h> 55 #include <vm/vm_page.h> 56 #include <vm/vm_kern.h> 57 #include <vm/vm_page.h> 58 #include <vm/vm_object.h> 59 #include <vm/swap_pager.h> 60 #include <vm/vnode_pager.h> 61 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <fcntl.h> 66 #include <kvm.h> 67 #include <nlist.h> 68 #include <getopt.h> 69 70 struct nlist Nl[] = { 71 #if 0 72 { "_vm_page_buckets" }, 73 { "_vm_page_hash_mask" }, 74 #endif 75 { "_vm_page_array" }, 76 { "_vm_page_array_size" }, 77 { NULL } 78 }; 79 80 int debugopt; 81 int verboseopt; 82 #if 0 83 struct vm_page **vm_page_buckets; 84 int vm_page_hash_mask; 85 #endif 86 struct vm_page *vm_page_array; 87 int vm_page_array_size; 88 89 void checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj); 90 void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 91 92 int 93 main(int ac, char **av) 94 { 95 const char *corefile = NULL; 96 const char *sysfile = NULL; 97 vm_page_t mptr; 98 struct vm_page m; 99 struct vm_object obj; 100 kvm_t *kd; 101 int ch; 102 int hv; 103 int i; 104 const char *qstr; 105 const char *ostr; 106 107 while ((ch = getopt(ac, av, "M:N:dv")) != -1) { 108 switch(ch) { 109 case 'd': 110 ++debugopt; 111 break; 112 case 'v': 113 ++verboseopt; 114 break; 115 case 'M': 116 corefile = optarg; 117 break; 118 case 'N': 119 sysfile = optarg; 120 break; 121 default: 122 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 123 exit(1); 124 } 125 } 126 ac -= optind; 127 av += optind; 128 129 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 130 perror("kvm_open"); 131 exit(1); 132 } 133 if (kvm_nlist(kd, Nl) != 0) { 134 perror("kvm_nlist"); 135 exit(1); 136 } 137 138 #if 0 139 kkread(kd, Nl[0].n_value, &vm_page_buckets, sizeof(vm_page_buckets)); 140 kkread(kd, Nl[1].n_value, &vm_page_hash_mask, sizeof(vm_page_hash_mask)); 141 #endif 142 kkread(kd, Nl[0].n_value, &vm_page_array, sizeof(vm_page_array)); 143 kkread(kd, Nl[1].n_value, &vm_page_array_size, sizeof(vm_page_array_size)); 144 145 /* 146 * Scan the vm_page_array validating all pages with associated objects 147 */ 148 for (i = 0; i < vm_page_array_size; ++i) { 149 if (debugopt) { 150 printf("page %d\r", i); 151 fflush(stdout); 152 } 153 kkread(kd, (u_long)&vm_page_array[i], &m, sizeof(m)); 154 if (m.object) { 155 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 156 checkpage(kd, &vm_page_array[i], &m, &obj); 157 } 158 if (verboseopt) { 159 if (m.queue >= PQ_HOLD) { 160 qstr = "HOLD"; 161 } else if (m.queue >= PQ_CACHE) { 162 qstr = "CACHE"; 163 } else if (m.queue >= PQ_ACTIVE) { 164 qstr = "ACTIVE"; 165 } else if (m.queue >= PQ_INACTIVE) { 166 qstr = "INACTIVE"; 167 } else if (m.queue >= PQ_FREE) { 168 qstr = "FREE"; 169 } else { 170 qstr = "NONE"; 171 } 172 printf("page %p obj %p/%-8jd val=%02x dty=%02x hold=%d " 173 "wire=%-2d act=%-3d busy=%d %8s", 174 &vm_page_array[i], 175 m.object, 176 (intmax_t)m.pindex, 177 m.valid, 178 m.dirty, 179 m.hold_count, 180 m.wire_count, 181 m.act_count, 182 m.busy, 183 qstr 184 ); 185 if (m.object) { 186 switch(obj.type) { 187 case OBJT_DEFAULT: 188 ostr = "default"; 189 break; 190 case OBJT_SWAP: 191 ostr = "swap"; 192 break; 193 case OBJT_VNODE: 194 ostr = "vnode"; 195 break; 196 case OBJT_DEVICE: 197 ostr = "device"; 198 break; 199 case OBJT_PHYS: 200 ostr = "phys"; 201 break; 202 case OBJT_DEAD: 203 ostr = "dead"; 204 break; 205 default: 206 ostr = "unknown"; 207 break; 208 } 209 } else { 210 ostr = "-"; 211 } 212 printf(" %-7s", ostr); 213 if (m.flags & PG_BUSY) 214 printf(" BUSY"); 215 if (m.flags & PG_WANTED) 216 printf(" WANTED"); 217 if (m.flags & PG_WINATCFLS) 218 printf(" WINATCFLS"); 219 if (m.flags & PG_FICTITIOUS) 220 printf(" FICTITIOUS"); 221 if (m.flags & PG_WRITEABLE) 222 printf(" WRITEABLE"); 223 if (m.flags & PG_MAPPED) 224 printf(" MAPPED"); 225 if (m.flags & PG_ZERO) 226 printf(" ZERO"); 227 if (m.flags & PG_REFERENCED) 228 printf(" REFERENCED"); 229 if (m.flags & PG_CLEANCHK) 230 printf(" CLEANCHK"); 231 if (m.flags & PG_SWAPINPROG) 232 printf(" SWAPINPROG"); 233 if (m.flags & PG_NOSYNC) 234 printf(" NOSYNC"); 235 if (m.flags & PG_UNMANAGED) 236 printf(" UNMANAGED"); 237 if (m.flags & PG_MARKER) 238 printf(" MARKER"); 239 if (m.flags & PG_RAM) 240 printf(" RAM"); 241 if (m.flags & PG_SWAPPED) 242 printf(" SWAPPED"); 243 printf("\n"); 244 } 245 } 246 if (debugopt || verboseopt) 247 printf("\n"); 248 249 #if 0 250 /* 251 * Scan the vm_page_buckets array validating all pages found 252 */ 253 for (i = 0; i <= vm_page_hash_mask; ++i) { 254 if (debugopt) { 255 printf("index %d\r", i); 256 fflush(stdout); 257 } 258 kkread(kd, (u_long)&vm_page_buckets[i], &mptr, sizeof(mptr)); 259 while (mptr) { 260 kkread(kd, (u_long)mptr, &m, sizeof(m)); 261 if (m.object) { 262 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 263 hv = ((uintptr_t)m.object + m.pindex) ^ obj.hash_rand; 264 hv &= vm_page_hash_mask; 265 if (i != hv) 266 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 267 " should be in bucket %d\n", i, mptr, hv); 268 checkpage(kd, mptr, &m, &obj); 269 } else { 270 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 271 " has no object\n", i, mptr); 272 } 273 mptr = m.hnext; 274 } 275 } 276 #endif 277 if (debugopt) 278 printf("\n"); 279 return(0); 280 } 281 282 /* 283 * A page with an object. 284 */ 285 void 286 checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) 287 { 288 #if 0 289 struct vm_page scan; 290 vm_page_t scanptr; 291 int hv; 292 293 hv = ((uintptr_t)m->object + m->pindex) ^ obj->hash_rand; 294 hv &= vm_page_hash_mask; 295 kkread(kd, (u_long)&vm_page_buckets[hv], &scanptr, sizeof(scanptr)); 296 while (scanptr) { 297 if (scanptr == mptr) 298 break; 299 kkread(kd, (u_long)scanptr, &scan, sizeof(scan)); 300 scanptr = scan.hnext; 301 } 302 if (scanptr) { 303 if (debugopt > 1) 304 printf("good checkpage %p bucket %d\n", mptr, hv); 305 } else { 306 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 307 " page not found in bucket list\n", hv, mptr); 308 } 309 #endif 310 } 311 312 void 313 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 314 { 315 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 316 perror("kvm_read"); 317 exit(1); 318 } 319 } 320 321