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