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