4 * cc -I/usr/src/sys vnodeinfo.c -o /usr/local/bin/vnodeinfo -lkvm
8 * Dump the mountlist and related vnodes.
11 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
13 * This code is derived from software contributed to The DragonFly Project
14 * by Matthew Dillon <dillon@backplane.com>
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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
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.
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
45 #define _KERNEL_STRUCTURES
46 #include <sys/param.h>
48 #include <sys/malloc.h>
49 #include <sys/signalvar.h>
50 #include <sys/namecache.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.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>
62 #include <vfs/ufs/quota.h>
63 #include <vfs/ufs/inode.h>
75 { "_vnode_inactive_list" },
76 { "_vnode_active_list" },
80 static void kkread(kvm_t
*kd
, u_long addr
, void *buf
, size_t nbytes
);
81 static struct mount
*dumpmount(kvm_t
*kd
, struct mount
*mp
);
82 static struct vnode
*dumpvp(kvm_t
*kd
, struct vnode
*vp
, int whichlist
, char *vfc_name
);
83 static void dumpbufs(kvm_t
*kd
, void *bufp
, const char *id
);
84 static void dumplocks(kvm_t
*kd
, struct lockf
*lockf
);
85 static void dumplockinfo(kvm_t
*kd
, struct lockf_range
*item
);
86 static int getobjpages(kvm_t
*kd
, struct vm_object
*obj
);
87 static int getobjvnpsize(kvm_t
*kd
, struct vm_object
*obj
);
89 static const struct dump_private_data
{
90 char vfc_name
[MFSNAMELEN
];
91 void (*dumpfn
)(kvm_t
*, void *);
102 main(int ac
, char **av
)
108 const char *corefile
= NULL
;
109 const char *sysfile
= NULL
;
111 while ((ch
= getopt(ac
, av
, "alnbM:N:p")) != -1) {
138 fprintf(stderr
, "%s [-pbnla] [-M core] [-N system]\n", av
[0]);
143 if ((kd
= kvm_open(sysfile
, corefile
, NULL
, O_RDONLY
, "kvm:")) == NULL
) {
147 if (kvm_nlist(kd
, Nl
) != 0) {
151 kkread(kd
, Nl
[0].n_value
, &mp
, sizeof(mp
));
153 mp
= dumpmount(kd
, mp
);
154 printf("INACTIVELIST {\n");
155 kkread(kd
, Nl
[1].n_value
, &vp
, sizeof(vp
));
157 vp
= dumpvp(kd
, vp
, 0, NULL
);
159 printf("ACTIVELIST {\n");
160 kkread(kd
, Nl
[2].n_value
, &vp
, sizeof(vp
));
162 vp
= dumpvp(kd
, vp
, 0, NULL
);
167 static struct mount
*
168 dumpmount(kvm_t
*kd
, struct mount
*mp
)
174 kkread(kd
, (u_long
)mp
, &mnt
, sizeof(mnt
));
175 printf("MOUNTPOINT %s on %s {\n",
176 mnt
.mnt_stat
.f_mntfromname
, mnt
.mnt_stat
.f_mntonname
);
177 printf(" lk_flags %08x count %08x holder = %p\n",
178 mnt
.mnt_lock
.lk_flags
, mnt
.mnt_lock
.lk_count
,
179 mnt
.mnt_lock
.lk_lockholder
);
180 printf(" mnt_flag %08x mnt_kern_flag %08x\n",
181 mnt
.mnt_flag
, mnt
.mnt_kern_flag
);
182 printf(" mnt_nvnodelistsize %d\n", mnt
.mnt_nvnodelistsize
);
183 printf(" mnt_stat.f_fsid %08x %08x\n", mnt
.mnt_stat
.f_fsid
.val
[0],
184 mnt
.mnt_stat
.f_fsid
.val
[1]);
186 /* Dump fs private node data */
187 kkread(kd
, (u_long
)mnt
.mnt_vfc
, &vfc
, sizeof(vfc
));
188 vp
= mnt
.mnt_nvnodelist
.tqh_first
;
190 vp
= dumpvp(kd
, vp
, 1, vfc
.vfc_name
);
194 return(mnt
.mnt_list
.tqe_next
);
198 vtype(enum vtype type
)
224 snprintf(buf
, sizeof(buf
), "%d", (int)type
);
228 static struct vnode
*
229 dumpvp(kvm_t
*kd
, struct vnode
*vp
, int whichlist
, char *vfc_name
)
233 kkread(kd
, (u_long
)vp
, &vn
, sizeof(vn
));
235 printf(" vnode %p.%d refcnt %08x auxcnt %d type=%s flags %08x",
236 vp
, vn
.v_state
, vn
.v_refcnt
, vn
.v_auxrefs
, vtype(vn
.v_type
), vn
.v_flag
);
238 if ((vn
.v_flag
& VOBJBUF
) && vn
.v_object
) {
239 int npages
= getobjpages(kd
, vn
.v_object
);
240 int vnpsize
= getobjvnpsize(kd
, vn
.v_object
);
241 if (npages
|| vnpsize
)
242 printf(" vmobjpgs=%d vnpsize=%d", npages
, vnpsize
);
245 if (vn
.v_flag
& VROOT
)
247 if (vn
.v_flag
& VTEXT
)
249 if (vn
.v_flag
& VSYSTEM
)
251 if (vn
.v_flag
& VISTTY
)
254 if (vn
.v_flag
& VXLOCK
)
256 if (vn
.v_flag
& VXWANT
)
260 if (vn
.v_flag
& VRECLAIMED
)
261 printf(" VRECLAIMED");
262 if (vn
.v_flag
& VINACTIVE
)
263 printf(" VINACTIVE");
265 if (vn
.v_flag
& VOBJBUF
)
268 if (vn
.v_flag
& VSWAPCACHE
)
269 printf(" VSWAPCACHE");
271 switch(vn
.v_flag
& (VAGE0
| VAGE1
)) {
286 if (vn
.v_flag
& VDOOMED
)
290 if (vn
.v_flag
& VINFREE
)
293 if (vn
.v_flag
& VONWORKLST
)
294 printf(" VONWORKLST");
295 if (vn
.v_flag
& VOBJDIRTY
)
296 printf(" VOBJDIRTY");
297 if (vn
.v_flag
& VMAYHAVELOCKS
)
298 printf(" VMAYHAVELOCKS");
302 if (vn
.v_lock
.lk_count
|| vn
.v_lock
.lk_lockholder
!= LK_NOTHREAD
) {
303 printf("\tlk_flags %08x count %08x holder = %p\n",
304 vn
.v_lock
.lk_flags
, vn
.v_lock
.lk_count
,
305 vn
.v_lock
.lk_lockholder
);
308 if (withnames
&& TAILQ_FIRST(&vn
.v_namecache
)) {
309 struct namecache ncp
;
313 kkread(kd
, (u_long
)TAILQ_FIRST(&vn
.v_namecache
), &ncp
, sizeof(ncp
));
314 if ((nlen
= ncp
.nc_nlen
) >= sizeof(buf
))
315 nlen
= sizeof(buf
) - 1;
319 kkread(kd
, (u_long
)ncp
.nc_name
, buf
, nlen
);
321 printf("\tfilename %s\n", buf
);
326 if (vn
.v_rbclean_tree
.rbh_root
) {
327 printf("\tCLEAN BUFFERS\n");
328 dumpbufs(kd
, vn
.v_rbclean_tree
.rbh_root
, "ROOT");
330 if (vn
.v_rbdirty_tree
.rbh_root
) {
331 printf("\tDIRTY BUFFERS\n");
332 dumpbufs(kd
, vn
.v_rbdirty_tree
.rbh_root
, "ROOT");
337 if (vn
.v_tag
== VT_UFS
&& vn
.v_data
) {
338 struct inode
*ip
= vn
.v_data
;
341 kkread(kd
, (u_long
)&ip
->i_lockf
, &lockf
, sizeof(lockf
));
342 dumplocks(kd
, &lockf
);
346 if (fsprivate
&& vfc_name
) {
348 * Actually find whether the filesystem can dump
349 * detailed inode information out of the vnode
351 const struct dump_private_data
*dpd
;
353 for (dpd
= dumplist
; dpd
->dumpfn
!= NULL
; dpd
++) {
354 if ((strcmp(dpd
->vfc_name
, vfc_name
) == 0) &&
356 dpd
->dumpfn(kd
, vn
.v_data
);
361 return(vn
.v_nmntvnodes
.tqe_next
);
363 return(vn
.v_list
.tqe_next
);
367 dumpbufs(kvm_t
*kd
, void *bufp
, const char *id
)
371 kkread(kd
, (u_long
)bufp
, &buf
, sizeof(buf
));
372 printf("\t %-8s %p loffset %012lx/%05x foffset %08lx",
374 buf
.b_bio1
.bio_offset
,
376 buf
.b_bio2
.bio_offset
);
377 printf(" q=%d count=%08x flags=%08x refs=%08x dep=%p",
378 buf
.b_qindex
, buf
.b_lock
.lk_count
,
379 buf
.b_flags
, buf
.b_refs
, buf
.b_dep
.lh_first
);
382 if (buf
.b_rbnode
.rbe_left
)
383 dumpbufs(kd
, buf
.b_rbnode
.rbe_left
, "LEFT");
384 if (buf
.b_rbnode
.rbe_right
)
385 dumpbufs(kd
, buf
.b_rbnode
.rbe_right
, "RIGHT");
389 dumplocks(kvm_t
*kd
, struct lockf
*lockf
)
391 struct lockf_range item
;
392 struct lockf_range
*scan
;
394 if ((scan
= TAILQ_FIRST(&lockf
->lf_range
)) != NULL
) {
397 kkread(kd
, (u_long
)scan
, &item
, sizeof(item
));
398 dumplockinfo(kd
, &item
);
399 } while ((scan
= TAILQ_NEXT(&item
, lf_link
)) != NULL
);
402 if ((scan
= TAILQ_FIRST(&lockf
->lf_blocked
)) != NULL
) {
405 kkread(kd
, (u_long
)scan
, &item
, sizeof(item
));
406 dumplockinfo(kd
, &item
);
407 } while ((scan
= TAILQ_NEXT(&item
, lf_link
)) != NULL
);
414 dumplockinfo(kvm_t
*kd
, struct lockf_range
*item
)
418 if (item
->lf_owner
&& (item
->lf_flags
& F_POSIX
)) {
419 kkread(kd
, (u_long
)&item
->lf_owner
->p_pid
,
420 &ownerpid
, sizeof(ownerpid
));
425 printf("\t ty=%d flgs=%04x %ld-%ld owner=%d\n",
426 item
->lf_type
, item
->lf_flags
,
427 item
->lf_start
, item
->lf_end
,
434 getobjpages(kvm_t
*kd
, struct vm_object
*obj
)
436 struct vm_object vmobj
;
438 kkread(kd
, (u_long
)obj
, &vmobj
, sizeof(vmobj
));
439 return(vmobj
.resident_page_count
);
444 getobjvnpsize(kvm_t
*kd
, struct vm_object
*obj
)
446 struct vm_object vmobj
;
448 kkread(kd
, (u_long
)obj
, &vmobj
, sizeof(vmobj
));
449 return ((int)vmobj
.size
);
453 kkread(kvm_t
*kd
, u_long addr
, void *buf
, size_t nbytes
)
455 if (kvm_read(kd
, addr
, buf
, nbytes
) != nbytes
) {