metastat.c revision 8452:89d32dfdae6e
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
29typedef struct	submirror_cb {
30	minor_t		un_self_id;
31	int		un_nsm;
32	ushort_t	mm_un_nsm;
33}submirror_cb_t;
34
35void
36print_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
50void
51print_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 */
90int
91print_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 */
131static void
132print_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
182void
183print_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
272void
273print_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
337void
338print_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
384void
385print_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
409void
410print_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 */
445int
446metastat(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