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