xref: /illumos-gate/usr/src/uts/common/fs/ufs/lufs_debug.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
22 
23 /*
24  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #include <sys/systm.h>
29 #include <sys/types.h>
30 #include <sys/vnode.h>
31 #include <sys/buf.h>
32 #include <sys/ddi.h>
33 #include <sys/errno.h>
34 #include <sys/sysmacros.h>
35 #include <sys/debug.h>
36 #include <sys/kmem.h>
37 #include <sys/conf.h>
38 #include <sys/proc.h>
39 #include <sys/cmn_err.h>
40 #include <sys/fs/ufs_inode.h>
41 #include <sys/fs/ufs_filio.h>
42 #include <sys/fs/ufs_log.h>
43 
44 
45 #ifdef	DEBUG
46 
47 /*
48  * DEBUG ROUTINES
49  *	THESE ROUTINES ARE ONLY USED WHEN ASSERTS ARE ENABLED
50  */
51 
52 static	kmutex_t	toptracelock;
53 static	int		toptraceindex;
54 int			toptracemax	= 1024;	/* global so it can be set */
55 struct toptrace {
56 	enum delta_type	dtyp;
57 	kthread_t	*thread;
58 	dev_t		dev;
59 	long		arg2;
60 	long		arg3;
61 	long long	arg1;
62 } *toptrace;
63 
64 static void
65 top_trace(enum delta_type dtyp, dev_t dev, long long arg1, long arg2, long arg3)
66 {
67 	if (toptrace == NULL) {
68 		toptraceindex = 0;
69 		toptrace = kmem_zalloc((size_t)
70 		    (sizeof (struct toptrace) * toptracemax), KM_SLEEP);
71 	}
72 	mutex_enter(&toptracelock);
73 	toptrace[toptraceindex].dtyp = dtyp;
74 	toptrace[toptraceindex].thread = curthread;
75 	toptrace[toptraceindex].dev = dev;
76 	toptrace[toptraceindex].arg1 = arg1;
77 	toptrace[toptraceindex].arg2 = arg2;
78 	toptrace[toptraceindex].arg3 = arg3;
79 	if (++toptraceindex == toptracemax)
80 		toptraceindex = 0;
81 	else {
82 		toptrace[toptraceindex].dtyp = (enum delta_type)-1;
83 		toptrace[toptraceindex].thread = (kthread_t *)-1;
84 		toptrace[toptraceindex].dev = (dev_t)-1;
85 		toptrace[toptraceindex].arg1 = -1;
86 		toptrace[toptraceindex].arg2 = -1;
87 	}
88 
89 	mutex_exit(&toptracelock);
90 }
91 
92 /*
93  * add a range into the metadata map
94  */
95 void
96 top_mataadd(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb)
97 {
98 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
99 
100 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
101 	deltamap_add(ul->un_matamap, mof, nb, 0, 0, 0, NULL);
102 }
103 
104 /*
105  * delete a range from the metadata map
106  */
107 void
108 top_matadel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb)
109 {
110 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
111 
112 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
113 	ASSERT(!matamap_overlap(ul->un_deltamap, mof, nb));
114 	deltamap_del(ul->un_matamap, mof, nb);
115 }
116 
117 /*
118  * clear the entries from the metadata map
119  */
120 void
121 top_mataclr(ufsvfs_t *ufsvfsp)
122 {
123 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
124 
125 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
126 	map_free_entries(ul->un_matamap);
127 	map_free_entries(ul->un_deltamap);
128 }
129 
130 int
131 top_begin_debug(ml_unit_t *ul, top_t topid, ulong_t size)
132 {
133 	threadtrans_t *tp;
134 
135 	if (ul->un_debug & MT_TRACE)
136 		top_trace(DT_BOT, ul->un_dev,
137 		    (long long)topid, (long)size, (long)0);
138 
139 	ASSERT(curthread->t_flag & T_DONTBLOCK);
140 
141 	tp = tsd_get(topkey);
142 	if (tp == NULL) {
143 		tp = kmem_zalloc(sizeof (threadtrans_t), KM_SLEEP);
144 		(void) tsd_set(topkey, tp);
145 	}
146 	tp->topid  = topid;
147 	tp->esize  = size;
148 	tp->rsize  = 0;
149 	tp->dev    = ul->un_dev;
150 	return (1);
151 }
152 
153 int
154 top_end_debug(ml_unit_t *ul, mt_map_t *mtm, top_t topid, ulong_t size)
155 {
156 	threadtrans_t *tp;
157 
158 	ASSERT(curthread->t_flag & T_DONTBLOCK);
159 
160 	ASSERT((tp = (threadtrans_t *)tsd_get(topkey)) != NULL);
161 
162 	ASSERT((tp->dev == ul->un_dev) && (tp->topid == topid) &&
163 	    (tp->esize == size));
164 
165 	ASSERT(((ul->un_debug & MT_SIZE) == 0) || (tp->rsize <= tp->esize));
166 
167 	mtm->mtm_tops->mtm_top_num[topid]++;
168 	mtm->mtm_tops->mtm_top_size_etot[topid] += tp->esize;
169 	mtm->mtm_tops->mtm_top_size_rtot[topid] += tp->rsize;
170 
171 	if (tp->rsize > mtm->mtm_tops->mtm_top_size_max[topid])
172 		mtm->mtm_tops->mtm_top_size_max[topid] = tp->rsize;
173 	if (mtm->mtm_tops->mtm_top_size_min[topid] == 0)
174 			mtm->mtm_tops->mtm_top_size_min[topid] =
175 			    tp->rsize;
176 	else
177 		if (tp->rsize < mtm->mtm_tops->mtm_top_size_min[topid])
178 			mtm->mtm_tops->mtm_top_size_min[topid] =
179 			    tp->rsize;
180 
181 	if (ul->un_debug & MT_TRACE)
182 		top_trace(DT_EOT, ul->un_dev, (long long)topid,
183 		    (long)tp->rsize, (long)0);
184 
185 	return (1);
186 }
187 
188 int
189 top_delta_debug(
190 	ml_unit_t *ul,
191 	offset_t mof,
192 	off_t nb,
193 	delta_t dtyp)
194 {
195 	struct threadtrans	*tp;
196 
197 	ASSERT(curthread->t_flag & T_DONTBLOCK);
198 
199 	/*
200 	 * check for delta contained fully within matamap
201 	 */
202 	ASSERT((ul->un_matamap == NULL) ||
203 	    matamap_within(ul->un_matamap, mof, nb));
204 
205 	/*
206 	 * maintain transaction info
207 	 */
208 	if (ul->un_debug & MT_TRANSACT)
209 		ul->un_logmap->mtm_tops->mtm_delta_num[dtyp]++;
210 
211 	/*
212 	 * check transaction stuff
213 	 */
214 	if (ul->un_debug & MT_TRANSACT) {
215 		tp = (struct threadtrans *)tsd_get(topkey);
216 		ASSERT(tp);
217 		switch (dtyp) {
218 		case DT_CANCEL:
219 		case DT_ABZERO:
220 			if (!matamap_within(ul->un_deltamap, mof, nb))
221 				tp->rsize += sizeof (struct delta);
222 			break;
223 		default:
224 			if (!matamap_within(ul->un_deltamap, mof, nb))
225 				tp->rsize += nb + sizeof (struct delta);
226 			break;
227 		}
228 	} else
229 		return (1);
230 
231 	if (ul->un_debug & MT_TRACE)
232 		top_trace(dtyp, ul->un_dev, mof, (long)nb, (long)0);
233 
234 	return (1);
235 }
236 
237 int
238 top_roll_debug(ml_unit_t *ul)
239 {
240 	logmap_roll_dev(ul);
241 	return (1);
242 }
243 
244 int
245 top_init_debug(void)
246 {
247 	mutex_init(&toptracelock, NULL, MUTEX_DEFAULT, NULL);
248 	return (1);
249 }
250 
251 struct topstats_link {
252 	struct topstats_link	*ts_next;
253 	dev_t			ts_dev;
254 	struct topstats		ts_stats;
255 };
256 struct topstats_link *topstats_anchor = NULL;
257 
258 /*
259  * DEBUG ROUTINES
260  *	from debug portion of *_map.c
261  */
262 /*
263  * scan test support
264  */
265 int
266 logmap_logscan_debug(mt_map_t *mtm, mapentry_t *age)
267 {
268 	mapentry_t	*me;
269 	ml_unit_t	*ul;
270 	off_t		head, trimroll, lof;
271 
272 	/*
273 	 * remember location of youngest rolled delta
274 	 */
275 	mutex_enter(&mtm->mtm_mutex);
276 	ul = mtm->mtm_ul;
277 	head = ul->un_head_lof;
278 	trimroll = mtm->mtm_trimrlof;
279 	for (me = age; me; me = me->me_agenext) {
280 		lof = me->me_lof;
281 		if (trimroll == 0)
282 			trimroll = lof;
283 		if (lof >= head) {
284 			if (trimroll >= head && trimroll <= lof)
285 				trimroll = lof;
286 		} else {
287 			if (trimroll <= lof || trimroll >= head)
288 				trimroll = lof;
289 		}
290 	}
291 	mtm->mtm_trimrlof = trimroll;
292 	mutex_exit(&mtm->mtm_mutex);
293 	return (1);
294 }
295 
296 /*
297  * scan test support
298  */
299 int
300 logmap_logscan_commit_debug(off_t lof, mt_map_t *mtm)
301 {
302 	off_t	oldtrimc, newtrimc, trimroll;
303 
304 	trimroll = mtm->mtm_trimrlof;
305 	oldtrimc = mtm->mtm_trimclof;
306 	newtrimc = mtm->mtm_trimclof = dbtob(btod(lof));
307 
308 	/*
309 	 * can't trim prior to transaction w/rolled delta
310 	 */
311 	if (trimroll)
312 		if (newtrimc >= oldtrimc) {
313 			if (trimroll <= newtrimc && trimroll >= oldtrimc)
314 				mtm->mtm_trimalof = newtrimc;
315 		} else {
316 			if (trimroll >= oldtrimc || trimroll <= newtrimc)
317 				mtm->mtm_trimalof = newtrimc;
318 		}
319 	return (1);
320 }
321 
322 int
323 logmap_logscan_add_debug(struct delta *dp, mt_map_t *mtm)
324 {
325 	if ((dp->d_typ == DT_AB) || (dp->d_typ == DT_INODE))
326 		mtm->mtm_trimalof = mtm->mtm_trimclof;
327 	return (1);
328 }
329 
330 /*
331  * log-read after log-write
332  */
333 int
334 map_check_ldl_write(ml_unit_t *ul, caddr_t va, offset_t vamof, mapentry_t *me)
335 {
336 	caddr_t		bufp;
337 
338 	ASSERT(me->me_nb);
339 	ASSERT((me->me_flags & ME_AGE) == 0);
340 
341 	/* Alloc a buf */
342 	bufp = kmem_alloc(me->me_nb, KM_SLEEP);
343 
344 	/* Do the read */
345 	me->me_agenext = NULL;
346 	if (ldl_read(ul, bufp, me->me_mof, me->me_nb, me) == 0) {
347 		ASSERT(bcmp(bufp, va + (me->me_mof - vamof), me->me_nb) == 0);
348 	}
349 
350 	kmem_free(bufp, me->me_nb);
351 	return (1);
352 }
353 
354 /*
355  * Cleanup a map struct
356  */
357 int
358 map_put_debug(mt_map_t *mtm)
359 {
360 	struct topstats_link	*tsl, **ptsl;
361 
362 	if (mtm->mtm_tops == NULL)
363 		return (1);
364 
365 	/* Don't free this, cause the next snarf will want it */
366 	if ((lufs_debug & MT_TRANSACT) != 0)
367 		return (1);
368 
369 	ptsl = &topstats_anchor;
370 	tsl = topstats_anchor;
371 	while (tsl) {
372 		if (mtm->mtm_tops == &tsl->ts_stats) {
373 			mtm->mtm_tops = NULL;
374 			*ptsl = tsl->ts_next;
375 			kmem_free(tsl, sizeof (*tsl));
376 			return (1);
377 		}
378 		ptsl = &tsl->ts_next;
379 		tsl = tsl->ts_next;
380 	}
381 
382 	return (1);
383 }
384 
385 int
386 map_get_debug(ml_unit_t *ul, mt_map_t *mtm)
387 {
388 	struct topstats_link	*tsl;
389 
390 	if ((ul->un_debug & MT_TRANSACT) == 0)
391 		return (1);
392 
393 	if (mtm->mtm_type != logmaptype)
394 		return (1);
395 
396 	tsl = topstats_anchor;
397 	while (tsl) {
398 		if (tsl->ts_dev == ul->un_dev) {
399 			mtm->mtm_tops = &(tsl->ts_stats);
400 			return (1);
401 		}
402 		tsl = tsl->ts_next;
403 	}
404 
405 	tsl = kmem_zalloc(sizeof (*tsl), KM_SLEEP);
406 	tsl->ts_dev = ul->un_dev;
407 	tsl->ts_next = topstats_anchor;
408 	topstats_anchor = tsl;
409 	mtm->mtm_tops = &tsl->ts_stats;
410 	return (1);
411 }
412 
413 /*
414  * check a map's list
415  */
416 int
417 map_check_linkage(mt_map_t *mtm)
418 {
419 	int		i;
420 	int		hashed;
421 	int		nexted;
422 	int		preved;
423 	int		ncancel;
424 	mapentry_t	*me;
425 	off_t		olof;
426 	off_t		firstlof;
427 	int		wrapped;
428 
429 	mutex_enter(&mtm->mtm_mutex);
430 
431 	ASSERT(mtm->mtm_nme >= 0);
432 
433 	/*
434 	 * verify the entries on the hash
435 	 */
436 	hashed = 0;
437 	for (i = 0; i < mtm->mtm_nhash; ++i) {
438 		for (me = *(mtm->mtm_hash+i); me; me = me->me_hash) {
439 			++hashed;
440 			ASSERT(me->me_flags & ME_HASH);
441 			ASSERT((me->me_flags & ME_LIST) == 0);
442 		}
443 	}
444 	ASSERT(hashed >= mtm->mtm_nme);
445 	/*
446 	 * verify the doubly linked list of all entries
447 	 */
448 	nexted = 0;
449 	for (me = mtm->mtm_next; me != (mapentry_t *)mtm; me = me->me_next)
450 		nexted++;
451 	preved = 0;
452 	for (me = mtm->mtm_prev; me != (mapentry_t *)mtm; me = me->me_prev)
453 		preved++;
454 	ASSERT(nexted == preved);
455 	ASSERT(nexted == hashed);
456 
457 	/*
458 	 * verify the cancel list
459 	 */
460 	ncancel = 0;
461 	for (me = mtm->mtm_cancel; me; me = me->me_cancel) {
462 		++ncancel;
463 		ASSERT(me->me_flags & ME_CANCEL);
464 	}
465 	/*
466 	 * verify the logmap's log offsets
467 	 */
468 	if (mtm->mtm_type == logmaptype) {
469 		olof = mtm->mtm_next->me_lof;
470 		firstlof = olof;
471 		wrapped = 0;
472 		/*
473 		 * Make sure to skip any mapentries whose me_lof = 0
474 		 * and me_type == DT_CANCEL, these are mapentries
475 		 * in place just to mark user block deletions as not
476 		 * available for allocate within the same moby transaction
477 		 * in case we crash before it is comitted.  Skip these
478 		 * entries in the checks below as they are not applicable.
479 		 */
480 		for (me = mtm->mtm_next->me_next;
481 		    me != (mapentry_t *)mtm;
482 		    me = me->me_next) {
483 
484 			if (me->me_lof == 0 && me->me_dt == DT_CANCEL)
485 				continue;
486 			if (firstlof == 0) {
487 				olof = me->me_lof;
488 				firstlof = olof;
489 				if (me->me_next != (mapentry_t *)mtm)
490 					me = me->me_next;
491 				continue;
492 			}
493 			ASSERT(me->me_lof != olof);
494 
495 			if (wrapped) {
496 				ASSERT(me->me_lof > olof);
497 				ASSERT(me->me_lof < firstlof);
498 				olof = me->me_lof;
499 				continue;
500 			}
501 			if (me->me_lof < olof) {
502 				ASSERT(me->me_lof < firstlof);
503 				wrapped = 1;
504 				olof = me->me_lof;
505 				continue;
506 			}
507 			ASSERT(me->me_lof > firstlof);
508 			ASSERT(me->me_lof < mtm->mtm_ul->un_eol_lof);
509 			olof = me->me_lof;
510 		}
511 	}
512 
513 	mutex_exit(&mtm->mtm_mutex);
514 	return (1);
515 }
516 
517 /*
518  * check for overlap
519  */
520 int
521 matamap_overlap(mt_map_t *mtm, offset_t mof, off_t nb)
522 {
523 	off_t		hnb;
524 	mapentry_t	*me;
525 	mapentry_t	**mep;
526 
527 	for (hnb = 0; nb; nb -= hnb, mof += hnb) {
528 
529 		hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF);
530 		if (hnb > nb)
531 			hnb = nb;
532 		/*
533 		 * search for dup entry
534 		 */
535 		mep = MAP_HASH(mof, mtm);
536 		mutex_enter(&mtm->mtm_mutex);
537 		for (me = *mep; me; me = me->me_hash)
538 			if (DATAoverlapME(mof, hnb, me))
539 				break;
540 		mutex_exit(&mtm->mtm_mutex);
541 
542 		/*
543 		 * overlap detected
544 		 */
545 		if (me)
546 			return (1);
547 	}
548 	return (0);
549 }
550 /*
551  * check for within
552  */
553 int
554 matamap_within(mt_map_t *mtm, offset_t mof, off_t nb)
555 {
556 	off_t		hnb;
557 	mapentry_t	*me;
558 	mapentry_t	**mep;
559 	int		scans	= 0;
560 	int		withins	= 0;
561 
562 	for (hnb = 0; nb && scans == withins; nb -= hnb, mof += hnb) {
563 		scans++;
564 
565 		hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF);
566 		if (hnb > nb)
567 			hnb = nb;
568 		/*
569 		 * search for within entry
570 		 */
571 		mep = MAP_HASH(mof, mtm);
572 		mutex_enter(&mtm->mtm_mutex);
573 		for (me = *mep; me; me = me->me_hash)
574 			if (DATAwithinME(mof, hnb, me)) {
575 				withins++;
576 				break;
577 			}
578 		mutex_exit(&mtm->mtm_mutex);
579 	}
580 	return (scans == withins);
581 }
582 
583 int
584 ldl_sethead_debug(ml_unit_t *ul)
585 {
586 	mt_map_t	*mtm	= ul->un_logmap;
587 	off_t		trimr	= mtm->mtm_trimrlof;
588 	off_t		head	= ul->un_head_lof;
589 	off_t		tail	= ul->un_tail_lof;
590 
591 	if (head <= tail) {
592 		if (trimr < head || trimr >= tail)
593 			mtm->mtm_trimrlof = 0;
594 	} else {
595 		if (trimr >= tail && trimr < head)
596 			mtm->mtm_trimrlof = 0;
597 	}
598 	return (1);
599 }
600 
601 int
602 lufs_initialize_debug(ml_odunit_t *ud)
603 {
604 	ud->od_debug = lufs_debug;
605 	return (1);
606 }
607 
608 #endif	/* DEBUG */
609 
610 /*
611  * lufs_debug controls the debug level for TSufs, and is only used
612  * for a debug kernel. It's referenced by ufs_ioctl() and so is
613  * not under #ifdef DEBUG compilation.
614  */
615 uint_t lufs_debug;
616