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.
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.
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]
21 #pragma ident "%Z%%M% %I% %E% SMI"
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <sys/systm.h>
29 #include <sys/types.h>
30 #include <sys/vnode.h>
33 #include <sys/errno.h>
34 #include <sys/sysmacros.h>
35 #include <sys/debug.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>
49 * THESE ROUTINES ARE ONLY USED WHEN ASSERTS ARE ENABLED
52 static kmutex_t toptracelock
;
53 static int toptraceindex
;
54 int toptracemax
= 1024; /* global so it can be set */
65 top_trace(enum delta_type dtyp
, dev_t dev
, long long arg1
, long arg2
, long arg3
)
67 if (toptrace
== NULL
) {
69 toptrace
= kmem_zalloc((size_t)
70 (sizeof (struct toptrace
) * toptracemax
), KM_SLEEP
);
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
)
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;
89 mutex_exit(&toptracelock
);
93 * add a range into the metadata map
96 top_mataadd(ufsvfs_t
*ufsvfsp
, offset_t mof
, off_t nb
)
98 ml_unit_t
*ul
= ufsvfsp
->vfs_log
;
100 ASSERT(ufsvfsp
->vfs_dev
== ul
->un_dev
);
101 deltamap_add(ul
->un_matamap
, mof
, nb
, 0, 0, 0, NULL
);
105 * delete a range from the metadata map
108 top_matadel(ufsvfs_t
*ufsvfsp
, offset_t mof
, off_t nb
)
110 ml_unit_t
*ul
= ufsvfsp
->vfs_log
;
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
);
118 * clear the entries from the metadata map
121 top_mataclr(ufsvfs_t
*ufsvfsp
)
123 ml_unit_t
*ul
= ufsvfsp
->vfs_log
;
125 ASSERT(ufsvfsp
->vfs_dev
== ul
->un_dev
);
126 map_free_entries(ul
->un_matamap
);
127 map_free_entries(ul
->un_deltamap
);
131 top_begin_debug(ml_unit_t
*ul
, top_t topid
, ulong_t size
)
135 if (ul
->un_debug
& MT_TRACE
)
136 top_trace(DT_BOT
, ul
->un_dev
,
137 (long long)topid
, (long)size
, (long)0);
139 ASSERT(curthread
->t_flag
& T_DONTBLOCK
);
141 tp
= tsd_get(topkey
);
143 tp
= kmem_zalloc(sizeof (threadtrans_t
), KM_SLEEP
);
144 (void) tsd_set(topkey
, tp
);
149 tp
->dev
= ul
->un_dev
;
154 top_end_debug(ml_unit_t
*ul
, mt_map_t
*mtm
, top_t topid
, ulong_t size
)
158 ASSERT(curthread
->t_flag
& T_DONTBLOCK
);
160 ASSERT((tp
= (threadtrans_t
*)tsd_get(topkey
)) != NULL
);
162 ASSERT((tp
->dev
== ul
->un_dev
) && (tp
->topid
== topid
) &&
163 (tp
->esize
== size
));
165 ASSERT(((ul
->un_debug
& MT_SIZE
) == 0) || (tp
->rsize
<= tp
->esize
));
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
;
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
] =
177 if (tp
->rsize
< mtm
->mtm_tops
->mtm_top_size_min
[topid
])
178 mtm
->mtm_tops
->mtm_top_size_min
[topid
] =
181 if (ul
->un_debug
& MT_TRACE
)
182 top_trace(DT_EOT
, ul
->un_dev
, (long long)topid
,
183 (long)tp
->rsize
, (long)0);
195 struct threadtrans
*tp
;
197 ASSERT(curthread
->t_flag
& T_DONTBLOCK
);
200 * check for delta contained fully within matamap
202 ASSERT((ul
->un_matamap
== NULL
) ||
203 matamap_within(ul
->un_matamap
, mof
, nb
));
206 * maintain transaction info
208 if (ul
->un_debug
& MT_TRANSACT
)
209 ul
->un_logmap
->mtm_tops
->mtm_delta_num
[dtyp
]++;
212 * check transaction stuff
214 if (ul
->un_debug
& MT_TRANSACT
) {
215 tp
= (struct threadtrans
*)tsd_get(topkey
);
220 if (!matamap_within(ul
->un_deltamap
, mof
, nb
))
221 tp
->rsize
+= sizeof (struct delta
);
224 if (!matamap_within(ul
->un_deltamap
, mof
, nb
))
225 tp
->rsize
+= nb
+ sizeof (struct delta
);
231 if (ul
->un_debug
& MT_TRACE
)
232 top_trace(dtyp
, ul
->un_dev
, mof
, (long)nb
, (long)0);
238 top_roll_debug(ml_unit_t
*ul
)
247 mutex_init(&toptracelock
, NULL
, MUTEX_DEFAULT
, NULL
);
251 struct topstats_link
{
252 struct topstats_link
*ts_next
;
254 struct topstats ts_stats
;
256 struct topstats_link
*topstats_anchor
= NULL
;
260 * from debug portion of *_map.c
266 logmap_logscan_debug(mt_map_t
*mtm
, mapentry_t
*age
)
270 off_t head
, trimroll
, lof
;
273 * remember location of youngest rolled delta
275 mutex_enter(&mtm
->mtm_mutex
);
277 head
= ul
->un_head_lof
;
278 trimroll
= mtm
->mtm_trimrlof
;
279 for (me
= age
; me
; me
= me
->me_agenext
) {
284 if (trimroll
>= head
&& trimroll
<= lof
)
287 if (trimroll
<= lof
|| trimroll
>= head
)
291 mtm
->mtm_trimrlof
= trimroll
;
292 mutex_exit(&mtm
->mtm_mutex
);
300 logmap_logscan_commit_debug(off_t lof
, mt_map_t
*mtm
)
302 off_t oldtrimc
, newtrimc
, trimroll
;
304 trimroll
= mtm
->mtm_trimrlof
;
305 oldtrimc
= mtm
->mtm_trimclof
;
306 newtrimc
= mtm
->mtm_trimclof
= dbtob(btod(lof
));
309 * can't trim prior to transaction w/rolled delta
312 if (newtrimc
>= oldtrimc
) {
313 if (trimroll
<= newtrimc
&& trimroll
>= oldtrimc
)
314 mtm
->mtm_trimalof
= newtrimc
;
316 if (trimroll
>= oldtrimc
|| trimroll
<= newtrimc
)
317 mtm
->mtm_trimalof
= newtrimc
;
323 logmap_logscan_add_debug(struct delta
*dp
, mt_map_t
*mtm
)
325 if ((dp
->d_typ
== DT_AB
) || (dp
->d_typ
== DT_INODE
))
326 mtm
->mtm_trimalof
= mtm
->mtm_trimclof
;
331 * log-read after log-write
334 map_check_ldl_write(ml_unit_t
*ul
, caddr_t va
, offset_t vamof
, mapentry_t
*me
)
339 ASSERT((me
->me_flags
& ME_AGE
) == 0);
342 bufp
= kmem_alloc(me
->me_nb
, KM_SLEEP
);
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);
350 kmem_free(bufp
, me
->me_nb
);
355 * Cleanup a map struct
358 map_put_debug(mt_map_t
*mtm
)
360 struct topstats_link
*tsl
, **ptsl
;
362 if (mtm
->mtm_tops
== NULL
)
365 /* Don't free this, cause the next snarf will want it */
366 if ((lufs_debug
& MT_TRANSACT
) != 0)
369 ptsl
= &topstats_anchor
;
370 tsl
= topstats_anchor
;
372 if (mtm
->mtm_tops
== &tsl
->ts_stats
) {
373 mtm
->mtm_tops
= NULL
;
374 *ptsl
= tsl
->ts_next
;
375 kmem_free(tsl
, sizeof (*tsl
));
378 ptsl
= &tsl
->ts_next
;
386 map_get_debug(ml_unit_t
*ul
, mt_map_t
*mtm
)
388 struct topstats_link
*tsl
;
390 if ((ul
->un_debug
& MT_TRANSACT
) == 0)
393 if (mtm
->mtm_type
!= logmaptype
)
396 tsl
= topstats_anchor
;
398 if (tsl
->ts_dev
== ul
->un_dev
) {
399 mtm
->mtm_tops
= &(tsl
->ts_stats
);
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
;
417 map_check_linkage(mt_map_t
*mtm
)
429 mutex_enter(&mtm
->mtm_mutex
);
431 ASSERT(mtm
->mtm_nme
>= 0);
434 * verify the entries on the hash
437 for (i
= 0; i
< mtm
->mtm_nhash
; ++i
) {
438 for (me
= *(mtm
->mtm_hash
+i
); me
; me
= me
->me_hash
) {
440 ASSERT(me
->me_flags
& ME_HASH
);
441 ASSERT((me
->me_flags
& ME_LIST
) == 0);
444 ASSERT(hashed
>= mtm
->mtm_nme
);
446 * verify the doubly linked list of all entries
449 for (me
= mtm
->mtm_next
; me
!= (mapentry_t
*)mtm
; me
= me
->me_next
)
452 for (me
= mtm
->mtm_prev
; me
!= (mapentry_t
*)mtm
; me
= me
->me_prev
)
454 ASSERT(nexted
== preved
);
455 ASSERT(nexted
== hashed
);
458 * verify the cancel list
461 for (me
= mtm
->mtm_cancel
; me
; me
= me
->me_cancel
) {
463 ASSERT(me
->me_flags
& ME_CANCEL
);
466 * verify the logmap's log offsets
468 if (mtm
->mtm_type
== logmaptype
) {
469 olof
= mtm
->mtm_next
->me_lof
;
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.
480 for (me
= mtm
->mtm_next
->me_next
;
481 me
!= (mapentry_t
*)mtm
;
484 if (me
->me_lof
== 0 && me
->me_dt
== DT_CANCEL
)
489 if (me
->me_next
!= (mapentry_t
*)mtm
)
493 ASSERT(me
->me_lof
!= olof
);
496 ASSERT(me
->me_lof
> olof
);
497 ASSERT(me
->me_lof
< firstlof
);
501 if (me
->me_lof
< olof
) {
502 ASSERT(me
->me_lof
< firstlof
);
507 ASSERT(me
->me_lof
> firstlof
);
508 ASSERT(me
->me_lof
< mtm
->mtm_ul
->un_eol_lof
);
513 mutex_exit(&mtm
->mtm_mutex
);
521 matamap_overlap(mt_map_t
*mtm
, offset_t mof
, off_t nb
)
527 for (hnb
= 0; nb
; nb
-= hnb
, mof
+= hnb
) {
529 hnb
= MAPBLOCKSIZE
- (mof
& MAPBLOCKOFF
);
533 * search for dup entry
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
))
540 mutex_exit(&mtm
->mtm_mutex
);
554 matamap_within(mt_map_t
*mtm
, offset_t mof
, off_t nb
)
562 for (hnb
= 0; nb
&& scans
== withins
; nb
-= hnb
, mof
+= hnb
) {
565 hnb
= MAPBLOCKSIZE
- (mof
& MAPBLOCKOFF
);
569 * search for within entry
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
)) {
578 mutex_exit(&mtm
->mtm_mutex
);
580 return (scans
== withins
);
584 ldl_sethead_debug(ml_unit_t
*ul
)
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
;
592 if (trimr
< head
|| trimr
>= tail
)
593 mtm
->mtm_trimrlof
= 0;
595 if (trimr
>= tail
&& trimr
< head
)
596 mtm
->mtm_trimrlof
= 0;
602 lufs_initialize_debug(ml_odunit_t
*ud
)
604 ud
->od_debug
= lufs_debug
;
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.