xref: /illumos-gate/usr/src/cmd/mdb/common/modules/svc.configd/configd.c (revision 97a9db610324e7db4393415018e0e737485a94cd)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <mdb/mdb_modapi.h>
28 #include <mdb/mdb_ctf.h>
29 
30 #include <configd.h>
31 
32 mdb_ctf_id_t request_enum;
33 mdb_ctf_id_t response_enum;
34 mdb_ctf_id_t ptr_type_enum;
35 mdb_ctf_id_t thread_state_enum;
36 
37 hrtime_t max_time_seen;
38 
39 static void
40 enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val,
41     const char *prefix, const char *prefix2)
42 {
43 	const char *cp;
44 	size_t len = strlen(prefix);
45 	size_t len2 = strlen(prefix2);
46 
47 	if ((cp = mdb_ctf_enum_name(id, val)) != NULL) {
48 		if (strncmp(cp, prefix, len) == 0)
49 			cp += len;
50 		if (strncmp(cp, prefix2, len2) == 0)
51 			cp += len2;
52 		(void) strlcpy(out, cp, size);
53 	} else {
54 		mdb_snprintf(out, size, "? (%d)", val);
55 	}
56 }
57 
58 static void
59 make_lower(char *out, size_t sz)
60 {
61 	while (*out != 0 && sz > 0) {
62 		if (*out >= 'A' && *out <= 'Z')
63 			*out += 'a' - 'A';
64 		out++;
65 		sz--;
66 	}
67 }
68 
69 /*ARGSUSED*/
70 static int
71 configd_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
72 {
73 	int num_servers;
74 	int num_started;
75 
76 	if (argc != 0)
77 		return (DCMD_USAGE);
78 
79 	if (mdb_readvar(&num_servers, "num_servers") == -1) {
80 		mdb_warn("unable to read num_servers");
81 		return (DCMD_ERR);
82 	}
83 	if (mdb_readvar(&num_started, "num_started") == -1) {
84 		mdb_warn("unable to read num_started");
85 		return (DCMD_ERR);
86 	}
87 	mdb_printf(
88 	    "\nserver threads:\t%d running, %d starting\n\n", num_servers,
89 	    num_started - num_servers);
90 
91 	if (mdb_walk_dcmd("configd_threads", "configd_thread", argc,
92 	    argv) == -1) {
93 		mdb_warn("can't walk 'configd_threads'");
94 		return (DCMD_ERR);
95 	}
96 	return (DCMD_OK);
97 }
98 
99 /*ARGSUSED*/
100 static int
101 configd_thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
102 {
103 	thread_info_t t;
104 	char state[20];
105 	char oldstate[20];
106 
107 	if (!(flags & DCMD_ADDRSPEC)) {
108 		if (mdb_walk_dcmd("configd_threads", "configd_thread", argc,
109 		    argv) == -1) {
110 			mdb_warn("can't walk 'configd_threads'");
111 			return (DCMD_ERR);
112 		}
113 		return (DCMD_OK);
114 	}
115 
116 	if (argc != 0)
117 		return (DCMD_USAGE);
118 
119 	if (DCMD_HDRSPEC(flags)) {
120 		mdb_printf("%<u>%-?s %5s %-12s %-12s %-?s %-?s %-?s%</u>\n",
121 		    "ADDR", "TID", "STATE", "PREV_STATE", "CLIENT", "CLIENTRQ",
122 		    "MAINREQ");
123 	}
124 
125 	if (mdb_vread(&t, sizeof (t), addr) == -1) {
126 		mdb_warn("failed to read thread_info_t at %p", addr);
127 		return (DCMD_ERR);
128 	}
129 
130 	enum_lookup(state, sizeof (state), thread_state_enum,
131 	    t.ti_state, "TI_", "");
132 	make_lower(state, sizeof (state));
133 
134 	enum_lookup(oldstate, sizeof (oldstate), thread_state_enum,
135 	    t.ti_prev_state, "TI_", "");
136 	make_lower(oldstate, sizeof (oldstate));
137 
138 	mdb_printf("%0?p %5d %-12s %-12s %?p %?p %?p\n",
139 	    (void *)addr, t.ti_thread, state, oldstate,
140 	    t.ti_active_client, t.ti_client_request, t.ti_main_door_request);
141 
142 	return (DCMD_OK);
143 }
144 
145 static int
146 walk_thread_info_init(mdb_walk_state_t *wsp)
147 {
148 	if (mdb_readvar(&wsp->walk_addr, "thread_list") == -1) {
149 		mdb_warn("unable to read thread_list");
150 		return (WALK_ERR);
151 	}
152 
153 	if (mdb_layered_walk("uu_list_node", wsp) == -1) {
154 		mdb_warn("couldn't walk 'uu_list_node'");
155 		return (WALK_ERR);
156 	}
157 
158 	return (WALK_NEXT);
159 }
160 
161 static int
162 walk_thread_info_step(mdb_walk_state_t *wsp)
163 {
164 	uintptr_t addr = wsp->walk_addr;
165 	thread_info_t ti;
166 
167 	if (mdb_vread(&ti, sizeof (ti), addr) == -1) {
168 		mdb_warn("unable to read thread_info_t at %p", addr);
169 		return (WALK_ERR);
170 	}
171 
172 	return (wsp->walk_callback(addr, &ti, wsp->walk_cbdata));
173 }
174 
175 static int
176 request_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
177 {
178 	request_log_entry_t cur;
179 	hrtime_t dur;
180 	hrtime_t dursec;
181 	hrtime_t durnsec;
182 	char durstr[20];
183 	char stampstr[20];
184 	char requstr[30];
185 	char respstr[30];
186 	char typestr[30];
187 	uintptr_t node = 0;
188 	uintptr_t client = 0;
189 	uint64_t clientid = 0;
190 
191 	int idx;
192 	int opt_v = FALSE;			/* verbose */
193 
194 	if (!(flags & DCMD_ADDRSPEC)) {
195 		if (mdb_walk_dcmd("configd_log", "configd_log", argc,
196 		    argv) == -1) {
197 			mdb_warn("can't walk 'configd_log'");
198 			return (DCMD_ERR);
199 		}
200 		return (DCMD_OK);
201 	}
202 
203 	if (mdb_getopts(argc, argv,
204 	    'c', MDB_OPT_UINTPTR, &client,
205 	    'i', MDB_OPT_UINT64, &clientid,
206 	    'n', MDB_OPT_UINTPTR, &node,
207 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
208 		return (DCMD_USAGE);
209 
210 	if (DCMD_HDRSPEC(flags)) {
211 		mdb_printf("%<u>%-?s %-4s %-14s %9s %-22s %-17s\n%</u>",
212 		    "ADDR", "THRD", "START", "DURATION", "REQUEST",
213 		    "RESPONSE");
214 	}
215 
216 	if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
217 		mdb_warn("couldn't read log entry at %p", addr);
218 		return (DCMD_ERR);
219 	}
220 
221 	/*
222 	 * apply filters, if any.
223 	 */
224 	if (clientid != 0 && clientid != cur.rl_clientid)
225 		return (DCMD_OK);
226 
227 	if (client != 0 && client != (uintptr_t)cur.rl_client)
228 		return (DCMD_OK);
229 
230 	if (node != 0) {
231 		for (idx = 0; idx < MIN(MAX_PTRS, cur.rl_num_ptrs); idx++) {
232 			if ((uintptr_t)cur.rl_ptrs[idx].rlp_data == node) {
233 				node = 0;		/* found it */
234 				break;
235 			}
236 		}
237 		if (node != 0)
238 			return (DCMD_OK);
239 	}
240 
241 	enum_lookup(requstr, sizeof (requstr), request_enum, cur.rl_request,
242 	    "REP_PROTOCOL_", "");
243 
244 	if (cur.rl_end != 0) {
245 		enum_lookup(respstr, sizeof (respstr), response_enum,
246 		    cur.rl_response, "REP_PROTOCOL_", "FAIL_");
247 
248 		dur = cur.rl_end - cur.rl_start;
249 		dursec = dur / NANOSEC;
250 		durnsec = dur % NANOSEC;
251 
252 		if (dursec <= 9)
253 			mdb_snprintf(durstr, sizeof (durstr),
254 			    "%lld.%06lld",
255 			    dursec, durnsec / (NANOSEC / MICROSEC));
256 		else if (dursec <= 9999)
257 			mdb_snprintf(durstr, sizeof (durstr),
258 			    "%lld.%03lld",
259 			    dursec, NSEC2MSEC(durnsec));
260 		else
261 			mdb_snprintf(durstr, sizeof (durstr),
262 			    "%lld", dursec);
263 	} else {
264 		(void) strcpy(durstr, "-");
265 		(void) strcpy(respstr, "-");
266 	}
267 
268 	if (max_time_seen != 0 && max_time_seen >= cur.rl_start) {
269 		dur = max_time_seen - cur.rl_start;
270 		dursec = dur / NANOSEC;
271 		durnsec = dur % NANOSEC;
272 
273 		if (dursec <= 99ULL)
274 			mdb_snprintf(stampstr, sizeof (stampstr),
275 			    "-%lld.%09lld", dursec, durnsec);
276 		else if (dursec <= 99999ULL)
277 			mdb_snprintf(stampstr, sizeof (stampstr),
278 			    "-%lld.%06lld",
279 			    dursec, durnsec / (NANOSEC / MICROSEC));
280 		else if (dursec <= 99999999ULL)
281 			mdb_snprintf(stampstr, sizeof (stampstr),
282 			    "-%lld.%03lld",
283 			    dursec, NSEC2MSEC(durnsec));
284 		else
285 			mdb_snprintf(stampstr, sizeof (stampstr),
286 			    "-%lld", dursec);
287 	} else {
288 		(void) strcpy(stampstr, "-");
289 	}
290 
291 	mdb_printf("%0?x %4d T%13s %9s %-22s %-17s\n",
292 	    addr, cur.rl_tid, stampstr, durstr, requstr, respstr);
293 
294 	if (opt_v) {
295 		mdb_printf("\tclient: %?p (%d)\tptrs: %d\tstamp: %llx\n",
296 		    cur.rl_client, cur.rl_clientid, cur.rl_num_ptrs,
297 		    cur.rl_start);
298 		for (idx = 0; idx < MIN(MAX_PTRS, cur.rl_num_ptrs); idx++) {
299 			enum_lookup(typestr, sizeof (typestr), ptr_type_enum,
300 			    cur.rl_ptrs[idx].rlp_type, "RC_PTR_TYPE_", "");
301 			mdb_printf("\t\t%-7s %5d %?p %?p\n", typestr,
302 			    cur.rl_ptrs[idx].rlp_id, cur.rl_ptrs[idx].rlp_ptr,
303 			    cur.rl_ptrs[idx].rlp_data);
304 		}
305 		mdb_printf("\n");
306 	}
307 	return (DCMD_OK);
308 }
309 
310 struct request_log_walk {
311 	size_t		rlw_max;
312 	size_t		rlw_count;
313 	size_t		rlw_cur;
314 	struct request_entry {
315 		hrtime_t  timestamp;
316 		uintptr_t addr;
317 	}		*rlw_list;
318 };
319 
320 /*
321  * we want newer items at the top
322  */
323 static int
324 request_entry_compare(const void *l, const void *r)
325 {
326 	const struct request_entry *lp = l;
327 	const struct request_entry *rp = r;
328 
329 	if (rp->timestamp == lp->timestamp)
330 		return (0);
331 
332 	/*
333 	 * 0 timestamps go first.
334 	 */
335 	if (rp->timestamp == 0)
336 		return (1);
337 	if (lp->timestamp == 0)
338 		return (-1);
339 
340 	if (lp->timestamp < rp->timestamp)
341 		return (1);
342 	return (-1);
343 }
344 
345 /*ARGSUSED*/
346 static int
347 request_log_count_thread(uintptr_t addr, thread_info_t *tip, uint_t *arg)
348 {
349 	(*arg)++;
350 
351 	return (WALK_NEXT);
352 }
353 
354 static int
355 request_log_add_thread(uintptr_t addr, thread_info_t *tip,
356     struct request_entry **arg)
357 {
358 	if (max_time_seen < tip->ti_log.rl_start)
359 		max_time_seen = tip->ti_log.rl_start;
360 
361 	if (max_time_seen < tip->ti_log.rl_end)
362 		max_time_seen = tip->ti_log.rl_end;
363 
364 	if (tip->ti_log.rl_start != 0) {
365 		if (tip->ti_log.rl_end)
366 			(*arg)->timestamp = tip->ti_log.rl_start;
367 		else
368 			(*arg)->timestamp = 0;		/* sort to the top */
369 
370 		(*arg)->addr = addr + offsetof(thread_info_t, ti_log);
371 		++*arg;
372 	}
373 	return (WALK_NEXT);
374 }
375 
376 static int
377 request_log_walk_init(mdb_walk_state_t *wsp)
378 {
379 	struct request_log_walk *rlw;
380 	struct request_entry *list, *listp;
381 
382 	uint_t log_size;
383 	uint_t size;
384 	uint_t idx;
385 	uint_t pos;
386 	request_log_entry_t *base;
387 	request_log_entry_t cur;
388 
389 	if (mdb_readvar(&base, "request_log") == -1) {
390 		mdb_warn("couldn't read 'request_log'");
391 		return (WALK_ERR);
392 	}
393 	if (mdb_readvar(&log_size, "request_log_size") == -1) {
394 		mdb_warn("couldn't read 'request_log_size'");
395 		return (WALK_ERR);
396 	}
397 	size = log_size;
398 
399 	if (mdb_walk("configd_threads", (mdb_walk_cb_t)request_log_count_thread,
400 	    &size) == -1) {
401 		mdb_warn("couldn't walk 'configd_threads'");
402 		return (WALK_ERR);
403 	}
404 
405 	list = mdb_zalloc(sizeof (*list) * size, UM_SLEEP);
406 	listp = list;
407 
408 	if (mdb_walk("configd_threads", (mdb_walk_cb_t)request_log_add_thread,
409 	    &listp) == -1) {
410 		mdb_warn("couldn't walk 'configd_threads'");
411 		mdb_free(list, sizeof (*list) * size);
412 		return (WALK_ERR);
413 	}
414 
415 	pos = listp - list;
416 	for (idx = 0; idx < log_size; idx++) {
417 		uintptr_t addr = (uintptr_t)&base[idx];
418 		if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
419 			mdb_warn("couldn't read log entry at %p", addr);
420 			mdb_free(list, sizeof (*list) * size);
421 			return (WALK_ERR);
422 		}
423 
424 		if (max_time_seen < cur.rl_start)
425 			max_time_seen = cur.rl_start;
426 
427 		if (max_time_seen < cur.rl_end)
428 			max_time_seen = cur.rl_end;
429 
430 		if (cur.rl_start != 0) {
431 			list[pos].timestamp = cur.rl_start;
432 			list[pos].addr = addr;
433 			pos++;
434 		}
435 	}
436 	qsort(list, pos, sizeof (*list), &request_entry_compare);
437 
438 	rlw = mdb_zalloc(sizeof (*rlw), UM_SLEEP);
439 	rlw->rlw_max = size;
440 	rlw->rlw_count = pos;
441 	rlw->rlw_cur = 0;
442 	rlw->rlw_list = list;
443 
444 	wsp->walk_data = rlw;
445 
446 	return (WALK_NEXT);
447 }
448 
449 static int
450 request_log_walk_step(mdb_walk_state_t *wsp)
451 {
452 	struct request_log_walk *rlw = wsp->walk_data;
453 	uintptr_t addr;
454 	request_log_entry_t cur;
455 
456 	if (rlw->rlw_cur >= rlw->rlw_count)
457 		return (WALK_DONE);
458 
459 	addr = rlw->rlw_list[rlw->rlw_cur++].addr;
460 
461 	if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
462 		mdb_warn("couldn't read log entry at %p", addr);
463 		return (WALK_ERR);
464 	}
465 	return (wsp->walk_callback(addr, &cur, wsp->walk_cbdata));
466 }
467 
468 static void
469 request_log_walk_fini(mdb_walk_state_t *wsp)
470 {
471 	struct request_log_walk *rlw = wsp->walk_data;
472 
473 	mdb_free(rlw->rlw_list, sizeof (*rlw->rlw_list) * rlw->rlw_max);
474 	mdb_free(rlw, sizeof (*rlw));
475 }
476 
477 static const mdb_dcmd_t dcmds[] = {
478 	{ "configd_status", NULL, "svc.configd status summary",
479 	    configd_status },
480 	{ "configd_thread", "?", "Print a thread_info_t tabularly",
481 	    configd_thread },
482 	{ "configd_log", "?[-v] [-c clientptr] [-i clientid]",
483 	    "Print the request log, or a single entry", request_log },
484 	{ NULL }
485 };
486 
487 static const mdb_walker_t walkers[] = {
488 	{ "configd_threads", "walks the thread_info_ts for all "
489 	    "threads", walk_thread_info_init, walk_thread_info_step },
490 	{ "configd_log", "walks the request_log_entry_ts",
491 	    request_log_walk_init, request_log_walk_step,
492 	    request_log_walk_fini},
493 	{ NULL }
494 };
495 
496 static const mdb_modinfo_t modinfo = {
497 	MDB_API_VERSION, dcmds, walkers
498 };
499 
500 const mdb_modinfo_t *
501 _mdb_init(void)
502 {
503 	if (mdb_ctf_lookup_by_name("enum rep_protocol_requestid",
504 	    &request_enum) == -1) {
505 		mdb_warn("enum rep_protocol_requestid not found");
506 	}
507 	if (mdb_ctf_lookup_by_name("enum rep_protocol_responseid",
508 	    &response_enum) == -1) {
509 		mdb_warn("enum rep_protocol_responseid not found");
510 	}
511 	if (mdb_ctf_lookup_by_name("enum rc_ptr_type",
512 	    &ptr_type_enum) == -1) {
513 		mdb_warn("enum rc_ptr_type not found");
514 	}
515 	if (mdb_ctf_lookup_by_name("enum thread_state",
516 	    &thread_state_enum) == -1) {
517 		mdb_warn("enum thread_state not found");
518 	}
519 	return (&modinfo);
520 }
521