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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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