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 switch(obj.type) { 186 case OBJT_DEFAULT: 187 ostr = "default"; 188 break; 189 case OBJT_SWAP: 190 ostr = "swap"; 191 break; 192 case OBJT_VNODE: 193 ostr = "vnode"; 194 break; 195 case OBJT_DEVICE: 196 ostr = "device"; 197 break; 198 case OBJT_PHYS: 199 ostr = "phys"; 200 break; 201 case OBJT_DEAD: 202 ostr = "dead"; 203 break; 204 default: 205 ostr = "unknown"; 206 break; 207 } 208 printf(" %-7s", ostr); 209 if (m.flags & PG_BUSY) 210 printf(" BUSY"); 211 if (m.flags & PG_WANTED) 212 printf(" WANTED"); 213 if (m.flags & PG_WINATCFLS) 214 printf(" WINATCFLS"); 215 if (m.flags & PG_FICTITIOUS) 216 printf(" FICTITIOUS"); 217 if (m.flags & PG_WRITEABLE) 218 printf(" WRITEABLE"); 219 if (m.flags & PG_MAPPED) 220 printf(" MAPPED"); 221 if (m.flags & PG_ZERO) 222 printf(" ZERO"); 223 if (m.flags & PG_REFERENCED) 224 printf(" REFERENCED"); 225 if (m.flags & PG_CLEANCHK) 226 printf(" CLEANCHK"); 227 if (m.flags & PG_SWAPINPROG) 228 printf(" SWAPINPROG"); 229 if (m.flags & PG_NOSYNC) 230 printf(" NOSYNC"); 231 if (m.flags & PG_UNMANAGED) 232 printf(" UNMANAGED"); 233 if (m.flags & PG_MARKER) 234 printf(" MARKER"); 235 if (m.flags & PG_RAM) 236 printf(" RAM"); 237 if (m.flags & PG_SWAPPED) 238 printf(" SWAPPED"); 239 printf("\n"); 240 } 241 } 242 if (debugopt || verboseopt) 243 printf("\n"); 244 245 #if 0 246 /* 247 * Scan the vm_page_buckets array validating all pages found 248 */ 249 for (i = 0; i <= vm_page_hash_mask; ++i) { 250 if (debugopt) { 251 printf("index %d\r", i); 252 fflush(stdout); 253 } 254 kkread(kd, (u_long)&vm_page_buckets[i], &mptr, sizeof(mptr)); 255 while (mptr) { 256 kkread(kd, (u_long)mptr, &m, sizeof(m)); 257 if (m.object) { 258 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 259 hv = ((uintptr_t)m.object + m.pindex) ^ obj.hash_rand; 260 hv &= vm_page_hash_mask; 261 if (i != hv) 262 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 263 " should be in bucket %d\n", i, mptr, hv); 264 checkpage(kd, mptr, &m, &obj); 265 } else { 266 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 267 " has no object\n", i, mptr); 268 } 269 mptr = m.hnext; 270 } 271 } 272 #endif 273 if (debugopt) 274 printf("\n"); 275 return(0); 276 } 277 278 /* 279 * A page with an object. 280 */ 281 void 282 checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) 283 { 284 #if 0 285 struct vm_page scan; 286 vm_page_t scanptr; 287 int hv; 288 289 hv = ((uintptr_t)m->object + m->pindex) ^ obj->hash_rand; 290 hv &= vm_page_hash_mask; 291 kkread(kd, (u_long)&vm_page_buckets[hv], &scanptr, sizeof(scanptr)); 292 while (scanptr) { 293 if (scanptr == mptr) 294 break; 295 kkread(kd, (u_long)scanptr, &scan, sizeof(scan)); 296 scanptr = scan.hnext; 297 } 298 if (scanptr) { 299 if (debugopt > 1) 300 printf("good checkpage %p bucket %d\n", mptr, hv); 301 } else { 302 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 303 " page not found in bucket list\n", hv, mptr); 304 } 305 #endif 306 } 307 308 void 309 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 310 { 311 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 312 perror("kvm_read"); 313 exit(1); 314 } 315 } 316 317