xref: /titanic_41/usr/src/cmd/mdb/common/modules/md/metastat.c (revision 989f28072d20c73ae0955d6a1e3e2fc74831cb39)
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
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
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
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
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
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
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
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
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
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
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