xref: /illumos-gate/usr/src/cmd/mdb/common/modules/nfs/svc.c (revision 86d949f9)
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 *
svc_idname(uint_t id)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
svc_print_pool(SVCPOOL * pool,uintptr_t addr)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
svc_pool_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
svc_pool_help(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
svc_print_masterxprt(SVCMASTERXPRT * xprt)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
svc_mxprt_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
svc_mxprt_help(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
svc_get_pool(uintptr_t zone_addr,uintptr_t * svc_addr)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
svc_pool_walk_init(mdb_walk_state_t * wsp)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
svc_pool_walk_step(mdb_walk_state_t * wsp)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
svc_mxprt_walk_init(mdb_walk_state_t * wsp)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
svc_mxprt_walk_step(mdb_walk_state_t * wsp)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