1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 /* 12 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 13 */ 14 15 #include <sys/mdb_modapi.h> 16 #include <mdb/mdb_ctf.h> 17 #include <sys/types.h> 18 #include <sys/zone.h> 19 #include <rpc/svc.h> 20 21 #include "common.h" 22 #include "svc.h" 23 24 /* 25 * svc_pool dcmd implementation 26 */ 27 28 static const char * 29 svc_idname(uint_t id) 30 { 31 switch (id) { 32 case NFS_SVCPOOL_ID: 33 return ("NFS"); 34 case NLM_SVCPOOL_ID: 35 return ("NLM"); 36 case NFS_CB_SVCPOOL_ID: 37 return ("NFS_CB"); 38 default: 39 return (""); 40 } 41 } 42 43 static void 44 svc_print_pool(SVCPOOL *pool, uintptr_t addr) 45 { 46 mdb_printf("SVCPOOL = %p -> POOL ID = %s(%d)\n", addr, 47 svc_idname(pool->p_id), pool->p_id); 48 mdb_printf("Non detached threads = %d\n", pool->p_threads); 49 mdb_printf("Detached threads = %d\n", pool->p_detached_threads); 50 mdb_printf("Max threads = %d\n", pool->p_maxthreads); 51 mdb_printf("`redline' = %d\n", pool->p_redline); 52 mdb_printf("Reserved threads = %d\n", pool->p_reserved_threads); 53 mdb_printf("Thread lock = %s\n", 54 common_mutex(&pool->p_thread_lock)); 55 56 mdb_printf("Asleep threads = %d\n", pool->p_asleep); 57 mdb_printf("Request lock = %s\n", 58 common_mutex(&pool->p_req_lock)); 59 60 mdb_printf("Pending requests = %d\n", pool->p_reqs); 61 mdb_printf("Walking threads = %d\n", pool->p_walkers); 62 mdb_printf("Max requests from xprt = %d\n", pool->p_max_same_xprt); 63 mdb_printf("Stack size for svc_run = %d\n", pool->p_stksize); 64 mdb_printf("Creator lock = %s\n", 65 common_mutex(&pool->p_creator_lock)); 66 67 mdb_printf("No of Master xprt's = %d\n", pool->p_lcount); 68 mdb_printf("rwlock for mxprtlist = %s\n", 69 common_rwlock(&pool->p_lrwlock)); 70 mdb_printf("master xprt list ptr = %p\n\n", pool->p_lhead); 71 } 72 73 int 74 svc_pool_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 75 { 76 SVCPOOL svcpool; 77 uint_t opt_v = FALSE; 78 int *pools; 79 int count, i; 80 81 if ((flags & DCMD_ADDRSPEC) == 0) { 82 /* Walk through all svcpools in the global zone */ 83 if (mdb_walk_dcmd("svc_pool", "svc_pool", argc, argv) == -1) { 84 mdb_warn("failed to walk svcpools"); 85 return (DCMD_ERR); 86 } 87 return (DCMD_OK); 88 } 89 90 count = mdb_getopts(argc, argv, 91 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL); 92 argc -= count; 93 argv += count; 94 95 pools = mdb_alloc(argc * sizeof (*pools), UM_SLEEP | UM_GC); 96 for (i = 0; i < argc; i++) { 97 const char *s; 98 99 switch (argv[i].a_type) { 100 case MDB_TYPE_STRING: 101 s = argv[i].a_un.a_str; 102 103 if (strcmp(s, "nfs") == 0) 104 pools[i] = NFS_SVCPOOL_ID; 105 else if (strcmp(s, "nlm") == 0) 106 pools[i] = NLM_SVCPOOL_ID; 107 else if (strcmp(s, "nfs_cb") == 0) 108 pools[i] = NFS_CB_SVCPOOL_ID; 109 else 110 return (DCMD_USAGE); 111 112 break; 113 114 case MDB_TYPE_IMMEDIATE: 115 pools[i] = (int)argv[i].a_un.a_val; 116 break; 117 118 default: 119 return (DCMD_USAGE); 120 } 121 } 122 123 if (mdb_vread(&svcpool, sizeof (svcpool), addr) == -1) { 124 mdb_warn("failed to read svcpool"); 125 return (DCMD_ERR); 126 } 127 128 /* 129 * Make sure the svcpool is on the list (or the list is empty). 130 * If not, just return with DCMD_OK. 131 */ 132 for (i = 0; i < argc; i++) { 133 if (svcpool.p_id == pools[i]) { 134 argc = 0; 135 break; 136 } 137 } 138 if (argc != 0) 139 return (DCMD_OK); 140 141 /* Print the svcpool */ 142 svc_print_pool(&svcpool, addr); 143 if (opt_v && svcpool.p_lhead && (mdb_pwalk_dcmd("svc_mxprt", 144 "svc_mxprt", 0, NULL, (uintptr_t)svcpool.p_lhead) == -1)) 145 return (DCMD_ERR); 146 147 return (DCMD_OK); 148 } 149 150 void 151 svc_pool_help(void) 152 { 153 mdb_printf( 154 "-v display also the master xprts for the svcpools\n" 155 "poolid either $[numeric] or verbose: nfs or nlm or nfs_cb\n" 156 "\n" 157 "If the poolid list is specified, only those svcpools are dumped\n" 158 "whose poolid is in the list.\n"); 159 } 160 161 /* 162 * svc_mxprt dcmd implementation 163 */ 164 165 static void 166 svc_print_masterxprt(SVCMASTERXPRT *xprt) 167 { 168 mdb_printf("svcxprt_common structure:\n"); 169 mdb_printf("queue ptr = %p\n", xprt->xp_wq); 170 mdb_printf("cached cred for server = %d\n", xprt->xp_cred); 171 mdb_printf("transport type = %d\n", xprt->xp_type); 172 mdb_printf("TSDU or TIDU size = %d\n", xprt->xp_msg_size); 173 174 mdb_printf("address = %s\n", 175 common_netbuf_str(&xprt->xp_rtaddr)); 176 mdb_printf("Request queue head = %p\n", xprt->xp_req_head); 177 mdb_printf("Request queue tail = %p\n", xprt->xp_req_tail); 178 mdb_printf("Request lock address = %s\n", 179 common_mutex(&xprt->xp_req_lock)); 180 181 mdb_printf("Current no of attached threads = %d\n", 182 xprt->xp_threads); 183 mdb_printf("Current no of detached threads = %d\n", 184 xprt->xp_detached_threads); 185 mdb_printf("Thread count lock address = %s\n\n", 186 common_mutex(&xprt->xp_thread_lock)); 187 } 188 189 int 190 svc_mxprt_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 191 { 192 SVCMASTERXPRT xprt; 193 uint_t opt_w = FALSE; 194 195 if (mdb_getopts(argc, argv, 196 'w', MDB_OPT_SETBITS, TRUE, &opt_w, NULL) != argc) 197 return (DCMD_USAGE); 198 199 if ((flags & DCMD_ADDRSPEC) == 0) { 200 mdb_printf("requires address of SVCMASTERXPRT\n"); 201 return (DCMD_USAGE); 202 } 203 204 if (opt_w) { 205 /* Walk through all xprts */ 206 if (mdb_pwalk_dcmd("svc_mxprt", "svc_mxprt", 0, NULL, 207 addr) == -1) { 208 mdb_warn("failed to walk svc_mxprt"); 209 return (DCMD_ERR); 210 } 211 return (DCMD_OK); 212 } 213 214 if (mdb_vread(&xprt, sizeof (xprt), addr) == -1) { 215 mdb_warn("failed to read xprt"); 216 return (DCMD_ERR); 217 } 218 219 svc_print_masterxprt(&xprt); 220 221 return (DCMD_OK); 222 } 223 224 void 225 svc_mxprt_help(void) 226 { 227 mdb_printf( 228 "-w walks along all master xprts in the list\n" 229 "\n" 230 "The following two commands are equivalent:\n" 231 " ::svc_mxprt -w\n" 232 " ::walk svc_mxprt|::svc_mxprt\n"); 233 } 234 235 /* 236 * svc_pool walker implementation 237 */ 238 239 static int 240 svc_get_pool(uintptr_t zone_addr, uintptr_t *svc_addr) 241 { 242 mdb_ctf_id_t id; 243 ulong_t offset; 244 uintptr_t glob_addr; 245 246 if (zoned_get_zsd(zone_addr, "svc_zone_key", &glob_addr) != DCMD_OK) { 247 mdb_warn("failed to get zoned svc"); 248 return (WALK_ERR); 249 } 250 251 if (mdb_ctf_lookup_by_name("struct svc_globals", &id)) { 252 mdb_warn("failed to look up type %s", "struct svc_globals"); 253 return (WALK_ERR); 254 } 255 256 if (mdb_ctf_offsetof(id, "svc_pools", &offset)) { 257 mdb_warn("failed to get %s offset", "svc_pools"); 258 return (WALK_ERR); 259 } 260 261 offset /= NBBY; 262 if (mdb_vread(svc_addr, sizeof (*svc_addr), glob_addr + offset) == -1) { 263 mdb_warn("failed to read svc_pools address"); 264 return (WALK_ERR); 265 } 266 267 return (WALK_NEXT); 268 } 269 270 int 271 svc_pool_walk_init(mdb_walk_state_t *wsp) 272 { 273 /* Use global zone by default */ 274 if (wsp->walk_addr == 0) { 275 /* wsp->walk_addr = global_zone */ 276 if (mdb_readvar(&wsp->walk_addr, "global_zone") == -1) { 277 mdb_warn("failed to locate global_zone"); 278 return (WALK_ERR); 279 } 280 } 281 282 /* put svcpool address of the zone into wsp->walk_addr */ 283 return (svc_get_pool(wsp->walk_addr, &wsp->walk_addr)); 284 } 285 286 int 287 svc_pool_walk_step(mdb_walk_state_t *wsp) 288 { 289 SVCPOOL pool; 290 uintptr_t addr = wsp->walk_addr; 291 292 if (addr == 0) 293 return (WALK_DONE); 294 295 if (mdb_vread(&pool, sizeof (pool), addr) == -1) { 296 mdb_warn("failed to read SVCPOOL"); 297 return (WALK_ERR); 298 } 299 300 wsp->walk_addr = (uintptr_t)pool.p_next; 301 return (wsp->walk_callback(addr, &pool, wsp->walk_cbdata)); 302 } 303 304 /* 305 * svc_mxprt walker implementation 306 */ 307 308 int 309 svc_mxprt_walk_init(mdb_walk_state_t *wsp) 310 { 311 if (wsp->walk_addr == 0) { 312 mdb_warn("global walk not supported"); 313 return (WALK_ERR); 314 } 315 316 wsp->walk_data = (void *)wsp->walk_addr; 317 318 return (WALK_NEXT); 319 } 320 321 int 322 svc_mxprt_walk_step(mdb_walk_state_t *wsp) 323 { 324 SVCMASTERXPRT xprt; 325 uintptr_t addr = wsp->walk_addr; 326 int status; 327 328 if (mdb_vread(&xprt, sizeof (xprt), addr) == -1) { 329 mdb_warn("can't read SVCMASTERXPRT"); 330 return (WALK_ERR); 331 } 332 333 wsp->walk_addr = (uintptr_t)xprt.xp_next; 334 335 status = wsp->walk_callback(addr, &xprt, wsp->walk_cbdata); 336 if (status != WALK_NEXT) 337 return (status); 338 339 return (((void *)wsp->walk_addr == wsp->walk_data) ? WALK_DONE 340 : WALK_NEXT); 341 } 342