1 /* 2 * VNODEINFO.C 3 * 4 * cc -I/usr/src/sys vnodeinfo.c -o /usr/local/bin/vnodeinfo -lkvm 5 * 6 * vnodeinfo 7 * 8 * Dump the mountlist and related vnodes. 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/vnodeinfo.c,v 1.8 2005/12/05 16:52:02 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/mount.h> 52 #include <sys/vnode.h> 53 #include <sys/buf.h> 54 55 #include <vm/vm.h> 56 #include <vm/vm_page.h> 57 #include <vm/vm_kern.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 { "_mountlist" }, 72 { "_vnode_free_list" }, 73 { NULL } 74 }; 75 76 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 77 static struct mount *dumpmount(kvm_t *kd, struct mount *mp); 78 static struct vnode *dumpvp(kvm_t *kd, struct vnode *vp, int whichlist); 79 static void dumpbufs(kvm_t *kd, void *bufp, const char *id); 80 static int getobjpages(kvm_t *kd, struct vm_object *obj); 81 static int getobjvnpsize(kvm_t *kd, struct vm_object *obj); 82 83 int tracebufs = 0; 84 85 int 86 main(int ac, char **av) 87 { 88 struct mount *mp; 89 struct vnode *vp; 90 kvm_t *kd; 91 int i; 92 int ch; 93 const char *corefile = NULL; 94 const char *sysfile = NULL; 95 96 while ((ch = getopt(ac, av, "bM:N:")) != -1) { 97 switch(ch) { 98 case 'b': 99 tracebufs = 1; 100 break; 101 case 'M': 102 corefile = optarg; 103 break; 104 case 'N': 105 sysfile = optarg; 106 break; 107 default: 108 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 109 exit(1); 110 } 111 } 112 113 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 114 perror("kvm_open"); 115 exit(1); 116 } 117 if (kvm_nlist(kd, Nl) != 0) { 118 perror("kvm_nlist"); 119 exit(1); 120 } 121 kkread(kd, Nl[0].n_value, &mp, sizeof(mp)); 122 while (mp) 123 mp = dumpmount(kd, mp); 124 kkread(kd, Nl[1].n_value, &vp, sizeof(vp)); 125 printf("VNODEFREELIST {\n"); 126 while (vp) 127 vp = dumpvp(kd, vp, 0); 128 printf("}\n"); 129 return(0); 130 } 131 132 static struct mount * 133 dumpmount(kvm_t *kd, struct mount *mp) 134 { 135 struct mount mnt; 136 struct vnode *vp; 137 138 kkread(kd, (u_long)mp, &mnt, sizeof(mnt)); 139 printf("MOUNTPOINT %s on %s {\n", 140 mnt.mnt_stat.f_mntfromname, mnt.mnt_stat.f_mntonname); 141 printf(" lk_flags %08x share %d wait %d excl %d holder = %p\n", 142 mnt.mnt_lock.lk_flags, mnt.mnt_lock.lk_sharecount, 143 mnt.mnt_lock.lk_waitcount, mnt.mnt_lock.lk_exclusivecount, 144 mnt.mnt_lock.lk_lockholder); 145 printf(" mnt_flag %08x mnt_kern_flag %08x\n", 146 mnt.mnt_flag, mnt.mnt_kern_flag); 147 printf(" mnt_nvnodelistsize %d\n", mnt.mnt_nvnodelistsize); 148 printf(" mnt_stat.f_fsid %08x %08x\n", mnt.mnt_stat.f_fsid.val[0], 149 mnt.mnt_stat.f_fsid.val[1]); 150 vp = mnt.mnt_nvnodelist.tqh_first; 151 while (vp) 152 vp = dumpvp(kd, vp, 1); 153 154 printf("}\n"); 155 156 return(mnt.mnt_list.tqe_next); 157 } 158 159 static const char * 160 vtype(enum vtype type) 161 { 162 static char buf[32]; 163 164 switch(type) { 165 case VNON: 166 return("VNON"); 167 case VREG: 168 return("VREG"); 169 case VDIR: 170 return("VDIR"); 171 case VBLK: 172 return("VBLK"); 173 case VCHR: 174 return("VCHR"); 175 case VLNK: 176 return("VLNK"); 177 case VSOCK: 178 return("VSOCK"); 179 case VFIFO: 180 return("VFIFO"); 181 case VBAD: 182 return("VBAD"); 183 default: 184 break; 185 } 186 snprintf(buf, sizeof(buf), "%d", (int)type); 187 return(buf); 188 } 189 190 static struct vnode * 191 dumpvp(kvm_t *kd, struct vnode *vp, int whichlist) 192 { 193 struct vnode vn; 194 195 kkread(kd, (u_long)vp, &vn, sizeof(vn)); 196 197 printf(" vnode %p usecnt %d holdcnt %d type=%s flags %08x", 198 vp, vn.v_usecount, vn.v_holdcnt, vtype(vn.v_type), vn.v_flag); 199 200 if ((vn.v_flag & VOBJBUF) && vn.v_object) { 201 int npages = getobjpages(kd, vn.v_object); 202 int vnpsize = getobjvnpsize(kd, vn.v_object); 203 if (npages || vnpsize) 204 printf(" vmobjpgs=%d vnpsize=%d", npages, vnpsize); 205 } 206 207 if (vn.v_flag & VROOT) 208 printf(" VROOT"); 209 if (vn.v_flag & VTEXT) 210 printf(" VTEXT"); 211 if (vn.v_flag & VSYSTEM) 212 printf(" VSYSTEM"); 213 if (vn.v_flag & VISTTY) 214 printf(" VISTTY"); 215 #ifdef VXLOCK 216 if (vn.v_flag & VXLOCK) 217 printf(" VXLOCK"); 218 if (vn.v_flag & VXWANT) 219 printf(" VXWANT"); 220 #endif 221 #ifdef VRECLAIMED 222 if (vn.v_flag & VRECLAIMED) 223 printf(" VRECLAIMED"); 224 if (vn.v_flag & VINACTIVE) 225 printf(" VINACTIVE"); 226 #endif 227 if (vn.v_flag & VBWAIT) 228 printf(" VBWAIT"); 229 if (vn.v_flag & VOBJBUF) 230 printf(" VOBJBUF"); 231 if (vn.v_flag & VAGE) 232 printf(" VAGE"); 233 if (vn.v_flag & VOLOCK) 234 printf(" VOLOCK"); 235 if (vn.v_flag & VOWANT) 236 printf(" VOWANT"); 237 #ifdef VDOOMED 238 if (vn.v_flag & VDOOMED) 239 printf(" VDOOMED"); 240 #endif 241 if (vn.v_flag & VFREE) 242 printf(" VFREE"); 243 #ifdef VINFREE 244 if (vn.v_flag & VINFREE) 245 printf(" VINFREE"); 246 #endif 247 if (vn.v_flag & VONWORKLST) 248 printf(" VONWORKLST"); 249 if (vn.v_flag & VMOUNT) 250 printf(" VMOUNT"); 251 if (vn.v_flag & VOBJDIRTY) 252 printf(" VOBJDIRTY"); 253 254 printf("\n"); 255 256 if (vn.v_lock.lk_sharecount || vn.v_lock.lk_waitcount || 257 vn.v_lock.lk_exclusivecount || vn.v_lock.lk_lockholder != LK_NOTHREAD) { 258 printf("\tlk_flags %08x share %d wait %d excl %d holder = %p\n", 259 vn.v_lock.lk_flags, vn.v_lock.lk_sharecount, 260 vn.v_lock.lk_waitcount, vn.v_lock.lk_exclusivecount, 261 vn.v_lock.lk_lockholder); 262 } 263 264 if (tracebufs) { 265 if (vn.v_rbclean_tree.rbh_root) { 266 printf("\tCLEAN BUFFERS\n"); 267 dumpbufs(kd, vn.v_rbclean_tree.rbh_root, "ROOT"); 268 } 269 if (vn.v_rbdirty_tree.rbh_root) { 270 printf("\tDIRTY BUFFERS\n"); 271 dumpbufs(kd, vn.v_rbdirty_tree.rbh_root, "ROOT"); 272 } 273 } 274 275 if (whichlist) 276 return(vn.v_nmntvnodes.tqe_next); 277 else 278 return(vn.v_freelist.tqe_next); 279 } 280 281 static void 282 dumpbufs(kvm_t *kd, void *bufp, const char *id) 283 { 284 struct buf buf; 285 286 kkread(kd, (u_long)bufp, &buf, sizeof(buf)); 287 printf("\t %-8s %p lbn %5d fbn %6d\n", 288 id, bufp, 289 buf.b_lblkno, 290 buf.b_blkno); 291 292 if (buf.b_rbnode.rbe_left) 293 dumpbufs(kd, buf.b_rbnode.rbe_left, "LEFT"); 294 if (buf.b_rbnode.rbe_right) 295 dumpbufs(kd, buf.b_rbnode.rbe_right, "RIGHT"); 296 } 297 298 static 299 int 300 getobjpages(kvm_t *kd, struct vm_object *obj) 301 { 302 struct vm_object vmobj; 303 304 kkread(kd, (u_long)obj, &vmobj, sizeof(vmobj)); 305 return(vmobj.resident_page_count); 306 } 307 308 static 309 int 310 getobjvnpsize(kvm_t *kd, struct vm_object *obj) 311 { 312 struct vm_object vmobj; 313 314 kkread(kd, (u_long)obj, &vmobj, sizeof(vmobj)); 315 return(vmobj.un_pager.vnp.vnp_size); 316 } 317 318 static void 319 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 320 { 321 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 322 perror("kvm_read"); 323 exit(1); 324 } 325 } 326 327