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 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "mdinclude.h"
28
29 typedef struct submirror_cb {
30 minor_t un_self_id;
31 int un_nsm;
32 ushort_t mm_un_nsm;
33 }submirror_cb_t;
34
35 void
print_setname(int setno)36 print_setname(int setno)
37 {
38 char setname[1024];
39
40 if (setno != 0) {
41 if (mdb_readstr(setname, 1024,
42 (uintptr_t)set_dbs[setno].s_setname) == -1) {
43 mdb_warn("failed to read setname at 0x%p\n",
44 set_dbs[setno].s_setname);
45 }
46 mdb_printf("%s/", setname);
47 }
48 }
49
50 void
print_stripe(void * un_addr,void * mdcptr,uint_t verbose)51 print_stripe(void *un_addr, void *mdcptr, uint_t verbose)
52 {
53 ms_unit_t ms;
54 int setno;
55 minor_t un_self_id;
56 md_parent_t un_parent;
57 diskaddr_t un_total_blocks;
58
59 /* read in the device */
60 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
61 un_parent = ((mdc_unit_t *)mdcptr)->un_parent;
62 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
63 if (mdb_vread(&ms, sizeof (ms_unit_t),
64 (uintptr_t)un_addr) == -1) {
65 mdb_warn("failed to read ms_unit_t at %p\n", un_addr);
66 return;
67 }
68
69 setno = MD_MIN2SET(un_self_id);
70 print_setname(setno);
71
72 mdb_printf("d%u: ", MD_MIN2UNIT(un_self_id));
73 if (un_parent == ((unit_t)-1)) {
74 mdb_printf("Concat/Stripe");
75 } else {
76 mdb_printf("Subdevice of d%u", MD_MIN2UNIT(un_parent));
77 }
78 if (verbose) {
79 mdb_printf("\t< %p::print ms_unit_t >\n", un_addr);
80 } else {
81 mdb_printf("\t< %p>\n", un_addr);
82 }
83 mdb_inc_indent(2);
84 mdb_printf("Size: %llu blocks\n", un_total_blocks);
85 mdb_printf("Rows: %u\n", ms.un_nrows);
86 mdb_dec_indent(2);
87 }
88
89 /* ARGSUSED */
90 int
print_submirror(uintptr_t addr,void * arg,submirror_cb_t * data)91 print_submirror(uintptr_t addr, void *arg, submirror_cb_t *data)
92 {
93 uintptr_t un_addr;
94 mdc_unit_t mdc_sm;
95
96 if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) {
97 mdb_warn("failed to read submirror at %p\n", addr);
98 return (WALK_ERR);
99 }
100 if (un_addr != NULL) {
101 if (mdb_vread(&mdc_sm, sizeof (mdc_unit_t), un_addr) == -1) {
102 mdb_warn("failed to read mdc_unit_t at %p", un_addr);
103 return (WALK_ERR);
104 }
105 if (mdc_sm.un_parent == data->un_self_id) {
106 /* this is one of the sub mirrors */
107 mdb_printf("Submirror %u: d%u ",
108 data->un_nsm, MD_MIN2UNIT(mdc_sm.un_self_id));
109 mdb_printf("Size: %llu\n", mdc_sm.un_total_blocks);
110 data->un_nsm++;
111 if (data->un_nsm == data->mm_un_nsm)
112 return (WALK_DONE);
113 }
114 }
115 return (WALK_NEXT);
116 }
117
118 /*
119 * Construct an RLE count for the number of 'cleared' bits in the given 'bm'
120 * Output the RLE count in form: [<set>.<cleared>.<set>.<cleared>...]
121 * RLE is Run Length Encoding, a method for compactly describing a bitmap
122 * as a series of numbers indicating the count of consecutive set or cleared
123 * bits.
124 *
125 * Input:
126 * <bm> bitmap to scan
127 * <size> length of bitmap (in bits)
128 * <comp_bm> RLE count array to be updated
129 * <opstr> Descriptive text for bitmap RLE count display
130 */
131 static void
print_comp_bm(unsigned char * bm,uint_t size,ushort_t * comp_bm,char * opstr)132 print_comp_bm(unsigned char *bm, uint_t size, ushort_t *comp_bm, char *opstr)
133 {
134 int cnt_clean, tot_dirty, cur_idx;
135 int i, cur_clean, cur_dirty, printit, max_set_cnt, max_reset_cnt;
136
137 cnt_clean = 1;
138 printit = 0;
139 cur_clean = 0;
140 cur_dirty = 0;
141 cur_idx = 0;
142 tot_dirty = 0;
143 max_set_cnt = max_reset_cnt = 0;
144 for (i = 0; i < size; i++) {
145 if (isset(bm, i)) {
146 /* If we're counting clean bits, flush the count out */
147 if (cnt_clean) {
148 cnt_clean = 0;
149 comp_bm[cur_idx] = cur_clean;
150 printit = 1;
151 if (cur_clean > max_reset_cnt) {
152 max_reset_cnt = cur_clean;
153 }
154 }
155 cur_clean = 0;
156 cur_dirty++;
157 tot_dirty++;
158 } else {
159 if (!cnt_clean) {
160 cnt_clean = 1;
161 comp_bm[cur_idx] = cur_dirty;
162 printit = 1;
163 if (cur_dirty > max_set_cnt) {
164 max_set_cnt = cur_dirty;
165 }
166 }
167 cur_dirty = 0;
168 cur_clean++;
169 }
170 if (printit) {
171 mdb_printf("%u.", comp_bm[cur_idx++]);
172 printit = 0;
173 }
174 }
175
176 mdb_printf("\nTotal %s bits = %lu\n", opstr, tot_dirty);
177 mdb_printf("Total %s transactions = %lu\n", opstr, cur_idx);
178 mdb_printf("Maximum %s set count = %lu, reset count = %lu\n", opstr,
179 max_set_cnt, max_reset_cnt);
180 }
181
182 void
print_mirror(void * un_addr,void * mdcptr,uint_t verbose)183 print_mirror(void *un_addr, void *mdcptr, uint_t verbose)
184 {
185 mm_unit_t mm, *mmp;
186 void **ptr;
187 int setno = 0;
188 minor_t un_self_id;
189 diskaddr_t un_total_blocks;
190 ushort_t mm_un_nsm;
191 submirror_cb_t data;
192 uint_t num_rr, rr_blksize;
193 ushort_t *comp_rr;
194 unsigned char *rr_dirty_bm, *rr_goingclean_bm;
195 uintptr_t un_dbm, un_gcbm;
196
197 /* read in the device */
198 if (mdb_vread(&mm, sizeof (mm_unit_t),
199 (uintptr_t)un_addr) == -1) {
200 mdb_warn("failed to read mm_unit_t at %p\n", un_addr);
201 return;
202 }
203
204 mmp = &mm;
205
206 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
207 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
208 mm_un_nsm = mm.un_nsm;
209 setno = MD_MIN2SET(un_self_id);
210 print_setname(setno);
211
212 mdb_printf("d%u: Mirror", MD_MIN2UNIT(un_self_id));
213 if (verbose) {
214 mdb_printf("\t< %p::print mm_unit_t >\n", un_addr);
215 } else {
216 mdb_printf("\t< %p >\n", un_addr);
217 }
218 mdb_inc_indent(2);
219 mdb_printf("Size: %llu blocks\n", un_total_blocks);
220
221 /*
222 * Dump out the current un_dirty_bm together with its size
223 * Also, attempt to Run Length encode the bitmap to see if this
224 * is a viable option
225 */
226 num_rr = mm.un_rrd_num;
227 rr_blksize = mm.un_rrd_blksize;
228
229 un_dbm = (uintptr_t)mmp->un_dirty_bm;
230 un_gcbm = (uintptr_t)mmp->un_goingclean_bm;
231
232 mdb_printf("RR size: %lu bits\n", num_rr);
233 mdb_printf("RR block size: %lu blocks\n", rr_blksize);
234
235 rr_dirty_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC);
236 rr_goingclean_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC);
237 comp_rr = (ushort_t *)mdb_alloc(num_rr * sizeof (ushort_t),
238 UM_SLEEP|UM_GC);
239
240 if (mdb_vread(rr_dirty_bm, num_rr, un_dbm) == -1) {
241 mdb_warn("failed to read un_dirty_bm at %p\n", un_dbm);
242 return;
243 }
244 if (mdb_vread(rr_goingclean_bm, num_rr, un_gcbm) == -1) {
245 mdb_warn("failed to read un_goingclean_bm at %p\n", un_gcbm);
246 return;
247 }
248
249 print_comp_bm(rr_dirty_bm, num_rr, comp_rr, "dirty");
250
251 print_comp_bm(rr_goingclean_bm, num_rr, comp_rr, "clean");
252
253 /*
254 * find the sub mirrors, search through each metadevice looking
255 * at the un_parent.
256 */
257 ptr = mdset[setno].s_un;
258
259 data.un_self_id = un_self_id;
260 data.un_nsm = 0;
261 data.mm_un_nsm = mm_un_nsm;
262
263 if (mdb_pwalk("md_units", (mdb_walk_cb_t)print_submirror, &data,
264 (uintptr_t)ptr) == -1) {
265 mdb_warn("unable to walk units\n");
266 return;
267 }
268
269 mdb_dec_indent(2);
270 }
271
272 void
print_raid(void * un_addr,void * mdcptr,uint_t verbose)273 print_raid(void *un_addr, void *mdcptr, uint_t verbose)
274 {
275 mr_unit_t mr;
276 minor_t un_self_id;
277 diskaddr_t un_total_blocks;
278 mdc_unit_t mdc_sc;
279 void **ptr;
280 void *addr;
281 int setno = 0;
282 int i;
283 minor_t sc_un_self_id;
284 md_parent_t sc_parent;
285 diskaddr_t sc_total_blocks;
286
287 /* read in the device */
288 if (mdb_vread(&mr, sizeof (mr_unit_t), (uintptr_t)un_addr) == -1) {
289 mdb_warn("failed to read mr_unit_t at %p\n", un_addr);
290 return;
291 }
292 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
293 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
294 setno = MD_MIN2SET(un_self_id);
295 print_setname(setno);
296
297 mdb_printf("d%u: Raid", MD_MIN2UNIT(un_self_id));
298 if (verbose) {
299 mdb_printf("\t< %p ::print mr_unit_t>\n", un_addr);
300 } else {
301 mdb_printf("\t< %p >\n", un_addr);
302 }
303 mdb_inc_indent(2);
304 mdb_printf("Size: %llu\n", un_total_blocks);
305
306 /*
307 * find the sub components if any, search through each metadevice
308 * looking at the un_parent.
309 */
310 ptr = mdset[setno].s_un;
311 for (i = 0; i < md_nunits; i++, ptr++) {
312 if (mdb_vread(&addr, sizeof (void *), (uintptr_t)ptr) == -1) {
313 mdb_warn("failed to read addr at %p\n", ptr);
314 continue;
315 }
316 if (addr != NULL) {
317 if (mdb_vread(&mdc_sc, sizeof (mdc_unit_t),
318 (uintptr_t)addr) == -1) {
319 mdb_warn("failed to read mdc_unit_t at %p",
320 un_addr);
321 continue;
322 }
323 sc_parent = mdc_sc.un_parent;
324 sc_un_self_id = mdc_sc.un_self_id;
325 sc_total_blocks = mdc_sc.un_total_blocks;
326 if (sc_parent == un_self_id) {
327 /* this is one of the sub components */
328 mdb_printf("Subdevice %u ",
329 MD_MIN2UNIT(sc_un_self_id));
330 mdb_printf("Size: %llu\n", sc_total_blocks);
331 }
332 }
333 }
334 mdb_dec_indent(2);
335 }
336
337 void
print_sp(void * un_addr,void * mdcptr,uint_t verbose)338 print_sp(void *un_addr, void *mdcptr, uint_t verbose)
339 {
340 mp_unit_t mp;
341 minor_t un_self_id;
342 diskaddr_t un_total_blocks;
343 int setno = 0;
344 uintptr_t extaddr;
345 int i;
346
347 /* read in the device */
348 if (mdb_vread(&mp, sizeof (mp_unit_t), (uintptr_t)un_addr) == -1) {
349 mdb_warn("failed to read mp_unit_t at %p\n", un_addr);
350 return;
351 }
352 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
353 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
354 setno = MD_MIN2SET(un_self_id);
355 print_setname(setno);
356
357 mdb_printf("d%u: Soft Partition", MD_MIN2UNIT(un_self_id));
358 if (verbose) {
359 mdb_printf("\t< %p ::print mp_unit_t >\n", un_addr);
360 } else {
361 mdb_printf("\t< %p >\n", un_addr);
362 }
363 mdb_inc_indent(2);
364 mdb_printf("Size: %llu\n", un_total_blocks);
365 mdb_inc_indent(2);
366 mdb_printf("Extent\tStart Block\tBlock count\n");
367 extaddr = (uintptr_t)un_addr + sizeof (mp_unit_t) - sizeof (mp_ext_t);
368 for (i = 0; i < mp.un_numexts; i++) {
369 mp_ext_t mpext;
370
371 if (mdb_vread(&mpext, sizeof (mp_ext_t), extaddr) == -1) {
372 mdb_warn("failed to read mp_ext_t at %p\n", extaddr);
373 return;
374 }
375 mdb_printf(" %d \t %llu\t %llu\n",
376 i, mpext.un_poff, mpext.un_len);
377 extaddr += sizeof (mp_ext_t);
378 }
379 mdb_dec_indent(2);
380 mdb_dec_indent(2);
381
382 }
383
384 void
print_trans(void * un_addr,void * mdcptr,uint_t verbose)385 print_trans(void *un_addr, void *mdcptr, uint_t verbose)
386 {
387 mt_unit_t mt;
388 minor_t un_self_id;
389 int setno = 0;
390
391 /* read in the device */
392 if (mdb_vread(&mt, sizeof (mt_unit_t), (uintptr_t)un_addr) == -1) {
393 mdb_warn("failed to read mt_unit_t at %p\n", un_addr);
394 return;
395 }
396 un_self_id = ((mdc_unit32_od_t *)mdcptr)->un_self_id;
397 setno = MD_MIN2SET(un_self_id);
398 print_setname(setno);
399
400 mdb_printf("d%u: Trans", MD_MIN2UNIT(un_self_id));
401 if (verbose) {
402 mdb_printf("\t< %p ::print mt_unit_t>\n", un_addr);
403 } else {
404 mdb_printf("\t< %p >\n", un_addr);
405 }
406
407 }
408
409 void
print_device(void * un_addr,void * mdcptr,uint_t verbose)410 print_device(void *un_addr, void *mdcptr, uint_t verbose)
411 {
412 u_longlong_t un_type;
413
414 un_type = ((mdc_unit_t *)mdcptr)->un_type;
415
416 switch (un_type) {
417 case MD_DEVICE: /* stripe/concat */
418 print_stripe(un_addr, mdcptr, verbose);
419 break;
420 case MD_METAMIRROR:
421 print_mirror(un_addr, mdcptr, verbose);
422 break;
423 case MD_METATRANS:
424 print_trans(un_addr, mdcptr, verbose);
425 break;
426 case MD_METARAID:
427 print_raid(un_addr, mdcptr, verbose);
428 break;
429 case MD_METASP:
430 print_sp(un_addr, mdcptr, verbose);
431 break;
432 case MD_UNDEFINED:
433 mdb_warn("undefined metadevice at %p\n", un_addr);
434 break;
435 default:
436 mdb_warn("invalid metadevice at %p\n", un_addr);
437 break;
438 }
439 }
440
441 /* ARGSUSED */
442 /*
443 * usage: ::metastat [-v]
444 */
445 int
metastat(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)446 metastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
447 {
448 mdc_unit_t mdc;
449 uintptr_t un_addr;
450 uint_t verbose = FALSE;
451
452 snarf_sets();
453
454 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
455 != argc) {
456 return (DCMD_USAGE);
457 }
458
459 if (!(flags & DCMD_ADDRSPEC)) {
460 if (mdb_walk_dcmd("md_units", "metastat", argc,
461 argv) == -1) {
462 mdb_warn("failed to walk units");
463 return (DCMD_ERR);
464 }
465 return (DCMD_OK);
466 }
467 if (!(flags & DCMD_LOOP)) {
468 /* user passed set addr */
469 if (mdb_pwalk_dcmd("md_units", "metastat", argc,
470 argv, addr) == -1) {
471 mdb_warn("failed to walk units");
472 return (DCMD_ERR);
473 }
474 return (DCMD_OK);
475 }
476
477 if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) {
478 mdb_warn("failed to read un_addr at %p", addr);
479 return (DCMD_ERR);
480 }
481
482 if (un_addr != NULL) {
483 if (mdb_vread(&mdc, sizeof (mdc_unit_t), un_addr) == -1) {
484 mdb_warn("failed to read mdc_unit_t at %p", un_addr);
485 return (DCMD_ERR);
486 }
487 print_device((void *)un_addr, (void *)&mdc, verbose);
488 mdb_dec_indent(2);
489 }
490 return (DCMD_OK);
491 }
492