1 /* $NetBSD: opdump.c,v 1.37 2014/10/31 13:56:04 manu Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /* Pretty-printing helper routines for VFS/VOP request contents */
33
34 /* yes, this is pretty much a mess */
35
36 #include <sys/cdefs.h>
37 #if !defined(lint)
38 __RCSID("$NetBSD: opdump.c,v 1.37 2014/10/31 13:56:04 manu Exp $");
39 #endif /* !lint */
40
41 #include <sys/types.h>
42 #include <sys/time.h>
43
44 #include <puffs.h>
45 #include <puffsdump.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48
49 #include "puffs_priv.h"
50
51 #define DINT " "
52
53 const char *puffsdump_vfsop_revmap[] = {
54 "PUFFS_VFS_MOUNT",
55 "PUFFS_VFS_START",
56 "PUFFS_VFS_UNMOUNT",
57 "PUFFS_VFS_ROOT",
58 "PUFFS_VFS_QUOTACTL",
59 "PUFFS_VFS_STATVFS",
60 "PUFFS_VFS_SYNC",
61 "PUFFS_VFS_VGET",
62 "PUFFS_VFS_FHTOVP",
63 "PUFFS_VFS_VPTOFH",
64 "PUFFS_VFS_INIT",
65 "PUFFS_VFS_DONE",
66 "PUFFS_VFS_SNAPSHOT",
67 "PUFFS_VFS_EXTATTRCTL",
68 "PUFFS_VFS_SUSPEND"
69 };
70 size_t puffsdump_vfsop_count = __arraycount(puffsdump_vfsop_revmap);
71
72 const char *puffsdump_vnop_revmap[] = {
73 "PUFFS_VN_LOOKUP",
74 "PUFFS_VN_CREATE",
75 "PUFFS_VN_MKNOD",
76 "PUFFS_VN_OPEN",
77 "PUFFS_VN_CLOSE",
78 "PUFFS_VN_ACCESS",
79 "PUFFS_VN_GETATTR",
80 "PUFFS_VN_SETATTR",
81 "PUFFS_VN_READ",
82 "PUFFS_VN_WRITE",
83 "PUFFS_VN_IOCTL",
84 "PUFFS_VN_FCNTL",
85 "PUFFS_VN_POLL",
86 "PUFFS_VN_KQFILTER",
87 "PUFFS_VN_REVOKE",
88 "PUFFS_VN_MMAP",
89 "PUFFS_VN_FSYNC",
90 "PUFFS_VN_SEEK",
91 "PUFFS_VN_REMOVE",
92 "PUFFS_VN_LINK",
93 "PUFFS_VN_RENAME",
94 "PUFFS_VN_MKDIR",
95 "PUFFS_VN_RMDIR",
96 "PUFFS_VN_SYMLINK",
97 "PUFFS_VN_READDIR",
98 "PUFFS_VN_READLINK",
99 "PUFFS_VN_ABORTOP",
100 "PUFFS_VN_INACTIVE",
101 "PUFFS_VN_RECLAIM",
102 "PUFFS_VN_LOCK",
103 "PUFFS_VN_UNLOCK",
104 "PUFFS_VN_BMAP",
105 "PUFFS_VN_STRATEGY",
106 "PUFFS_VN_PRINT",
107 "PUFFS_VN_ISLOCKED",
108 "PUFFS_VN_PATHCONF",
109 "PUFFS_VN_ADVLOCK",
110 "PUFFS_VN_LEASE",
111 "PUFFS_VN_WHITEOUT",
112 "PUFFS_VN_GETPAGES",
113 "PUFFS_VN_PUTPAGES",
114 "PUFFS_VN_GETEXTATTR",
115 "PUFFS_VN_LISTEXTATTR",
116 "PUFFS_VN_OPENEXTATTR",
117 "PUFFS_VN_DELETEEXTATTR",
118 "PUFFS_VN_SETEXTATTR",
119 "PUFFS_VN_CLOSEEXTATTR",
120 "PUFFS_VN_FALLOCATE",
121 "PUFFS_VN_FDISCARD",
122 };
123 size_t puffsdump_vnop_count = __arraycount(puffsdump_vnop_revmap);
124
125 /* XXX! */
126 const char *puffsdump_cacheop_revmap[] = {
127 "PUFFS_CACHE_WRITE"
128 };
129
130 const char *puffsdump_errnot_revmap[] = {
131 "PUFFS_ERR_ERROR",
132 "PUFFS_ERR_MAKENODE",
133 "PUFFS_ERR_LOOKUP",
134 "PUFFS_ERR_READDIR",
135 "PUFFS_ERR_READLINK",
136 "PUFFS_ERR_READ",
137 "PUFFS_ERR_WRITE",
138 "PUFFS_ERR_VPTOFH",
139 "PUFFS_ERR_GETEXTATTR",
140 "PUFFS_ERR_LISTEXTATTR",
141 };
142 size_t puffsdump_errnot_count = __arraycount(puffsdump_errnot_revmap);
143
144 const char *puffsdump_flush_revmap[] = {
145 "PUFFS_INVAL_NAMECACHE_NODE",
146 "PUFFS_INVAL_NAMECACHE_DIR",
147 "PUFFS_INVAL_NAMECACHE_ALL",
148 "PUFFS_INVAL_PAGECACHE_NODE_RANGE",
149 "PUFFS_FLUSH_PAGECACHE_NODE_RANGE",
150 };
151 size_t puffsdump_flush_count = __arraycount(puffsdump_flush_revmap);
152
153 static __printflike(1, 2) void
mydprintf(const char * fmt,...)154 mydprintf(const char *fmt, ...)
155 {
156 va_list ap;
157
158 va_start(ap, fmt);
159 vfprintf(stderr, fmt, ap);
160 va_end(ap);
161 }
162
163 void
puffsdump_req(struct puffs_req * preq)164 puffsdump_req(struct puffs_req *preq)
165 {
166 char buf[128];
167 static struct timeval tv_prev;
168 struct timeval tv_now, tv;
169 const char **map;
170 const char *optype;
171 size_t maxhandle;
172 int opclass, isvn = 0;
173
174 mydprintf("reqid: %" PRIu64 ", ", preq->preq_id);
175 opclass = PUFFSOP_OPCLASS(preq->preq_opclass);
176 switch (opclass) {
177 case PUFFSOP_VFS:
178 map = puffsdump_vfsop_revmap;
179 maxhandle = puffsdump_vfsop_count;
180 break;
181 case PUFFSOP_VN:
182 map = puffsdump_vnop_revmap;
183 maxhandle = puffsdump_vnop_count;
184 isvn = 1;
185 break;
186 case PUFFSOP_CACHE:
187 map = puffsdump_cacheop_revmap;
188 maxhandle = __arraycount(puffsdump_cacheop_revmap);
189 break;
190 case PUFFSOP_ERROR:
191 map = puffsdump_errnot_revmap;
192 maxhandle = puffsdump_errnot_count;
193 break;
194 case PUFFSOP_FLUSH:
195 map = puffsdump_flush_revmap;
196 maxhandle = puffsdump_flush_count;
197 break;
198 default:
199 mydprintf("unhandled opclass %d\n", opclass);
200 return;
201 }
202
203 if (preq->preq_optype < maxhandle) {
204 optype = map[preq->preq_optype];
205 } else {
206 snprintf(buf, sizeof(buf), "UNKNOWN (%d)", preq->preq_optype);
207 optype = buf;
208 }
209
210 mydprintf("opclass %d%s, optype: %s, "
211 "cookie: %p,\n" DINT "aux: %p, auxlen: %zu, pid: %d, lwpid: %d\n",
212 opclass, PUFFSOP_WANTREPLY(preq->preq_opclass) ? "" : " (FAF)",
213 optype, preq->preq_cookie,
214 preq->preq_buf, preq->preq_buflen,
215 preq->preq_pid, preq->preq_lid);
216
217 if (isvn) {
218 switch (preq->preq_optype) {
219 case PUFFS_VN_LOOKUP:
220 puffsdump_lookup(preq);
221 break;
222 case PUFFS_VN_READ:
223 case PUFFS_VN_WRITE:
224 puffsdump_readwrite(preq);
225 break;
226 case PUFFS_VN_OPEN:
227 puffsdump_open(preq);
228 break;
229 case PUFFS_VN_REMOVE:
230 case PUFFS_VN_RMDIR:
231 case PUFFS_VN_LINK:
232 puffsdump_targ(preq);
233 break;
234 case PUFFS_VN_READDIR:
235 puffsdump_readdir(preq);
236 break;
237 case PUFFS_VN_CREATE:
238 case PUFFS_VN_MKDIR:
239 case PUFFS_VN_MKNOD:
240 case PUFFS_VN_SYMLINK:
241 puffsdump_create(preq);
242 break;
243 case PUFFS_VN_SETATTR:
244 puffsdump_attr(preq);
245 break;
246 default:
247 break;
248 }
249 }
250
251 PU_LOCK();
252 gettimeofday(&tv_now, NULL);
253 timersub(&tv_now, &tv_prev, &tv);
254 mydprintf(DINT "since previous call: %lld.%06ld\n",
255 (long long)tv.tv_sec, (long)tv.tv_usec);
256 gettimeofday(&tv_prev, NULL);
257 PU_UNLOCK();
258 }
259
260 void
puffsdump_rv(struct puffs_req * preq)261 puffsdump_rv(struct puffs_req *preq)
262 {
263
264 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
265 switch (preq->preq_optype) {
266 case PUFFS_VN_LOOKUP:
267 puffsdump_lookup_rv(preq);
268 break;
269 case PUFFS_VN_CREATE:
270 case PUFFS_VN_MKDIR:
271 case PUFFS_VN_MKNOD:
272 case PUFFS_VN_SYMLINK:
273 puffsdump_create_rv(preq);
274 break;
275 case PUFFS_VN_READ:
276 case PUFFS_VN_WRITE:
277 puffsdump_readwrite_rv(preq);
278 break;
279 case PUFFS_VN_READDIR:
280 puffsdump_readdir_rv(preq);
281 break;
282 case PUFFS_VN_GETATTR:
283 puffsdump_attr(preq);
284 break;
285 default:
286 break;
287 }
288 }
289
290 mydprintf("RV reqid: %" PRIu64 ", result: %d %s\n",
291 preq->preq_id, preq->preq_rv,
292 preq->preq_rv ? strerror(preq->preq_rv) : "");
293 }
294
295 /*
296 * Slightly tedious print-routine so that we get a nice NOVAL instead
297 * of some tedious output representations for -1, especially (uint64_t)-1
298 *
299 * We use typecasting to make this work beyond time_t/dev_t size changes.
300 */
301 static void
dumpattr(struct vattr * vap)302 dumpattr(struct vattr *vap)
303 {
304 const char * const vtypes[] = { VNODE_TYPES };
305 char buf[128];
306
307 /* XXX: better readability. and this is debug, so no cycle-sweat */
308 #define DEFAULTBUF() snprintf(buf, sizeof(buf), "NOVAL")
309
310 mydprintf(DINT "vattr:\n");
311 mydprintf(DINT DINT "type: %s, ", vtypes[vap->va_type]);
312
313 DEFAULTBUF();
314 if (vap->va_mode != (mode_t)PUFFS_VNOVAL)
315 snprintf(buf, sizeof(buf), "0%o", vap->va_mode);
316 mydprintf("mode: %s, ", buf);
317
318 DEFAULTBUF();
319 if (vap->va_nlink != (nlink_t)PUFFS_VNOVAL)
320 snprintf(buf, sizeof(buf), "%d", vap->va_nlink);
321 mydprintf("nlink: %s, ", buf);
322
323 DEFAULTBUF();
324 if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
325 snprintf(buf, sizeof(buf), "%d", vap->va_uid);
326 mydprintf("uid: %s, ", buf);
327
328 DEFAULTBUF();
329 if (vap->va_gid != (gid_t)PUFFS_VNOVAL)
330 snprintf(buf, sizeof(buf), "%d", vap->va_gid);
331 mydprintf("gid: %s\n", buf);
332
333 DEFAULTBUF();
334 if ((unsigned long long)vap->va_fsid!=(unsigned long long)PUFFS_VNOVAL)
335 snprintf(buf, sizeof(buf), "0x%llx",
336 (unsigned long long)vap->va_fsid);
337 mydprintf(DINT DINT "fsid: %s, ", buf);
338
339 DEFAULTBUF();
340 if (vap->va_fileid != (ino_t)PUFFS_VNOVAL)
341 snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_fileid);
342 mydprintf("ino: %s, ", buf);
343
344 DEFAULTBUF();
345 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
346 snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_size);
347 mydprintf("size: %s, ", buf);
348
349 DEFAULTBUF();
350 if (vap->va_blocksize != (long)PUFFS_VNOVAL)
351 snprintf(buf, sizeof(buf), "%ld", vap->va_blocksize);
352 mydprintf("bsize: %s\n", buf);
353
354 DEFAULTBUF();
355 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
356 snprintf(buf, sizeof(buf), "%lld",
357 (long long)vap->va_atime.tv_sec);
358 mydprintf(DINT DINT "a.s: %s, ", buf);
359
360 DEFAULTBUF();
361 if (vap->va_atime.tv_nsec != (long)PUFFS_VNOVAL)
362 snprintf(buf, sizeof(buf), "%ld", vap->va_atime.tv_nsec);
363 mydprintf("a.ns: %s, ", buf);
364
365 DEFAULTBUF();
366 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
367 snprintf(buf, sizeof(buf), "%lld",
368 (long long)vap->va_mtime.tv_sec);
369 mydprintf("m.s: %s, ", buf);
370
371 DEFAULTBUF();
372 if (vap->va_mtime.tv_nsec != (long)PUFFS_VNOVAL)
373 snprintf(buf, sizeof(buf), "%ld", vap->va_mtime.tv_nsec);
374 mydprintf("m.ns: %s\n", buf);
375
376 DEFAULTBUF();
377 if (vap->va_ctime.tv_sec != (time_t)PUFFS_VNOVAL)
378 snprintf(buf, sizeof(buf), "%lld",
379 (long long)vap->va_ctime.tv_sec);
380 mydprintf(DINT DINT "c.s: %s, ", buf);
381
382 DEFAULTBUF();
383 if (vap->va_ctime.tv_nsec != (long)PUFFS_VNOVAL)
384 snprintf(buf, sizeof(buf), "%ld", vap->va_ctime.tv_nsec);
385 mydprintf("c.ns: %s, ", buf);
386
387 DEFAULTBUF();
388 if (vap->va_birthtime.tv_sec != (time_t)PUFFS_VNOVAL)
389 snprintf(buf, sizeof(buf), "%lld",
390 (long long)vap->va_birthtime.tv_sec);
391 mydprintf("b.s: %s, ", buf);
392
393 DEFAULTBUF();
394 if (vap->va_birthtime.tv_nsec != (long)PUFFS_VNOVAL)
395 snprintf(buf, sizeof(buf), "%ld", vap->va_birthtime.tv_nsec);
396 mydprintf("b.ns: %s\n", buf);
397
398 DEFAULTBUF();
399 if (vap->va_gen != (u_long)PUFFS_VNOVAL)
400 snprintf(buf, sizeof(buf), "%lu", vap->va_gen);
401 mydprintf(DINT DINT "gen: %s, ", buf);
402
403 DEFAULTBUF();
404 if (vap->va_flags != (u_long)PUFFS_VNOVAL)
405 snprintf(buf, sizeof(buf), "0x%lx", vap->va_flags);
406 mydprintf("flags: %s, ", buf);
407
408 DEFAULTBUF();
409 if (vap->va_rdev != (dev_t)PUFFS_VNOVAL)
410 snprintf(buf, sizeof(buf), "0x%llx",
411 (unsigned long long)vap->va_rdev);
412 mydprintf("rdev: %s\n", buf);
413
414 DEFAULTBUF();
415 if (vap->va_bytes != (u_quad_t)PUFFS_VNOVAL)
416 snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_bytes);
417 mydprintf(DINT DINT "bytes: %s, ", buf);
418
419 snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_filerev);
420 mydprintf("filerev: %s, ", buf);
421
422 snprintf(buf, sizeof(buf), "0x%x", vap->va_vaflags);
423 mydprintf("vaflags: %s\n", buf);
424 }
425
426 void
puffsdump_cookie(puffs_cookie_t c,const char * cookiename)427 puffsdump_cookie(puffs_cookie_t c, const char *cookiename)
428 {
429
430 mydprintf("%scookie: at %p\n", cookiename, c);
431 }
432
433 static const char *cn_opnames[] = {
434 "LOOKUP",
435 "CREATE",
436 "DELETE",
437 "RENAME"
438 };
439
440 void
puffsdump_cn(struct puffs_kcn * pkcn)441 puffsdump_cn(struct puffs_kcn *pkcn)
442 {
443
444 mydprintf(DINT "puffs_cn: \"%s\", len %zu op %s (flags 0x%x)\n",
445 pkcn->pkcn_name, pkcn->pkcn_namelen,
446 cn_opnames[pkcn->pkcn_nameiop & NAMEI_OPMASK],
447 pkcn->pkcn_flags);
448 }
449
450 void
puffsdump_lookup(struct puffs_req * preq)451 puffsdump_lookup(struct puffs_req *preq)
452 {
453 struct puffs_vnmsg_lookup *lookup_msg = (void *)preq;
454
455 puffsdump_cn(&lookup_msg->pvnr_cn);
456 }
457
458 void
puffsdump_lookup_rv(struct puffs_req * preq)459 puffsdump_lookup_rv(struct puffs_req *preq)
460 {
461 struct puffs_vnmsg_lookup *lookup_msg = (void *)preq;
462
463 mydprintf(DINT "new %p, type 0x%x, size 0x%"PRIu64", dev 0x%llx\n",
464 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
465 lookup_msg->pvnr_size, (unsigned long long)lookup_msg->pvnr_rdev);
466 }
467
468 void
puffsdump_create(struct puffs_req * preq)469 puffsdump_create(struct puffs_req *preq)
470 {
471 /* XXX: wrong type, but we know it fits the slot */
472 struct puffs_vnmsg_create *create_msg = (void *)preq;
473
474 dumpattr(&create_msg->pvnr_va);
475 }
476
477 void
puffsdump_create_rv(struct puffs_req * preq)478 puffsdump_create_rv(struct puffs_req *preq)
479 {
480 /* XXX: wrong type, but we know it fits the slot */
481 struct puffs_vnmsg_create *create_msg = (void *)preq;
482
483 mydprintf(DINT "new %p\n", create_msg->pvnr_newnode);
484 }
485
486 void
puffsdump_readwrite(struct puffs_req * preq)487 puffsdump_readwrite(struct puffs_req *preq)
488 {
489 struct puffs_vnmsg_rw *rw_msg = (void *)preq;
490
491 mydprintf(DINT "offset: %" PRId64 ", resid %zu, ioflag 0x%x\n",
492 rw_msg->pvnr_offset, rw_msg->pvnr_resid, rw_msg->pvnr_ioflag);
493 }
494
495 void
puffsdump_readwrite_rv(struct puffs_req * preq)496 puffsdump_readwrite_rv(struct puffs_req *preq)
497 {
498 struct puffs_vnmsg_rw *rw_msg = (void *)preq;
499
500 mydprintf(DINT "resid after op: %zu\n", rw_msg->pvnr_resid);
501 }
502
503 void
puffsdump_readdir_rv(struct puffs_req * preq)504 puffsdump_readdir_rv(struct puffs_req *preq)
505 {
506 struct puffs_vnmsg_readdir *readdir_msg = (void *)preq;
507
508 mydprintf(DINT "resid after op: %zu, eofflag %d\n",
509 readdir_msg->pvnr_resid, readdir_msg->pvnr_eofflag);
510 }
511
512 void
puffsdump_open(struct puffs_req * preq)513 puffsdump_open(struct puffs_req *preq)
514 {
515 struct puffs_vnmsg_open *open_msg = (void *)preq;
516
517 mydprintf(DINT "mode: 0x%x\n", open_msg->pvnr_mode);
518 }
519
520 void
puffsdump_targ(struct puffs_req * preq)521 puffsdump_targ(struct puffs_req *preq)
522 {
523 struct puffs_vnmsg_remove *remove_msg = (void *)preq; /* XXX! */
524
525 mydprintf(DINT "target cookie: %p\n", remove_msg->pvnr_cookie_targ);
526 }
527
528 void
puffsdump_readdir(struct puffs_req * preq)529 puffsdump_readdir(struct puffs_req *preq)
530 {
531 struct puffs_vnmsg_readdir *readdir_msg = (void *)preq;
532
533 mydprintf(DINT "read offset: %" PRId64 "\n", readdir_msg->pvnr_offset);
534 }
535
536 void
puffsdump_attr(struct puffs_req * preq)537 puffsdump_attr(struct puffs_req *preq)
538 {
539 struct puffs_vnmsg_setgetattr *attr_msg = (void *)preq;
540
541 dumpattr(&attr_msg->pvnr_va);
542 }
543