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 { "_vm_page_buckets" }, 72 { "_vm_page_hash_mask" }, 73 { "_vm_page_array" }, 74 { "_vm_page_array_size" }, 75 { NULL } 76 }; 77 78 int debugopt; 79 int verboseopt; 80 struct vm_page **vm_page_buckets; 81 int vm_page_hash_mask; 82 struct vm_page *vm_page_array; 83 int vm_page_array_size; 84 85 void checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj); 86 void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 87 88 int 89 main(int ac, char **av) 90 { 91 const char *corefile = NULL; 92 const char *sysfile = NULL; 93 vm_page_t mptr; 94 struct vm_page m; 95 struct vm_object obj; 96 kvm_t *kd; 97 int ch; 98 int hv; 99 int i; 100 const char *qstr; 101 const char *ostr; 102 103 while ((ch = getopt(ac, av, "M:N:dv")) != -1) { 104 switch(ch) { 105 case 'd': 106 ++debugopt; 107 break; 108 case 'v': 109 ++verboseopt; 110 break; 111 case 'M': 112 corefile = optarg; 113 break; 114 case 'N': 115 sysfile = optarg; 116 break; 117 default: 118 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 119 exit(1); 120 } 121 } 122 ac -= optind; 123 av += optind; 124 125 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 126 perror("kvm_open"); 127 exit(1); 128 } 129 if (kvm_nlist(kd, Nl) != 0) { 130 perror("kvm_nlist"); 131 exit(1); 132 } 133 134 kkread(kd, Nl[0].n_value, &vm_page_buckets, sizeof(vm_page_buckets)); 135 kkread(kd, Nl[1].n_value, &vm_page_hash_mask, sizeof(vm_page_hash_mask)); 136 kkread(kd, Nl[2].n_value, &vm_page_array, sizeof(vm_page_array)); 137 kkread(kd, Nl[3].n_value, &vm_page_array_size, sizeof(vm_page_array_size)); 138 139 /* 140 * Scan the vm_page_array validating all pages with associated objects 141 */ 142 for (i = 0; i < vm_page_array_size; ++i) { 143 if (debugopt) { 144 printf("page %d\r", i); 145 fflush(stdout); 146 } 147 kkread(kd, (u_long)&vm_page_array[i], &m, sizeof(m)); 148 if (m.object) { 149 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 150 checkpage(kd, &vm_page_array[i], &m, &obj); 151 } 152 if (verboseopt) { 153 if (m.queue >= PQ_HOLD) { 154 qstr = "HOLD"; 155 } else if (m.queue >= PQ_CACHE) { 156 qstr = "CACHE"; 157 } else if (m.queue >= PQ_ACTIVE) { 158 qstr = "ACTIVE"; 159 } else if (m.queue >= PQ_INACTIVE) { 160 qstr = "INACTIVE"; 161 } else if (m.queue >= PQ_FREE) { 162 qstr = "FREE"; 163 } else { 164 qstr = "NONE"; 165 } 166 printf("page %p val=%02x dty=%02x hold=%d wired=%-2d active=%-3d busy=%d/%d %s", 167 &vm_page_array[i], 168 m.valid, 169 m.dirty, 170 m.hold_count, 171 m.wire_count, 172 m.act_count, 173 m.busy, 174 ((m.flags & PG_BUSY) ? 1 : 0), 175 qstr 176 ); 177 switch(obj.type) { 178 case OBJT_DEFAULT: 179 ostr = "default"; 180 break; 181 case OBJT_SWAP: 182 ostr = "swap"; 183 break; 184 case OBJT_VNODE: 185 ostr = "vnode"; 186 break; 187 case OBJT_DEVICE: 188 ostr = "device"; 189 break; 190 case OBJT_PHYS: 191 ostr = "phys"; 192 break; 193 case OBJT_DEAD: 194 ostr = "dead"; 195 break; 196 default: 197 ostr = "unknown"; 198 break; 199 } 200 201 if (m.object && verboseopt > 1) { 202 printf("\tobj=%p type=%s\n", m.object, ostr); 203 } else { 204 printf("\n"); 205 } 206 } 207 } 208 if (debugopt || verboseopt) 209 printf("\n"); 210 211 /* 212 * Scan the vm_page_buckets array validating all pages found 213 */ 214 for (i = 0; i <= vm_page_hash_mask; ++i) { 215 if (debugopt) { 216 printf("index %d\r", i); 217 fflush(stdout); 218 } 219 kkread(kd, (u_long)&vm_page_buckets[i], &mptr, sizeof(mptr)); 220 while (mptr) { 221 kkread(kd, (u_long)mptr, &m, sizeof(m)); 222 if (m.object) { 223 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 224 hv = ((uintptr_t)m.object + m.pindex) ^ obj.hash_rand; 225 hv &= vm_page_hash_mask; 226 if (i != hv) 227 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 228 " should be in bucket %d\n", i, mptr, hv); 229 checkpage(kd, mptr, &m, &obj); 230 } else { 231 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 232 " has no object\n", i, mptr); 233 } 234 mptr = m.hnext; 235 } 236 } 237 if (debugopt) 238 printf("\n"); 239 return(0); 240 } 241 242 /* 243 * A page with an object. 244 */ 245 void 246 checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) 247 { 248 struct vm_page scan; 249 vm_page_t scanptr; 250 int hv; 251 252 hv = ((uintptr_t)m->object + m->pindex) ^ obj->hash_rand; 253 hv &= vm_page_hash_mask; 254 kkread(kd, (u_long)&vm_page_buckets[hv], &scanptr, sizeof(scanptr)); 255 while (scanptr) { 256 if (scanptr == mptr) 257 break; 258 kkread(kd, (u_long)scanptr, &scan, sizeof(scan)); 259 scanptr = scan.hnext; 260 } 261 if (scanptr) { 262 if (debugopt > 1) 263 printf("good checkpage %p bucket %d\n", mptr, hv); 264 } else { 265 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 266 " page not found in bucket list\n", hv, mptr); 267 } 268 } 269 270 void 271 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 272 { 273 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 274 perror("kvm_read"); 275 exit(1); 276 } 277 } 278 279