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