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