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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2015 by Delphix. All rights reserved.
28 */
29
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/vnode.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/taskq.h>
40 #include <sys/cmn_err.h>
41 #include <sys/fs/ufs_inode.h>
42 #include <sys/fs/ufs_filio.h>
43 #include <sys/fs/ufs_log.h>
44 #include <sys/fs/ufs_bio.h>
45
46 /*
47 * FILE SYSTEM INTERFACE TO TRANSACTION OPERATIONS (TOP; like VOP)
48 */
49
50 uint_t topkey; /* tsd transaction key */
51
52 /*
53 * declare a delta
54 */
55 void
top_delta(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb,delta_t dtyp,int (* func)(),ulong_t arg)56 top_delta(
57 ufsvfs_t *ufsvfsp,
58 offset_t mof,
59 off_t nb,
60 delta_t dtyp,
61 int (*func)(),
62 ulong_t arg)
63 {
64 ml_unit_t *ul = ufsvfsp->vfs_log;
65 threadtrans_t *tp = tsd_get(topkey);
66
67 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
68 ASSERT(nb);
69 ASSERT(((ul->un_debug & (MT_TRANSACT|MT_MATAMAP)) == 0) ||
70 top_delta_debug(ul, mof, nb, dtyp));
71
72 deltamap_add(ul->un_deltamap, mof, nb, dtyp, func, arg, tp);
73
74 ul->un_logmap->mtm_ref = 1; /* for roll thread's heuristic */
75 if (tp) {
76 tp->any_deltas = 1;
77 }
78 }
79
80 /*
81 * cancel a delta
82 */
83 void
top_cancel(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb,int flags)84 top_cancel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb, int flags)
85 {
86 ml_unit_t *ul = ufsvfsp->vfs_log;
87 int metadata = flags & (I_DIR|I_IBLK|I_SHAD|I_QUOTA);
88
89 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
90 ASSERT(nb);
91 ASSERT(((ul->un_debug & (MT_TRANSACT|MT_MATAMAP)) == 0) ||
92 (!(flags & metadata) ||
93 top_delta_debug(ul, mof, nb, DT_CANCEL)));
94
95 if (metadata)
96 deltamap_del(ul->un_deltamap, mof, nb);
97
98 logmap_cancel(ul, mof, nb, metadata);
99
100 /*
101 * needed for the roll thread's heuristic
102 */
103 ul->un_logmap->mtm_ref = 1;
104 }
105
106 /*
107 * check if this delta has been canceled (metadata -> userdata)
108 */
109 int
top_iscancel(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb)110 top_iscancel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb)
111 {
112 ml_unit_t *ul = ufsvfsp->vfs_log;
113
114 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
115 ASSERT(nb);
116 if (logmap_iscancel(ul->un_logmap, mof, nb))
117 return (1);
118 if (ul->un_flags & LDL_ERROR)
119 return (1);
120 return (0);
121 }
122
123 /*
124 * put device into error state
125 */
126 void
top_seterror(ufsvfs_t * ufsvfsp)127 top_seterror(ufsvfs_t *ufsvfsp)
128 {
129 ml_unit_t *ul = ufsvfsp->vfs_log;
130
131 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
132 ldl_seterror(ul, "ufs is forcing a ufs log error");
133 }
134
135 /*
136 * issue a empty sync op to help empty the delta/log map or the log
137 */
138 static void
top_issue_sync(ufsvfs_t * ufsvfsp)139 top_issue_sync(ufsvfs_t *ufsvfsp)
140 {
141 int error = 0;
142
143 if ((curthread->t_flag & T_DONTBLOCK) == 0)
144 curthread->t_flag |= T_DONTBLOCK;
145 top_begin_sync(ufsvfsp, TOP_COMMIT_ASYNC, 0, &error);
146 if (!error) {
147 top_end_sync(ufsvfsp, &error, TOP_COMMIT_ASYNC, 0);
148 }
149 }
150
151 static void
top_issue_from_taskq(void * arg)152 top_issue_from_taskq(void *arg)
153 {
154 ufsvfs_t *ufsvfsp = arg;
155 ml_unit_t *ul = ufsvfsp->vfs_log;
156 mt_map_t *mtm = ul->un_logmap;
157
158 top_issue_sync(ufsvfsp);
159
160 /*
161 * We were called from the taskq_dispatch() in top_begin_async(), so
162 * decrement mtm_taskq_sync_count and wake up the thread waiting
163 * on the mtm_cv if the mtm_taskq_sync_count hits zero.
164 */
165 ASSERT(taskq_member(system_taskq, curthread));
166
167 mutex_enter(&mtm->mtm_lock);
168 mtm->mtm_taskq_sync_count--;
169 if (mtm->mtm_taskq_sync_count == 0) {
170 cv_signal(&mtm->mtm_cv);
171 }
172 mutex_exit(&mtm->mtm_lock);
173 }
174
175 /*
176 * MOBY TRANSACTION ROUTINES
177 * begin a moby transaction
178 * sync ops enter until first sync op finishes
179 * async ops enter until last sync op finishes
180 * end a moby transaction
181 * outstanding deltas are pushed thru log
182 * log buffer is committed (incore only)
183 * next trans is open to async ops
184 * log buffer is committed on the log
185 * next trans is open to sync ops
186 */
187
188 /*ARGSUSED*/
189 void
top_begin_sync(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size,int * error)190 top_begin_sync(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size, int *error)
191 {
192 ml_unit_t *ul = ufsvfsp->vfs_log;
193 mt_map_t *mtm = ul->un_logmap;
194 threadtrans_t *tp;
195 ushort_t seq;
196
197 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
198 ASSERT(error != NULL);
199 ASSERT(*error == 0);
200
201 mutex_enter(&mtm->mtm_lock);
202 if (topid == TOP_FSYNC) {
203 /*
204 * Error the fsync immediately if this is an nfs thread
205 * and its last transaction has already been committed.
206 * The only transactions outstanding are those
207 * where no commit has even started
208 * (last_async_tid == mtm->mtm_tid)
209 * or those where a commit is in progress
210 * (last_async_tid == mtm->mtm_committid)
211 */
212 if (curthread->t_flag & T_DONTPEND) {
213 tp = tsd_get(topkey);
214 if (tp && (tp->last_async_tid != mtm->mtm_tid) &&
215 (tp->last_async_tid != mtm->mtm_committid)) {
216 mutex_exit(&mtm->mtm_lock);
217 *error = 1;
218 return;
219 }
220 }
221
222 /*
223 * If there's already other synchronous transactions
224 * and we haven't allowed async ones to start yet
225 * then just wait for the commit to complete.
226 */
227 if (((mtm->mtm_closed & (TOP_SYNC | TOP_ASYNC)) ==
228 (TOP_SYNC | TOP_ASYNC)) || mtm->mtm_activesync) {
229 seq = mtm->mtm_seq;
230 do {
231 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
232 } while (seq == mtm->mtm_seq);
233 mutex_exit(&mtm->mtm_lock);
234 *error = 1;
235 return;
236 }
237 if (mtm->mtm_closed & TOP_SYNC) {
238 /*
239 * We know we're in the window where a thread is
240 * committing a transaction in top_end_sync() and
241 * has allowed async threads to start but hasn't
242 * got the completion on the commit write to
243 * allow sync threads to start.
244 * So wait for that commit completion then retest
245 * for the quick nfs check and if that fails
246 * go on to start a transaction
247 */
248 seq = mtm->mtm_seq;
249 do {
250 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
251 } while (seq == mtm->mtm_seq);
252
253 /* tp is set above if T_DONTPEND */
254 if ((curthread->t_flag & T_DONTPEND) && tp &&
255 (tp->last_async_tid != mtm->mtm_tid) &&
256 (tp->last_async_tid != mtm->mtm_committid)) {
257 mutex_exit(&mtm->mtm_lock);
258 *error = 1;
259 return;
260 }
261 }
262 }
263 retry:
264 mtm->mtm_ref = 1;
265 /*
266 * current transaction closed to sync ops; try for next transaction
267 */
268 if ((mtm->mtm_closed & TOP_SYNC) && !panicstr) {
269 ulong_t resv;
270
271 /*
272 * We know a commit is in progress, if we are trying to
273 * commit and we haven't allowed async ones to start yet,
274 * then just wait for the commit completion
275 */
276 if ((size == TOP_COMMIT_SIZE) &&
277 (((mtm->mtm_closed & (TOP_SYNC | TOP_ASYNC)) ==
278 (TOP_SYNC | TOP_ASYNC)) || (mtm->mtm_activesync))) {
279 seq = mtm->mtm_seq;
280 do {
281 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
282 } while (seq == mtm->mtm_seq);
283 mutex_exit(&mtm->mtm_lock);
284 *error = 1;
285 return;
286 }
287
288 /*
289 * next transaction is full; try for next transaction
290 */
291 resv = size + ul->un_resv_wantin + ul->un_resv;
292 if (resv > ul->un_maxresv) {
293 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
294 goto retry;
295 }
296 /*
297 * we are in the next transaction; wait for it to start
298 */
299 mtm->mtm_wantin++;
300 ul->un_resv_wantin += size;
301 /*
302 * The corresponding cv_broadcast wakes up
303 * all threads that have been validated to go into
304 * the next transaction. However, because spurious
305 * cv_wait wakeups are possible we use a sequence
306 * number to check that the commit and cv_broadcast
307 * has really occurred. We couldn't use mtm_tid
308 * because on error that doesn't get incremented.
309 */
310 seq = mtm->mtm_seq;
311 do {
312 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
313 } while (seq == mtm->mtm_seq);
314 } else {
315 /*
316 * if the current transaction is full; try the next one
317 */
318 if (size && (ul->un_resv && ((size + ul->un_resv) >
319 ul->un_maxresv)) && !panicstr) {
320 /*
321 * log is over reserved and no one will unresv the space
322 * so generate empty sync op to unresv the space
323 */
324 if (mtm->mtm_activesync == 0) {
325 mutex_exit(&mtm->mtm_lock);
326 top_issue_sync(ufsvfsp);
327 mutex_enter(&mtm->mtm_lock);
328 goto retry;
329 }
330 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
331 goto retry;
332 }
333 /*
334 * we are in the current transaction
335 */
336 mtm->mtm_active++;
337 mtm->mtm_activesync++;
338 ul->un_resv += size;
339 }
340
341 ASSERT(mtm->mtm_active > 0);
342 ASSERT(mtm->mtm_activesync > 0);
343 mutex_exit(&mtm->mtm_lock);
344
345 ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
346 top_begin_debug(ul, topid, size));
347 }
348
349 int tryfail_cnt;
350
351 int
top_begin_async(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size,int tryasync)352 top_begin_async(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size, int tryasync)
353 {
354 ml_unit_t *ul = ufsvfsp->vfs_log;
355 mt_map_t *mtm = ul->un_logmap;
356 threadtrans_t *tp;
357
358 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
359
360 tp = tsd_get(topkey);
361 if (tp == NULL) {
362 tp = kmem_zalloc(sizeof (threadtrans_t), KM_SLEEP);
363 (void) tsd_set(topkey, tp);
364 }
365 tp->deltas_size = 0;
366 tp->any_deltas = 0;
367
368 mutex_enter(&mtm->mtm_lock);
369 retry:
370 mtm->mtm_ref = 1;
371 /*
372 * current transaction closed to async ops; try for next transaction
373 */
374 if ((mtm->mtm_closed & TOP_ASYNC) && !panicstr) {
375 if (tryasync) {
376 mutex_exit(&mtm->mtm_lock);
377 tryfail_cnt++;
378 return (EWOULDBLOCK);
379 }
380 cv_wait(&mtm->mtm_cv_next, &mtm->mtm_lock);
381 goto retry;
382 }
383
384 /*
385 * if the current transaction is full; try the next one
386 */
387 if (((size + ul->un_resv + ul->un_resv_wantin) > ul->un_maxresv) &&
388 !panicstr) {
389 /*
390 * log is overreserved and no one will unresv the space
391 * so generate empty sync op to unresv the space
392 * We need TOP_SYNC_FORCED because we want to know when
393 * a top_end_sync is completed.
394 * mtm_taskq_sync_count is needed because we want to keep track
395 * of the pending top_issue_sync dispatches so that during
396 * forced umount we can wait for these to complete.
397 * mtm_taskq_sync_count is decremented in top_issue_sync and
398 * can remain set even after top_end_sync completes.
399 * We have a window between the clearing of TOP_SYNC_FORCED
400 * flag and the decrementing of mtm_taskq_sync_count.
401 * If in this window new async transactions start consuming
402 * log space, the log can get overreserved.
403 * Subsequently a new async transaction would fail to generate
404 * an empty sync transaction via the taskq, since it finds
405 * the mtm_taskq_sync_count set. This can cause a hang.
406 * Hence we do not test for mtm_taskq_sync_count being zero.
407 * Instead, the TOP_SYNC_FORCED flag is tested here.
408 */
409 if ((mtm->mtm_activesync == 0) &&
410 (!(mtm->mtm_closed & TOP_SYNC_FORCED))) {
411 /*
412 * Set flag to stop multiple forced empty
413 * sync transactions. Increment mtm_taskq_sync_count.
414 */
415 mtm->mtm_closed |= TOP_SYNC_FORCED;
416 mtm->mtm_taskq_sync_count++;
417 mutex_exit(&mtm->mtm_lock);
418 (void) taskq_dispatch(system_taskq,
419 top_issue_from_taskq, ufsvfsp, TQ_SLEEP);
420 if (tryasync) {
421 tryfail_cnt++;
422 return (EWOULDBLOCK);
423 }
424 mutex_enter(&mtm->mtm_lock);
425 goto retry;
426 }
427 if (tryasync) {
428 mutex_exit(&mtm->mtm_lock);
429 tryfail_cnt++;
430 return (EWOULDBLOCK);
431 }
432 cv_wait(&mtm->mtm_cv_next, &mtm->mtm_lock);
433 goto retry;
434 }
435 /*
436 * we are in the current transaction
437 */
438 mtm->mtm_active++;
439 ul->un_resv += size;
440
441 ASSERT(mtm->mtm_active > 0);
442 mutex_exit(&mtm->mtm_lock);
443
444 ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
445 top_begin_debug(ul, topid, size));
446 return (0);
447 }
448
449 /*ARGSUSED*/
450 void
top_end_sync(ufsvfs_t * ufsvfsp,int * ep,top_t topid,ulong_t size)451 top_end_sync(ufsvfs_t *ufsvfsp, int *ep, top_t topid, ulong_t size)
452 {
453 ml_unit_t *ul = ufsvfsp->vfs_log;
454 mt_map_t *mtm = ul->un_logmap;
455 mapentry_t *cancellist;
456 uint32_t tid;
457
458 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
459 ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
460 top_end_debug(ul, mtm, topid, size));
461
462 mutex_enter(&mtm->mtm_lock);
463 tid = mtm->mtm_tid;
464
465 mtm->mtm_activesync--;
466 mtm->mtm_active--;
467
468 mtm->mtm_ref = 1;
469
470 /*
471 * wait for last syncop to complete
472 */
473 if (mtm->mtm_activesync || panicstr) {
474 ushort_t seq = mtm->mtm_seq;
475
476 mtm->mtm_closed = TOP_SYNC;
477
478 do {
479 cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
480 } while (seq == mtm->mtm_seq);
481 mutex_exit(&mtm->mtm_lock);
482 goto out;
483 }
484 /*
485 * last syncop; close current transaction to all ops
486 */
487 mtm->mtm_closed = TOP_SYNC|TOP_ASYNC;
488
489 /*
490 * wait for last asyncop to finish
491 */
492 while (mtm->mtm_active) {
493 cv_wait(&mtm->mtm_cv_eot, &mtm->mtm_lock);
494 }
495
496 /*
497 * push dirty metadata thru the log
498 */
499 deltamap_push(ul);
500
501 ASSERT(((ul->un_debug & MT_FORCEROLL) == 0) ||
502 top_roll_debug(ul));
503
504 mtm->mtm_tid = tid + 1; /* can overflow to 0 */
505
506 /*
507 * Empty the cancellist, but save it for logmap_free_cancel
508 */
509 mutex_enter(&mtm->mtm_mutex);
510 cancellist = mtm->mtm_cancel;
511 mtm->mtm_cancel = NULL;
512 mutex_exit(&mtm->mtm_mutex);
513
514 /*
515 * allow async ops
516 */
517 ASSERT(mtm->mtm_active == 0);
518 ul->un_resv = 0; /* unreserve the log space */
519 mtm->mtm_closed = TOP_SYNC;
520 /*
521 * Hold the un_log_mutex here until we are done writing
522 * the commit record to prevent any more deltas to be written
523 * to the log after we allow async operations.
524 */
525 mutex_enter(&ul->un_log_mutex);
526 mutex_exit(&mtm->mtm_lock);
527 cv_broadcast(&mtm->mtm_cv_next);
528
529 /*
530 * asynchronously write the commit record,
531 */
532 logmap_commit(ul, tid);
533
534 /*
535 * wait for outstanding log writes (e.g., commits) to finish
536 */
537 ldl_waito(ul);
538
539 /*
540 * Now that we are sure the commit has been written to the log
541 * we can free any canceled deltas. If we free them before
542 * guaranteeing that the commit was written, we could panic before
543 * the commit, but after an async thread has allocated and written
544 * to canceled freed block.
545 */
546
547 logmap_free_cancel(mtm, &cancellist);
548 mutex_exit(&ul->un_log_mutex);
549
550 /*
551 * now, allow all ops
552 */
553 mutex_enter(&mtm->mtm_lock);
554 mtm->mtm_active += mtm->mtm_wantin;
555 ul->un_resv += ul->un_resv_wantin;
556 mtm->mtm_activesync = mtm->mtm_wantin;
557 mtm->mtm_wantin = 0;
558 mtm->mtm_closed = 0;
559 ul->un_resv_wantin = 0;
560 mtm->mtm_committid = mtm->mtm_tid;
561 mtm->mtm_seq++;
562 mutex_exit(&mtm->mtm_lock);
563
564 /*
565 * Finish any other synchronous transactions and
566 * start any waiting new synchronous transactions
567 */
568 cv_broadcast(&mtm->mtm_cv_commit);
569
570 /*
571 * if the logmap is getting full; roll something
572 */
573 if (logmap_need_roll_sync(mtm)) {
574 logmap_forceroll_nowait(mtm);
575 }
576
577 out:
578 if (ul->un_flags & LDL_ERROR)
579 *ep = EIO;
580 }
581
582 /*ARGSUSED*/
583 void
top_end_async(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size)584 top_end_async(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size)
585 {
586 ml_unit_t *ul = ufsvfsp->vfs_log;
587 mt_map_t *mtm = ul->un_logmap;
588 threadtrans_t *tp = tsd_get(topkey);
589 int wakeup_needed = 0;
590
591 ASSERT(tp);
592 ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
593 ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
594 top_end_debug(ul, mtm, topid, size));
595
596 mutex_enter(&mtm->mtm_lock);
597
598 if (size > tp->deltas_size) {
599 ul->un_resv -= (size - tp->deltas_size);
600 }
601 if (tp->any_deltas) {
602 tp->last_async_tid = mtm->mtm_tid;
603 }
604 mtm->mtm_ref = 1;
605
606 mtm->mtm_active--;
607 if ((mtm->mtm_active == 0) &&
608 (mtm->mtm_closed == (TOP_SYNC|TOP_ASYNC))) {
609 wakeup_needed = 1;
610 }
611 mutex_exit(&mtm->mtm_lock);
612 if (wakeup_needed)
613 cv_signal(&mtm->mtm_cv_eot);
614
615 /*
616 * Generate a sync op if the log, logmap, or deltamap are heavily used.
617 * Unless we are possibly holding any VM locks, since if we are holding
618 * any VM locks and we issue a top_end_sync(), we could deadlock.
619 */
620 if ((mtm->mtm_activesync == 0) &&
621 !(mtm->mtm_closed & TOP_SYNC) &&
622 (deltamap_need_commit(ul->un_deltamap) ||
623 logmap_need_commit(mtm) ||
624 ldl_need_commit(ul)) &&
625 (topid != TOP_GETPAGE)) {
626 top_issue_sync(ufsvfsp);
627 }
628 /*
629 * roll something from the log if the logmap is too full
630 */
631 if (logmap_need_roll_async(mtm))
632 logmap_forceroll_nowait(mtm);
633 }
634
635 /*
636 * Called from roll thread;
637 * buffer set for reading master
638 * Returns
639 * 0 - success, can continue with next buffer
640 * 1 - failure due to logmap deltas being in use
641 */
642 int
top_read_roll(rollbuf_t * rbp,ml_unit_t * ul)643 top_read_roll(rollbuf_t *rbp, ml_unit_t *ul)
644 {
645 buf_t *bp = &rbp->rb_bh;
646 offset_t mof = ldbtob(bp->b_blkno);
647
648 /*
649 * get a list of deltas
650 */
651 if (logmap_list_get_roll(ul->un_logmap, mof, rbp)) {
652 /* logmap deltas are in use */
653 return (1);
654 }
655
656 /*
657 * no deltas were found, nothing to roll
658 */
659 if (rbp->rb_age == NULL) {
660 bp->b_flags |= B_INVAL;
661 return (0);
662 }
663
664 /*
665 * If there is one cached roll buffer that cover all the deltas then
666 * we can use that instead of copying to a separate roll buffer.
667 */
668 if (rbp->rb_crb) {
669 rbp->rb_bh.b_blkno = lbtodb(rbp->rb_crb->c_mof);
670 return (0);
671 }
672
673 /*
674 * Set up the read.
675 * If no read is needed logmap_setup_read() returns 0.
676 */
677 if (logmap_setup_read(rbp->rb_age, rbp)) {
678 /*
679 * async read the data from master
680 */
681 logstats.ls_rreads.value.ui64++;
682 bp->b_bcount = MAPBLOCKSIZE;
683 (void) bdev_strategy(bp);
684 lwp_stat_update(LWP_STAT_INBLK, 1);
685 } else {
686 sema_v(&bp->b_io); /* mark read as complete */
687 }
688 return (0);
689 }
690
691 int ufs_crb_enable = 1;
692
693 /*
694 * move deltas from deltamap into the log
695 */
696 void
top_log(ufsvfs_t * ufsvfsp,char * va,offset_t vamof,off_t nb,caddr_t buf,uint32_t bufsz)697 top_log(ufsvfs_t *ufsvfsp, char *va, offset_t vamof, off_t nb,
698 caddr_t buf, uint32_t bufsz)
699 {
700 ml_unit_t *ul = ufsvfsp->vfs_log;
701 mapentry_t *me;
702 offset_t hmof;
703 uint32_t hnb, nb1;
704
705 /*
706 * needed for the roll thread's heuristic
707 */
708 ul->un_logmap->mtm_ref = 1;
709
710 if (buf && ufs_crb_enable) {
711 ASSERT((bufsz & DEV_BMASK) == 0);
712 /*
713 * Move any deltas to the logmap. Split requests that
714 * straddle MAPBLOCKSIZE hash boundaries (i.e. summary info).
715 */
716 for (hmof = vamof - (va - buf), nb1 = nb; bufsz;
717 bufsz -= hnb, hmof += hnb, buf += hnb, nb1 -= hnb) {
718 hnb = MAPBLOCKSIZE - (hmof & MAPBLOCKOFF);
719 if (hnb > bufsz)
720 hnb = bufsz;
721 me = deltamap_remove(ul->un_deltamap,
722 MAX(hmof, vamof), MIN(hnb, nb1));
723 if (me) {
724 logmap_add_buf(ul, va, hmof, me, buf, hnb);
725 }
726 }
727 } else {
728 /*
729 * if there are deltas
730 */
731 me = deltamap_remove(ul->un_deltamap, vamof, nb);
732 if (me) {
733 /*
734 * move to logmap
735 */
736 logmap_add(ul, va, vamof, me);
737 }
738 }
739
740 ASSERT((ul->un_matamap == NULL) ||
741 matamap_within(ul->un_matamap, vamof, nb));
742 }
743
744
745 static void
top_threadtrans_destroy(void * tp)746 top_threadtrans_destroy(void *tp)
747 {
748 kmem_free(tp, sizeof (threadtrans_t));
749 }
750
751 void
_init_top(void)752 _init_top(void)
753 {
754 ASSERT(top_init_debug());
755
756 /*
757 * set up the delta layer
758 */
759 _init_map();
760
761 /*
762 * Initialise the thread specific data transaction key
763 */
764 tsd_create(&topkey, top_threadtrans_destroy);
765 }
766