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 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <mdb/mdb_modapi.h>
26
27 #include <libuutil.h>
28 #include <libuutil_impl.h>
29
30 #include <librestart_priv.h> /* instance_data_t */
31 #include <startd.h>
32
33
34 /*
35 * To count the elements of a uu_list_t without knowing its implementation, we
36 * must walk & count them.
37 */
38 /* ARGSUSED */
39 static int
inc_sz(uintptr_t addr,const void * unknown,void * data)40 inc_sz(uintptr_t addr, const void *unknown, void *data)
41 {
42 size_t *sz = data;
43
44 ++(*sz);
45
46 return (WALK_NEXT);
47 }
48
49 /*ARGSUSED*/
50 static int
startd_status(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)51 startd_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
52 {
53 uu_list_t *dgraphp;
54 restarter_instance_list_t ril;
55 u_longlong_t ns_total;
56 u_longlong_t lookups;
57 u_longlong_t dep_inserts, dep_cycle_ns, dep_insert_ns;
58 size_t graph_num, restarter_num;
59 uint64_t ct_maint;
60 uint64_t ct_hwerr;
61 uint64_t ct_service;
62 uint64_t ct_global;
63 uint64_t ct_noprefs;
64 uint64_t ct_from_uninit;
65 uint64_t ct_bad_state;
66 uint64_t ct_ovr_prefs;
67
68 if (mdb_readvar(&lookups, "dictionary_lookups") == -1) {
69 mdb_warn("failed to read 'dictionary_lookups' value\n");
70 return (DCMD_ERR);
71 }
72
73 if (mdb_readvar(&ns_total, "dictionary_ns_total") == -1) {
74 mdb_warn("failed to read 'dictionary_ns_total' value\n");
75 return (DCMD_ERR);
76 }
77
78 if (mdb_readvar(&dep_inserts, "dep_inserts") == -1) {
79 mdb_warn("failed to read 'dep_inserts' value\n");
80 return (DCMD_ERR);
81 }
82
83 if (mdb_readvar(&dep_cycle_ns, "dep_cycle_ns") == -1) {
84 mdb_warn("failed to read 'dep_cycle_ns' value\n");
85 return (DCMD_ERR);
86 }
87
88 if (mdb_readvar(&dep_insert_ns, "dep_insert_ns") == -1) {
89 mdb_warn("failed to read 'dep_insert_ns' value\n");
90 return (DCMD_ERR);
91 }
92
93 if (mdb_readvar(&dgraphp, "dgraph") == -1) {
94 mdb_warn("failed to read 'dgraph' value\n");
95 return (DCMD_ERR);
96 }
97
98 graph_num = 0;
99 if (mdb_pwalk("uu_list_node", inc_sz, &graph_num,
100 (uintptr_t)dgraphp) == -1) {
101 mdb_warn("failed to read uu_list\n");
102 return (DCMD_ERR);
103 }
104
105 if (mdb_readvar(&ril, "instance_list") == -1) {
106 mdb_warn("failed to read 'instance_list' value\n");
107 return (DCMD_ERR);
108 }
109
110 restarter_num = 0;
111 if (mdb_pwalk("uu_list_node", inc_sz, &restarter_num,
112 (uintptr_t)ril.ril_instance_list) == -1) {
113 mdb_warn("failed to read uu_list\n");
114 return (DCMD_ERR);
115 }
116
117 if (mdb_readvar(&ct_maint, "stev_ct_maint") == -1) {
118 mdb_warn("failed to read 'stev_ct_maint'\n");
119 return (DCMD_ERR);
120 }
121
122 if (mdb_readvar(&ct_hwerr, "stev_ct_hwerr") == -1) {
123 mdb_warn("failed to read 'stev_ct_hwerr'\n");
124 return (DCMD_ERR);
125 }
126
127 if (mdb_readvar(&ct_service, "stev_ct_service") == -1) {
128 mdb_warn("failed to read 'stev_ct_service'\n");
129 return (DCMD_ERR);
130 }
131
132 if (mdb_readvar(&ct_global, "stev_ct_global") == -1) {
133 mdb_warn("failed to read 'stev_ct_global'\n");
134 return (DCMD_ERR);
135 }
136
137 if (mdb_readvar(&ct_noprefs, "stev_ct_noprefs") == -1) {
138 mdb_warn("failed to read 'stev_ct_noprefs'\n");
139 return (DCMD_ERR);
140 }
141
142 if (mdb_readvar(&ct_from_uninit, "stev_ct_from_uninit") == -1) {
143 mdb_warn("failed to read 'stev_ct_from_uninit'\n");
144 return (DCMD_ERR);
145 }
146
147 if (mdb_readvar(&ct_bad_state, "stev_ct_bad_state") == -1) {
148 mdb_warn("failed to read 'stev_ct_bad_state'\n");
149 return (DCMD_ERR);
150 }
151
152 if (mdb_readvar(&ct_ovr_prefs, "stev_ct_ovr_prefs") == -1) {
153 mdb_warn("failed to read 'stev_ct_ovr_prefs'\n");
154 return (DCMD_ERR);
155 }
156
157 mdb_printf(
158 "General stats\n"
159 " dictionary lookups: %llu\n"
160 " average lookup time: %llu us\n"
161 " graph dependency insertions: %llu\n"
162 " average cycle-check time: %llu us\n"
163 " avg dependency insert time: %llu us\n"
164 " number of nodes in dgraph: %llu\n"
165 "number of nodes in instance_list: %llu\n"
166 "\nState Transition Events\n"
167 " maintenance: %llu\n"
168 " hardware error: %llu\n"
169 " service specific pref: %llu\n"
170 " system wide pref: %llu\n"
171 " no prefs, not raised: %llu\n"
172 " from unint, not raised: %llu\n"
173 " bad state, not raised: %llu\n"
174 " override pref, raised: %llu\n", lookups,
175 lookups ? ns_total / (1000 * lookups) : 0, dep_inserts,
176 dep_inserts ? dep_cycle_ns / (1000 * dep_inserts) : 0,
177 dep_inserts ? dep_insert_ns / (1000 * dep_inserts) : 0,
178 (u_longlong_t)graph_num, (u_longlong_t)restarter_num,
179 ct_maint, ct_hwerr, ct_service, ct_global, ct_noprefs,
180 ct_from_uninit, ct_bad_state, ct_ovr_prefs);
181
182
183 return (DCMD_OK);
184 }
185
186 static char
xstate2chr(restarter_instance_state_t s)187 xstate2chr(restarter_instance_state_t s)
188 {
189 switch (s) {
190 case RESTARTER_STATE_UNINIT: return ('u');
191 case RESTARTER_STATE_DISABLED: return ('d');
192 case RESTARTER_STATE_OFFLINE: return ('0');
193 case RESTARTER_STATE_DEGRADED: return ('D');
194 case RESTARTER_STATE_ONLINE: return ('1');
195 case RESTARTER_STATE_MAINT: return ('m');
196 case RESTARTER_STATE_NONE: return ('n');
197 default: return ('?');
198 }
199 }
200
201 /*ARGSUSED*/
202 static int
pr_instance(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)203 pr_instance(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
204 {
205 restarter_instance_list_t ril;
206 restarter_inst_t ri;
207 char *iname;
208 char statechr = '-';
209 char typechr;
210
211 if ((flags & DCMD_ADDRSPEC) == 0) {
212 if (mdb_readvar(&ril, "instance_list") == -1) {
213 mdb_warn("failed to read 'instance_list' value\n");
214 return (DCMD_ERR);
215 }
216
217 if (mdb_pwalk_dcmd("uu_list_node", "instance", 0, NULL,
218 (uintptr_t)ril.ril_instance_list) == -1) {
219 mdb_warn("can't walk instances\n");
220 return (DCMD_ERR);
221 }
222
223 return (DCMD_OK);
224 }
225
226 if (mdb_vread(&ri, sizeof (restarter_inst_t), addr) == -1) {
227 mdb_warn("couldn't read instance at %a\n");
228 return (DCMD_ERR);
229 }
230
231 if (DCMD_HDRSPEC(flags))
232 mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
233 "FMRI");
234
235 iname = mdb_alloc(1024, UM_SLEEP | UM_GC);
236
237 if (mdb_readstr(iname, 1024, (uintptr_t)ri.ri_i.i_fmri) == -1) {
238 mdb_warn("couldn't read instance name\n");
239 strcpy(iname, "-");
240 }
241
242 statechr = xstate2chr(ri.ri_i.i_state);
243 typechr = (ri.ri_i.i_enabled) ? 'I' : 'i';
244
245 mdb_printf("%-10a %3x %c %c %s\n", addr, ri.ri_id, typechr, statechr,
246 iname);
247
248 return (DCMD_OK);
249 }
250
251 /*ARGSUSED*/
252 static int
pr_vertex(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)253 pr_vertex(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
254 {
255 uu_list_t *dgraphp;
256 graph_vertex_t gv;
257 char *vname;
258 int id;
259 char typechr;
260 char statechr = '-';
261
262 if ((flags & DCMD_ADDRSPEC) == 0) {
263 if (mdb_readvar(&dgraphp, "dgraph") == -1) {
264 mdb_warn("failed to read 'dgraph' value\n");
265 return (DCMD_ERR);
266 }
267
268 if (mdb_pwalk_dcmd("uu_list_node", "vertex", 0, NULL,
269 (uintptr_t)dgraphp) == -1) {
270 mdb_warn("can't walk vertices");
271 return (DCMD_ERR);
272 }
273
274 return (DCMD_OK);
275 }
276
277 if (mdb_vread(&gv, sizeof (graph_vertex_t), addr) == -1) {
278 mdb_warn("couldn't read vertex at %a\n");
279 return (DCMD_ERR);
280 }
281
282 if (DCMD_HDRSPEC(flags))
283 mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
284 "FMRI");
285
286 vname = mdb_alloc(1024, UM_SLEEP | UM_GC);
287
288 if (mdb_readstr(vname, 1024, (uintptr_t)gv.gv_name) == -1) {
289 mdb_warn("couldn't read vertex name\n");
290 strcpy(vname, "-");
291 }
292
293 id = gv.gv_id;
294
295 switch (gv.gv_type) {
296 case GVT_FILE:
297 typechr = 'f';
298 break;
299 case GVT_GROUP:
300 switch (gv.gv_depgroup) {
301 case DEPGRP_REQUIRE_ANY:
302 typechr = 'r';
303 break;
304 case DEPGRP_REQUIRE_ALL:
305 typechr = 'R';
306 break;
307 case DEPGRP_EXCLUDE_ALL:
308 typechr = 'X';
309 break;
310 case DEPGRP_OPTIONAL_ALL:
311 typechr = 'o';
312 break;
313 default:
314 typechr = '?';
315 break;
316 }
317 break;
318 case GVT_INST:
319 typechr = (gv.gv_flags & GV_ENABLED) ? 'I' : 'i';
320 statechr = xstate2chr(gv.gv_state);
321 break;
322 case GVT_SVC:
323 typechr = 's';
324 break;
325 default:
326 typechr = '?';
327 break;
328 }
329
330 mdb_printf("%-10a %3x %c %c %s\n", addr, id, typechr, statechr, vname);
331
332 return (DCMD_OK);
333 }
334
335 /* ARGSUSED */
336 static int
logbuf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)337 logbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
338 {
339 GElf_Sym sym;
340 char *buf;
341 char *cp;
342
343 if (mdb_lookup_by_name("logbuf", &sym) == -1) {
344 mdb_warn("The 'logbuf' symbol is missing.\n");
345 return (DCMD_ERR);
346 }
347
348 buf = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
349
350 if (mdb_vread(buf, sym.st_size, sym.st_value) == -1) {
351 mdb_warn("failed to read 'logbuf'\n");
352 return (DCMD_ERR);
353 }
354
355 cp = strchr(buf, '\0');
356
357 if (cp == buf)
358 /* Empty */
359 return (DCMD_OK);
360
361 if (cp >= buf + sym.st_size ||
362 strchr(cp + 1, '\0') >= buf + sym.st_size) {
363 mdb_warn("'logbuf' is corrupt\n");
364 return (DCMD_ERR);
365 }
366
367 mdb_printf("%s", cp + 1);
368 mdb_printf("%s", buf);
369
370 return (DCMD_OK);
371 }
372
373 static const mdb_dcmd_t dcmds[] = {
374 { "instance", NULL, "display svc.startd restarter instance",
375 pr_instance },
376 { "startd_log", NULL, "display svc.startd debug message buffer",
377 logbuf },
378 { "startd_status", NULL, "svc.startd status summary", startd_status },
379 { "vertex", NULL, "display svc.startd dependency graph vertex",
380 pr_vertex },
381 { NULL }
382 };
383
384 static const mdb_walker_t walkers[] = {
385 { NULL }
386 };
387
388 static const mdb_modinfo_t modinfo = {
389 MDB_API_VERSION, dcmds, walkers
390 };
391
392 const mdb_modinfo_t *
_mdb_init(void)393 _mdb_init(void)
394 {
395 return (&modinfo);
396 }
397