1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/mdb_modapi.h> 28 #include <sys/types.h> 29 #include <sys/refstr_impl.h> 30 #include <sys/vnode.h> 31 #include <sys/vfs.h> 32 33 #include "smbfs.h" 34 #include "smbfs_node.h" 35 36 #define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */ 37 38 /* 39 * This macro lets us easily use both sizeof (typename) 40 * and the string-ified typename for the error message. 41 */ 42 #define SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \ 43 if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \ 44 != sizeof (obj_type)) { \ 45 mdb_warn("error reading "#obj_type" at %p", obj_addr); \ 46 return (err); \ 47 } 48 49 /* 50 * We need to read in a private copy 51 * of every string we want to print out. 52 */ 53 void 54 print_str(uintptr_t addr) 55 { 56 char buf[64]; 57 int len, mx = sizeof (buf) - 4; 58 59 if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) { 60 mdb_printf(" (%p)", addr); 61 } else { 62 if (len > mx) 63 strcpy(&buf[mx], "..."); 64 mdb_printf(" %s", buf); 65 } 66 } 67 68 /* 69 * Dcmd (and callback function) to print a summary of 70 * all "smbfs" entries in the VFS list. 71 */ 72 73 typedef struct smbfs_vfs_cbdata { 74 int flags; 75 int printed_header; 76 uintptr_t vfsops; /* filter by vfs ops pointer */ 77 smbmntinfo_t smi; /* scratch space for smbfs_vfs_cb */ 78 } smbfs_vfs_cbdata_t; 79 80 int 81 smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg) 82 { 83 const vfs_t *vfs = data; 84 smbfs_vfs_cbdata_t *cbd = arg; 85 uintptr_t ta; 86 87 /* Filter by matching smbfs ops vector. */ 88 if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) { 89 return (WALK_NEXT); 90 } 91 92 if (cbd->printed_header == 0) { 93 cbd->printed_header = 1; 94 mdb_printf("// vfs_t smbmntinfo_t mnt_path\n"); 95 } 96 97 mdb_printf(" %-p", addr); /* vfs_t */ 98 mdb_printf(" %-p", (uintptr_t)vfs->vfs_data); 99 /* 100 * Note: vfs_mntpt is a refstr_t. 101 * Advance to string member. 102 */ 103 ta = (uintptr_t)vfs->vfs_mntpt; 104 ta += OFFSETOF(struct refstr, rs_string); 105 print_str(ta); 106 mdb_printf("\n"); 107 108 if (cbd->flags & OPT_VERBOSE) { 109 mdb_inc_indent(2); 110 /* Don't fail the walk if this fails. */ 111 if (mdb_vread(&cbd->smi, sizeof (cbd->smi), 112 (uintptr_t)vfs->vfs_data) == -1) { 113 mdb_warn("error reading smbmntinfo_t at %p", 114 (uintptr_t)vfs->vfs_data); 115 } else { 116 /* Interesting parts of smbmntinfo_t */ 117 mdb_printf("smi_share: %p, smi_root: %p\n", 118 cbd->smi.smi_share, cbd->smi.smi_root); 119 } 120 mdb_dec_indent(2); 121 } 122 123 return (WALK_NEXT); 124 } 125 126 int 127 smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 128 { 129 smbfs_vfs_cbdata_t *cbd; 130 vfs_t *vfs; 131 132 cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); 133 134 /* 135 * Get the ops address here, so things work 136 * even if the smbfs module is loaded later 137 * than this mdb module. 138 */ 139 if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) { 140 mdb_warn("failed to find 'smbfs_vfsops'\n"); 141 return (DCMD_ERR); 142 } 143 144 if (mdb_getopts(argc, argv, 145 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, 146 NULL) != argc) { 147 return (DCMD_USAGE); 148 } 149 150 if (!(flags & DCMD_ADDRSPEC)) { 151 if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd) 152 == -1) { 153 mdb_warn("can't walk smbfs vfs"); 154 return (DCMD_ERR); 155 } 156 return (DCMD_OK); 157 } 158 159 vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC); 160 SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR); 161 smbfs_vfs_cb(addr, vfs, cbd); 162 return (DCMD_OK); 163 } 164 165 void 166 smbfs_vfs_help(void) 167 { 168 mdb_printf( 169 "Display addresses of the mounted smbfs structures\n" 170 "and the pathname of the mountpoint\n" 171 "\nOptions:\n" 172 " -v display details of the smbmntinfo\n"); 173 } 174 175 /* 176 * Dcmd (and callback function) to print a summary of 177 * all smbnodes in the node "hash" (cache) AVL tree. 178 */ 179 180 typedef struct smbfs_node_cbdata { 181 int flags; 182 int printed_header; 183 vnode_t vn; 184 } smbfs_node_cbdata_t; 185 186 int 187 smbfs_node_cb(uintptr_t addr, const void *data, void *arg) 188 { 189 const smbnode_t *np = data; 190 smbfs_node_cbdata_t *cbd = arg; 191 192 if (cbd->printed_header == 0) { 193 cbd->printed_header = 1; 194 mdb_printf("// vnode smbnode rpath\n"); 195 } 196 197 mdb_printf(" %-p", (uintptr_t)np->r_vnode); 198 mdb_printf(" %-p", addr); /* smbnode */ 199 print_str((uintptr_t)np->n_rpath); 200 mdb_printf("\n"); 201 202 if (cbd->flags & OPT_VERBOSE) { 203 mdb_inc_indent(2); 204 /* Don't fail the walk if this fails. */ 205 if (mdb_vread(&cbd->vn, sizeof (cbd->vn), 206 (uintptr_t)np->r_vnode) == -1) { 207 mdb_warn("error reading vnode_t at %p", 208 (uintptr_t)np->r_vnode); 209 } else { 210 /* Interesting parts of vnode_t */ 211 mdb_printf("v_type=%d v_count=%d", 212 cbd->vn.v_type, cbd->vn.v_count); 213 mdb_printf("\n"); 214 } 215 mdb_dec_indent(2); 216 } 217 218 return (WALK_NEXT); 219 } 220 221 int 222 smbfs_node_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 223 { 224 smbfs_node_cbdata_t *cbd; 225 226 cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); 227 228 if (mdb_getopts(argc, argv, 229 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, 230 NULL) != argc) { 231 return (DCMD_USAGE); 232 } 233 234 if (!(flags & DCMD_ADDRSPEC)) { 235 mdb_warn("expect an smbmntinfo_t addr"); 236 return (DCMD_USAGE); 237 } 238 addr += OFFSETOF(smbmntinfo_t, smi_hash_avl); 239 240 if (mdb_pwalk("genunix`avl", smbfs_node_cb, cbd, addr) == -1) { 241 mdb_warn("cannot walk smbfs nodes"); 242 return (DCMD_ERR); 243 } 244 245 return (DCMD_OK); 246 } 247 248 void 249 smbfs_node_help(void) 250 { 251 mdb_printf("Options:\n" 252 " -v be verbose when displaying smbnodes\n"); 253 } 254 255 static const mdb_dcmd_t dcmds[] = { 256 { 257 "smbfs_vfs", "?[-v]", 258 "show smbfs-mounted vfs structs", 259 smbfs_vfs_dcmd, smbfs_vfs_help 260 }, 261 { 262 "smbfs_node", "?[-v]", 263 "given an smbmntinfo_t, list smbnodes", 264 smbfs_node_dcmd, smbfs_node_help 265 }, 266 {NULL} 267 }; 268 269 static const mdb_walker_t walkers[] = { 270 {NULL} 271 }; 272 273 static const mdb_modinfo_t modinfo = { 274 MDB_API_VERSION, 275 dcmds, 276 walkers 277 }; 278 279 const mdb_modinfo_t * 280 _mdb_init(void) 281 { 282 return (&modinfo); 283 } 284