static int pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) { vnode_t v, layer_vn; int myfd = cb->fd; const char *type; char path[MAXPATHLEN]; uintptr_t top_vnodep, realvpp; char fsname[_ST_FSTYPSZ]; int err, i; cb->fd++; if (addr == NULL) { return (WALK_NEXT); } top_vnodep = realvpp = (uintptr_t)f->f_vnode; if (mdb_vread(&v, sizeof (v), realvpp) == -1) { mdb_warn("failed to read vnode"); return (DCMD_ERR); } type = "?"; for (i = 0; i <= NUM_FS_TYPES; i++) { if (fs_types[i].type == v.v_type) type = fs_types[i].name; } do { uintptr_t next_realvpp; err = next_realvp(realvpp, &layer_vn, &next_realvpp); if (next_realvpp != NULL) realvpp = next_realvpp; } while (err == REALVP_CONTINUE); if (err == REALVP_ERR) { mdb_warn("failed to do realvp() for %p", realvpp); return (DCMD_ERR); } if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1) return (DCMD_ERR); mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep); if (cb->opt_p) { if (pfiles_dig_pathname(top_vnodep, path) == -1) return (DCMD_ERR); mdb_printf("%s\n", path); return (DCMD_OK); } /* * Sockets generally don't have interesting pathnames; we only * show those in the '-p' view. */ path[0] = '\0'; if (v.v_type != VSOCK) { if (pfiles_dig_pathname(top_vnodep, path) == -1) return (DCMD_ERR); } mdb_printf("%s%s", path, path[0] == '\0' ? "" : " "); switch (v.v_type) { case VDOOR: { door_node_t doornode; proc_t pr; if (mdb_vread(&doornode, sizeof (doornode), (uintptr_t)layer_vn.v_data) == -1) { mdb_warn("failed to read door_node"); return (DCMD_ERR); } if (mdb_vread(&pr, sizeof (pr), (uintptr_t)doornode.door_target) == -1) { mdb_warn("failed to read door server process %p", doornode.door_target); return (DCMD_ERR); } mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm, doornode.door_target); break; } case VSOCK: { struct sonode sonode; if (pfiles_get_sonode(realvpp, &sonode) == -1) return (DCMD_ERR); /* * If the address is cached in the sonode, use it; otherwise, * we print nothing. */ if (sonode.so_state & SS_LADDR_VALID) { struct sockaddr *laddr = mdb_alloc(sonode.so_laddr_len, UM_SLEEP); if (mdb_vread(laddr, sonode.so_laddr_len, (uintptr_t)sonode.so_laddr_sa) == -1) { mdb_warn("failed to read sonode socket addr"); return (DCMD_ERR); } mdb_printf("socket: "); pfiles_print_addr(laddr); } if (sonode.so_state & SS_FADDR_VALID) { struct sockaddr *faddr = mdb_alloc(sonode.so_faddr_len, UM_SLEEP); if (mdb_vread(faddr, sonode.so_faddr_len, (uintptr_t)sonode.so_faddr_sa) == -1) { mdb_warn("failed to read sonode remote addr"); return (DCMD_ERR); } mdb_printf("remote: "); pfiles_print_addr(faddr); } break; } case VPORT: mdb_printf("[event port (port=%p)]", v.v_data); break; case VPROC: { prnode_t prnode; prcommon_t prcommon; if (mdb_vread(&prnode, sizeof (prnode), (uintptr_t)layer_vn.v_data) == -1) { mdb_warn("failed to read prnode"); return (DCMD_ERR); } if (mdb_vread(&prcommon, sizeof (prcommon), (uintptr_t)prnode.pr_common) == -1) { mdb_warn("failed to read prcommon %p", prnode.pr_common); return (DCMD_ERR); } mdb_printf("(proc=%p)", prcommon.prc_proc); break; } default: break; } mdb_printf("\n"); return (WALK_NEXT); }
/*ARGSUSED*/ int fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { vfs_t vfs; int len; int opt_v = 0; char buf[MAXPATHLEN]; char fsname[_ST_FSTYPSZ]; mntopt_t *mntopts; size_t size; int i; int first = 1; char opt[MAX_MNTOPT_STR]; uintptr_t global_zone; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) { mdb_warn("failed to walk file system list"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) return (DCMD_USAGE); if (DCMD_HDRSPEC(flags)) mdb_printf("%<u>%?s %-15s %s%</u>\n", "VFSP", "FS", "MOUNT"); if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) { mdb_warn("failed to read vfs_t %p", addr); return (DCMD_ERR); } if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf, sizeof (buf))) <= 0) strcpy(buf, "??"); else if (!opt_v && (len >= FSINFO_MNTLEN)) /* * In normal mode, we truncate the path to keep the output * clean. In -v mode, we just print the full path. */ strcpy(&buf[FSINFO_MNTLEN - 4], "..."); if (read_fsname(addr, fsname) == -1) return (DCMD_ERR); mdb_printf("%0?p %-15s %s\n", addr, fsname, buf); if (!opt_v) return (DCMD_OK); /* * Print 'resource' string; this shows what we're mounted upon. */ if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf, MAXPATHLEN) <= 0) strcpy(buf, "??"); mdb_printf("%?s %s\n", "R:", buf); /* * Print mount options array; it sucks to be a mimic, but we copy * the same logic as in mntvnops.c for adding zone= tags, and we * don't bother with the obsolete dev= option. */ size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t); mntopts = mdb_alloc(size, UM_SLEEP | UM_GC); if (mdb_vread(mntopts, size, (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) { mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list); return (DCMD_ERR); } for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) { if (mntopts[i].mo_flags & MO_SET) { if (mdb_readstr(opt, sizeof (opt), (uintptr_t)mntopts[i].mo_name) == -1) { mdb_warn("failed to read mntopt name %p", mntopts[i].mo_name); return (DCMD_ERR); } if (first) { mdb_printf("%?s ", "O:"); first = 0; } else { mdb_printf(","); } mdb_printf("%s", opt); if (mntopts[i].mo_flags & MO_HASVALUE) { if (mdb_readstr(opt, sizeof (opt), (uintptr_t)mntopts[i].mo_arg) == -1) { mdb_warn("failed to read mntopt " "value %p", mntopts[i].mo_arg); return (DCMD_ERR); } mdb_printf("=%s", opt); } } } if (mdb_readvar(&global_zone, "global_zone") == -1) { mdb_warn("failed to locate global_zone"); return (DCMD_ERR); } if ((vfs.vfs_zone != NULL) && ((uintptr_t)vfs.vfs_zone != global_zone)) { zone_t z; if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) { mdb_warn("failed to read zone"); return (DCMD_ERR); } /* * zone names are much shorter than MAX_MNTOPT_STR */ if (mdb_readstr(opt, sizeof (opt), (uintptr_t)z.zone_name) == -1) { mdb_warn("failed to read zone name"); return (DCMD_ERR); } if (first) { mdb_printf("%?s ", "O:"); } else { mdb_printf(","); } mdb_printf("zone=%s", opt); } return (DCMD_OK); }
static int next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp) { char fsname[_ST_FSTYPSZ]; *outvp = invp; if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) { mdb_warn("failed to read vnode at %p", invp); return (REALVP_ERR); } if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1) return (REALVP_ERR); /* * We know how to do 'realvp' for as many filesystems as possible; * for all other filesystems, we assume that the vp we are given * is the realvp. In the kernel, a realvp operation will sometimes * dig through multiple layers. Here, we only fetch the pointer * to the next layer down. This allows dcmds to print out the * various layers. */ if (strcmp(fsname, "fifofs") == 0) { fifonode_t fn; if (mdb_vread(&fn, sizeof (fn), (uintptr_t)outvn->v_data) == -1) { mdb_warn("failed to read fifonode"); return (REALVP_ERR); } *outvp = (uintptr_t)fn.fn_realvp; } else if (strcmp(fsname, "namefs") == 0) { struct namenode nn; if (mdb_vread(&nn, sizeof (nn), (uintptr_t)outvn->v_data) == -1) { mdb_warn("failed to read namenode"); return (REALVP_ERR); } *outvp = (uintptr_t)nn.nm_filevp; } else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) { struct stdata stream; /* * Sockets have a strange and different layering scheme; we * hop over into the sockfs vnode (accessible via the stream * head) if possible. */ if (mdb_vread(&stream, sizeof (stream), (uintptr_t)outvn->v_stream) == -1) { mdb_warn("failed to read stream data"); return (REALVP_ERR); } *outvp = (uintptr_t)stream.sd_vnode; } if (*outvp == invp || *outvp == NULL) return (REALVP_DONE); return (REALVP_CONTINUE); }
static int pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) { vnode_t v, layer_vn; int myfd = cb->fd; const char *type; char path[MAXPATHLEN]; uintptr_t top_vnodep, realvpp; char fsname[_ST_FSTYPSZ]; int err, i; cb->fd++; if (addr == NULL) { return (WALK_NEXT); } top_vnodep = realvpp = (uintptr_t)f->f_vnode; if (mdb_vread(&v, sizeof (v), realvpp) == -1) { mdb_warn("failed to read vnode"); return (DCMD_ERR); } type = "?"; for (i = 0; i < NUM_FS_TYPES; i++) { if (fs_types[i].type == v.v_type) { type = fs_types[i].name; break; } } do { uintptr_t next_realvpp; err = next_realvp(realvpp, &layer_vn, &next_realvpp); if (next_realvpp != NULL) realvpp = next_realvpp; } while (err == REALVP_CONTINUE); if (err == REALVP_ERR) { mdb_warn("failed to do realvp() for %p", realvpp); return (DCMD_ERR); } if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1) return (DCMD_ERR); mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep); if (cb->opt_p) { if (pfiles_dig_pathname(top_vnodep, path) == -1) return (DCMD_ERR); mdb_printf("%s\n", path); return (DCMD_OK); } /* * Sockets generally don't have interesting pathnames; we only * show those in the '-p' view. */ path[0] = '\0'; if (v.v_type != VSOCK) { if (pfiles_dig_pathname(top_vnodep, path) == -1) return (DCMD_ERR); } mdb_printf("%s%s", path, path[0] == '\0' ? "" : " "); switch (v.v_type) { case VDOOR: { door_node_t doornode; proc_t pr; if (mdb_vread(&doornode, sizeof (doornode), (uintptr_t)layer_vn.v_data) == -1) { mdb_warn("failed to read door_node"); return (DCMD_ERR); } if (mdb_vread(&pr, sizeof (pr), (uintptr_t)doornode.door_target) == -1) { mdb_warn("failed to read door server process %p", doornode.door_target); return (DCMD_ERR); } mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm, doornode.door_target); break; } case VSOCK: { vnode_t v_sock; struct sonode so; if (mdb_vread(&v_sock, sizeof (v_sock), realvpp) == -1) { mdb_warn("failed to read socket vnode"); return (DCMD_ERR); } /* * Sockets can be non-stream or stream, they have to be dealed * with differently. */ if (v_sock.v_stream == NULL) { if (pfiles_get_sonode(&v_sock, &so) == -1) return (DCMD_ERR); /* Pick the proper methods. */ for (i = 0; i <= NUM_SOCK_PRINTS; i++) { if ((sock_prints[i].family == so.so_family && sock_prints[i].type == so.so_type && sock_prints[i].pro == so.so_protocol) || (sock_prints[i].family == so.so_family && sock_prints[i].type == so.so_type && so.so_type == SOCK_RAW)) { if ((*sock_prints[i].print)(&so) == -1) return (DCMD_ERR); } } } else { sotpi_sonode_t sotpi_sonode; if (pfiles_get_sonode(&v_sock, &so) == -1) return (DCMD_ERR); /* * If the socket is a fallback socket, read its related * information separately; otherwise, read it as a whole * tpi socket. */ if (so.so_state & SS_FALLBACK_COMP) { sotpi_sonode.st_sonode = so; if (mdb_vread(&(sotpi_sonode.st_info), sizeof (sotpi_info_t), (uintptr_t)so.so_priv) == -1) return (DCMD_ERR); } else { if (pfiles_get_tpi_sonode(&v_sock, &sotpi_sonode) == -1) return (DCMD_ERR); } if (tpi_sock_print(&sotpi_sonode) == -1) return (DCMD_ERR); } break; } case VPORT: mdb_printf("[event port (port=%p)]", v.v_data); break; case VPROC: { prnode_t prnode; prcommon_t prcommon; if (mdb_vread(&prnode, sizeof (prnode), (uintptr_t)layer_vn.v_data) == -1) { mdb_warn("failed to read prnode"); return (DCMD_ERR); } if (mdb_vread(&prcommon, sizeof (prcommon), (uintptr_t)prnode.pr_common) == -1) { mdb_warn("failed to read prcommon %p", prnode.pr_common); return (DCMD_ERR); } mdb_printf("(proc=%p)", prcommon.prc_proc); break; } default: break; } mdb_printf("\n"); return (WALK_NEXT); }