Add vnodeinfo - a program which scans each mount's vnode list and dumps
[dragonfly.git] / test / debug / vnodeinfo.c
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  * $DragonFly: src/test/debug/vnodeinfo.c,v 1.1 2004/10/07 00:05:03 dillon Exp $
11  */
12
13 #define _KERNEL_STRUCTURES_
14 #include <sys/param.h>
15 #include <sys/user.h>
16 #include <sys/malloc.h>
17 #include <sys/signalvar.h>
18 #include <sys/mount.h>
19 #include <sys/vnode.h>
20
21 #include <vm/vm.h>
22 #include <vm/vm_page.h>
23 #include <vm/vm_kern.h>
24 #include <vm/swap_pager.h>
25 #include <vm/vnode_pager.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <kvm.h>
32 #include <nlist.h>
33 #include <getopt.h>
34
35 struct nlist Nl[] = {
36     { "_mountlist" },
37     { "_vnode_free_list" },
38     { NULL }
39 };
40
41 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
42 static struct mount *dumpmount(kvm_t *kd, struct mount *mp);
43 static struct vnode *dumpvp(kvm_t *kd, struct vnode *vp, int whichlist);
44
45 main(int ac, char **av)
46 {
47     struct mount *mp;
48     struct vnode *vp;
49     kvm_t *kd;
50     int i;
51     int ch;
52     const char *corefile = NULL;
53     const char *sysfile = NULL;
54
55     while ((ch = getopt(ac, av, "M:N:")) != -1) {
56         switch(ch) {   
57         case 'M':
58             corefile = optarg;
59             break;
60         case 'N': 
61             sysfile = optarg;
62             break; 
63         default:  
64             fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
65             exit(1);
66         }
67     }
68
69     if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
70         perror("kvm_open");
71         exit(1);
72     }
73     if (kvm_nlist(kd, Nl) != 0) {
74         perror("kvm_nlist");
75         exit(1);
76     }
77     kkread(kd, Nl[0].n_value, &mp, sizeof(mp));
78     while (mp)
79         mp = dumpmount(kd, mp);
80     kkread(kd, Nl[1].n_value, &vp, sizeof(vp));
81     printf("VNODEFREELIST {\n");
82     while (vp)
83         vp = dumpvp(kd, vp, 0);
84     printf("}\n");
85     return(0);
86 }
87
88 static struct mount *
89 dumpmount(kvm_t *kd, struct mount *mp)
90 {
91     struct mount mnt;
92     struct vnode *vp;
93
94     kkread(kd, (u_long)mp, &mnt, sizeof(mnt));
95     printf("MOUNTPOINT %s on %s {\n", 
96         mnt.mnt_stat.f_mntfromname, mnt.mnt_stat.f_mntonname);
97     printf("    lk_flags %08x share %d wait %d excl %d holder = %p\n",
98         mnt.mnt_lock.lk_flags, mnt.mnt_lock.lk_sharecount,
99         mnt.mnt_lock.lk_waitcount, mnt.mnt_lock.lk_exclusivecount,
100         mnt.mnt_lock.lk_lockholder);
101     printf("    mnt_flag %08x mnt_kern_flag %08x\n", 
102         mnt.mnt_flag, mnt.mnt_kern_flag);
103     printf("    mnt_nvnodelistsize %d\n", mnt.mnt_nvnodelistsize);
104     vp = mnt.mnt_nvnodelist.tqh_first;
105     while (vp)
106         vp = dumpvp(kd, vp, 1);
107
108     printf("}\n");
109
110     return(mnt.mnt_list.tqe_next);
111 }
112
113 static const char *
114 vtype(enum vtype type)
115 {
116     static char buf[32];
117
118     switch(type) {
119     case VNON:
120         return("VNON");
121     case VREG:
122         return("VREG");
123     case VDIR:
124         return("VDIR");
125     case VBLK:
126         return("VBLK");
127     case VCHR:
128         return("VCHR");
129     case VLNK:
130         return("VLNK");
131     case VSOCK:
132         return("VSOCK");
133     case VFIFO:
134         return("VFIFO");
135     case VBAD:
136         return("VBAD");
137     default:
138         break;
139     }
140     snprintf(buf, sizeof(buf), "%d", (int)type);
141     return(buf);
142 }
143
144 static struct vnode *
145 dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
146 {
147     struct vnode vn;
148
149     kkread(kd, (u_long)vp, &vn, sizeof(vn));
150
151     printf("    vnode %p usecnt %d holdcnt %d type=%s flags %08x",
152         vp, vn.v_usecount, vn.v_holdcnt, vtype(vn.v_type), vn.v_flag);
153     if (vn.v_flag & VROOT)
154         printf(" ROOT");
155     if (vn.v_flag & VTEXT)
156         printf(" TEXT");
157     if (vn.v_flag & VSYSTEM)
158         printf(" SYSTEM");
159     if (vn.v_flag & VISTTY)
160         printf(" ISTTY");
161     if (vn.v_flag & VXLOCK)
162         printf(" XLOCK");
163     if (vn.v_flag & VXWANT)
164         printf(" XWANT");
165     if (vn.v_flag & VBWAIT)
166         printf(" BWAIT");
167     if (vn.v_flag & VOBJBUF)
168         printf(" OBJBUF");
169     if (vn.v_flag & VAGE)
170         printf(" AGE");
171     if (vn.v_flag & VOLOCK)
172         printf(" OLOCK");
173     if (vn.v_flag & VOWANT)
174         printf(" OWANT");
175     if (vn.v_flag & VDOOMED)
176         printf(" DOOMED");
177     if (vn.v_flag & VFREE)
178         printf(" FREE");
179     if (vn.v_flag & VINFREE)
180         printf(" INFREE");
181     if (vn.v_flag & VONWORKLST)
182         printf(" ONWORKLST");
183     if (vn.v_flag & VMOUNT)
184         printf(" MOUNT");
185     if (vn.v_flag & VOBJDIRTY)
186         printf(" OBJDIRTY");
187     if (vn.v_flag & VPLACEMARKER)
188         printf(" PLACEMARKER");
189     printf("\n");
190
191     if (vn.v_lock.lk_sharecount || vn.v_lock.lk_waitcount || 
192         vn.v_lock.lk_exclusivecount || vn.v_lock.lk_lockholder != LK_NOTHREAD) {
193         printf("\tlk_flags %08x share %d wait %d excl %d holder = %p\n",
194             vn.v_lock.lk_flags, vn.v_lock.lk_sharecount,
195             vn.v_lock.lk_waitcount, vn.v_lock.lk_exclusivecount,
196             vn.v_lock.lk_lockholder);
197     }
198
199     if (whichlist)
200         return(vn.v_nmntvnodes.tqe_next);
201     else
202         return(vn.v_freelist.tqe_next);
203 }
204
205 void
206 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes)
207 {
208     if (kvm_read(kd, addr, buf, nbytes) != nbytes) {
209         perror("kvm_read");
210         exit(1);
211     }
212 }
213