Add vnodeinfo - a program which scans each mount's vnode list and dumps
authorMatthew Dillon <dillon@dragonflybsd.org>
Thu, 7 Oct 2004 00:05:03 +0000 (00:05 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Thu, 7 Oct 2004 00:05:03 +0000 (00:05 +0000)
mount and vnode information, plus scans the vnode_free_list and dumps it
as well.

Give ncptrace the ability to specify a kernel and core file.

test/debug/ncptrace.c
test/debug/vnodeinfo.c [new file with mode: 0644]

index caf569b..4d4577f 100644 (file)
@@ -9,7 +9,7 @@
  * Trace and dump the kernel namecache hierarchy.  If a path is specified
  * the trace begins there, otherwise the trace begins at the root.
  *
- * $DragonFly: src/test/debug/ncptrace.c,v 1.2 2004/10/06 05:13:20 dillon Exp $
+ * $DragonFly: src/test/debug/ncptrace.c,v 1.3 2004/10/07 00:05:03 dillon Exp $
  */
 
 #define _KERNEL_STRUCTURES_
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <kvm.h>
 #include <nlist.h>
+#include <getopt.h>
 
 struct nlist Nl[] = {
 #ifdef CINV_PARENT
@@ -49,9 +50,26 @@ main(int ac, char **av)
 {
     struct namecache *ncptr;
     kvm_t *kd;
+    const char *corefile = NULL;
+    const char *sysfile = NULL;
+    int ch;
     int i;
 
-    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm:")) == NULL) {
+    while ((ch = getopt(ac, av, "M:N:")) != -1) {
+       switch(ch) {
+       case 'M':
+           corefile = optarg;
+           break;
+       case 'N':
+           sysfile = optarg;
+           break;
+       default:
+           fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
+           exit(1);
+       }
+    }
+
+    if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
        perror("kvm_open");
        exit(1);
     }
diff --git a/test/debug/vnodeinfo.c b/test/debug/vnodeinfo.c
new file mode 100644 (file)
index 0000000..39917b7
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * VNODEINFO.C
+ *
+ * cc -I/usr/src/sys vnodeinfo.c -o /usr/local/bin/vnodeinfo -lkvm
+ *
+ * vnodeinfo
+ *
+ * Dump the mountlist and related vnodes.
+ *
+ * $DragonFly: src/test/debug/vnodeinfo.c,v 1.1 2004/10/07 00:05:03 dillon Exp $
+ */
+
+#define _KERNEL_STRUCTURES_
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/malloc.h>
+#include <sys/signalvar.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_kern.h>
+#include <vm/swap_pager.h>
+#include <vm/vnode_pager.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <getopt.h>
+
+struct nlist Nl[] = {
+    { "_mountlist" },
+    { "_vnode_free_list" },
+    { NULL }
+};
+
+static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
+static struct mount *dumpmount(kvm_t *kd, struct mount *mp);
+static struct vnode *dumpvp(kvm_t *kd, struct vnode *vp, int whichlist);
+
+main(int ac, char **av)
+{
+    struct mount *mp;
+    struct vnode *vp;
+    kvm_t *kd;
+    int i;
+    int ch;
+    const char *corefile = NULL;
+    const char *sysfile = NULL;
+
+    while ((ch = getopt(ac, av, "M:N:")) != -1) {
+       switch(ch) {   
+       case 'M':
+           corefile = optarg;
+           break;
+       case 'N': 
+           sysfile = optarg;
+           break; 
+       default:  
+           fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
+           exit(1);
+       }
+    }
+
+    if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
+       perror("kvm_open");
+       exit(1);
+    }
+    if (kvm_nlist(kd, Nl) != 0) {
+       perror("kvm_nlist");
+       exit(1);
+    }
+    kkread(kd, Nl[0].n_value, &mp, sizeof(mp));
+    while (mp)
+       mp = dumpmount(kd, mp);
+    kkread(kd, Nl[1].n_value, &vp, sizeof(vp));
+    printf("VNODEFREELIST {\n");
+    while (vp)
+       vp = dumpvp(kd, vp, 0);
+    printf("}\n");
+    return(0);
+}
+
+static struct mount *
+dumpmount(kvm_t *kd, struct mount *mp)
+{
+    struct mount mnt;
+    struct vnode *vp;
+
+    kkread(kd, (u_long)mp, &mnt, sizeof(mnt));
+    printf("MOUNTPOINT %s on %s {\n", 
+       mnt.mnt_stat.f_mntfromname, mnt.mnt_stat.f_mntonname);
+    printf("    lk_flags %08x share %d wait %d excl %d holder = %p\n",
+       mnt.mnt_lock.lk_flags, mnt.mnt_lock.lk_sharecount,
+       mnt.mnt_lock.lk_waitcount, mnt.mnt_lock.lk_exclusivecount,
+       mnt.mnt_lock.lk_lockholder);
+    printf("    mnt_flag %08x mnt_kern_flag %08x\n", 
+       mnt.mnt_flag, mnt.mnt_kern_flag);
+    printf("    mnt_nvnodelistsize %d\n", mnt.mnt_nvnodelistsize);
+    vp = mnt.mnt_nvnodelist.tqh_first;
+    while (vp)
+       vp = dumpvp(kd, vp, 1);
+
+    printf("}\n");
+
+    return(mnt.mnt_list.tqe_next);
+}
+
+static const char *
+vtype(enum vtype type)
+{
+    static char buf[32];
+
+    switch(type) {
+    case VNON:
+       return("VNON");
+    case VREG:
+       return("VREG");
+    case VDIR:
+       return("VDIR");
+    case VBLK:
+       return("VBLK");
+    case VCHR:
+       return("VCHR");
+    case VLNK:
+       return("VLNK");
+    case VSOCK:
+       return("VSOCK");
+    case VFIFO:
+       return("VFIFO");
+    case VBAD:
+       return("VBAD");
+    default:
+       break;
+    }
+    snprintf(buf, sizeof(buf), "%d", (int)type);
+    return(buf);
+}
+
+static struct vnode *
+dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
+{
+    struct vnode vn;
+
+    kkread(kd, (u_long)vp, &vn, sizeof(vn));
+
+    printf("    vnode %p usecnt %d holdcnt %d type=%s flags %08x",
+       vp, vn.v_usecount, vn.v_holdcnt, vtype(vn.v_type), vn.v_flag);
+    if (vn.v_flag & VROOT)
+       printf(" ROOT");
+    if (vn.v_flag & VTEXT)
+       printf(" TEXT");
+    if (vn.v_flag & VSYSTEM)
+       printf(" SYSTEM");
+    if (vn.v_flag & VISTTY)
+       printf(" ISTTY");
+    if (vn.v_flag & VXLOCK)
+       printf(" XLOCK");
+    if (vn.v_flag & VXWANT)
+       printf(" XWANT");
+    if (vn.v_flag & VBWAIT)
+       printf(" BWAIT");
+    if (vn.v_flag & VOBJBUF)
+       printf(" OBJBUF");
+    if (vn.v_flag & VAGE)
+       printf(" AGE");
+    if (vn.v_flag & VOLOCK)
+       printf(" OLOCK");
+    if (vn.v_flag & VOWANT)
+       printf(" OWANT");
+    if (vn.v_flag & VDOOMED)
+       printf(" DOOMED");
+    if (vn.v_flag & VFREE)
+       printf(" FREE");
+    if (vn.v_flag & VINFREE)
+       printf(" INFREE");
+    if (vn.v_flag & VONWORKLST)
+       printf(" ONWORKLST");
+    if (vn.v_flag & VMOUNT)
+       printf(" MOUNT");
+    if (vn.v_flag & VOBJDIRTY)
+       printf(" OBJDIRTY");
+    if (vn.v_flag & VPLACEMARKER)
+       printf(" PLACEMARKER");
+    printf("\n");
+
+    if (vn.v_lock.lk_sharecount || vn.v_lock.lk_waitcount || 
+       vn.v_lock.lk_exclusivecount || vn.v_lock.lk_lockholder != LK_NOTHREAD) {
+       printf("\tlk_flags %08x share %d wait %d excl %d holder = %p\n",
+           vn.v_lock.lk_flags, vn.v_lock.lk_sharecount,
+           vn.v_lock.lk_waitcount, vn.v_lock.lk_exclusivecount,
+           vn.v_lock.lk_lockholder);
+    }
+
+    if (whichlist)
+       return(vn.v_nmntvnodes.tqe_next);
+    else
+       return(vn.v_freelist.tqe_next);
+}
+
+void
+kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes)
+{
+    if (kvm_read(kd, addr, buf, nbytes) != nbytes) {
+        perror("kvm_read");
+        exit(1);
+    }
+}
+