vfs_trans.c revision 1.47 1 /* $NetBSD: vfs_trans.c,v 1.47 2017/06/18 13:59:45 hannken Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juergen Hannken-Illjes.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.47 2017/06/18 13:59:45 hannken Exp $");
34
35 /*
36 * File system transaction operations.
37 */
38
39 #ifdef _KERNEL_OPT
40 #include "opt_ddb.h"
41 #endif
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/atomic.h>
46 #include <sys/buf.h>
47 #include <sys/kmem.h>
48 #include <sys/mount.h>
49 #include <sys/pserialize.h>
50 #include <sys/vnode.h>
51 #include <sys/fstrans.h>
52 #include <sys/proc.h>
53
54 #include <miscfs/specfs/specdev.h>
55
56 enum fstrans_lock_type {
57 FSTRANS_SHARED, /* Granted while not suspending */
58 FSTRANS_EXCL /* Internal: exclusive lock */
59 };
60
61 struct fscow_handler {
62 LIST_ENTRY(fscow_handler) ch_list;
63 int (*ch_func)(void *, struct buf *, bool);
64 void *ch_arg;
65 };
66 struct fstrans_lwp_info {
67 struct fstrans_lwp_info *fli_succ;
68 struct lwp *fli_self;
69 struct mount *fli_mount;
70 int fli_trans_cnt;
71 int fli_cow_cnt;
72 enum fstrans_lock_type fli_lock_type;
73 LIST_ENTRY(fstrans_lwp_info) fli_list;
74 };
75 struct fstrans_mount_info {
76 enum fstrans_state fmi_state;
77 unsigned int fmi_ref_cnt;
78 bool fmi_cow_change;
79 LIST_HEAD(, fscow_handler) fmi_cow_handler;
80 };
81
82 static specificdata_key_t lwp_data_key; /* Our specific data key. */
83 static kmutex_t vfs_suspend_lock; /* Serialize suspensions. */
84 static kmutex_t fstrans_lock; /* Fstrans big lock. */
85 static kmutex_t fstrans_mount_lock; /* Fstrans mount big lock. */
86 static kcondvar_t fstrans_state_cv; /* Fstrans or cow state changed. */
87 static kcondvar_t fstrans_count_cv; /* Fstrans or cow count changed. */
88 static pserialize_t fstrans_psz; /* Pserialize state. */
89 static LIST_HEAD(fstrans_lwp_head, fstrans_lwp_info) fstrans_fli_head;
90 /* List of all fstrans_lwp_info. */
91
92 static inline struct mount *fstrans_normalize_mount(struct mount *);
93 static void fstrans_lwp_dtor(void *);
94 static void fstrans_mount_dtor(struct mount *);
95 static void fstrans_clear_lwp_info(void);
96 static struct fstrans_lwp_info *fstrans_get_lwp_info(struct mount *, bool);
97 static inline int _fstrans_start(struct mount *, enum fstrans_lock_type, int);
98 static bool grant_lock(const enum fstrans_state, const enum fstrans_lock_type);
99 static bool state_change_done(const struct mount *);
100 static bool cow_state_change_done(const struct mount *);
101 static void cow_change_enter(const struct mount *);
102 static void cow_change_done(const struct mount *);
103
104 /*
105 * Initialize.
106 */
107 void
108 fstrans_init(void)
109 {
110 int error __diagused;
111
112 error = lwp_specific_key_create(&lwp_data_key, fstrans_lwp_dtor);
113 KASSERT(error == 0);
114
115 mutex_init(&vfs_suspend_lock, MUTEX_DEFAULT, IPL_NONE);
116 mutex_init(&fstrans_lock, MUTEX_DEFAULT, IPL_NONE);
117 mutex_init(&fstrans_mount_lock, MUTEX_DEFAULT, IPL_NONE);
118 cv_init(&fstrans_state_cv, "fstchg");
119 cv_init(&fstrans_count_cv, "fstcnt");
120 fstrans_psz = pserialize_create();
121 LIST_INIT(&fstrans_fli_head);
122 }
123
124 /*
125 * Normalize mount.
126 * Return mount if file system supports fstrans, NULL otherwise.
127 */
128 static inline struct mount *
129 fstrans_normalize_mount(struct mount *mp)
130 {
131
132 while (mp && mp->mnt_lower)
133 mp = mp->mnt_lower;
134 if (mp == NULL)
135 return NULL;
136 if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
137 return NULL;
138 return mp;
139 }
140
141 /*
142 * Deallocate lwp state.
143 */
144 static void
145 fstrans_lwp_dtor(void *arg)
146 {
147 struct fstrans_lwp_info *fli, *fli_next;
148
149 for (fli = arg; fli; fli = fli_next) {
150 KASSERT(fli->fli_trans_cnt == 0);
151 KASSERT(fli->fli_cow_cnt == 0);
152 if (fli->fli_mount != NULL)
153 fstrans_mount_dtor(fli->fli_mount);
154 fli_next = fli->fli_succ;
155 fli->fli_mount = NULL;
156 membar_sync();
157 fli->fli_self = NULL;
158 }
159 }
160
161 /*
162 * Dereference mount state.
163 */
164 static void
165 fstrans_mount_dtor(struct mount *mp)
166 {
167 struct fstrans_mount_info *fmi;
168
169 mutex_enter(&fstrans_mount_lock);
170
171 fmi = mp->mnt_transinfo;
172 KASSERT(fmi != NULL);
173 fmi->fmi_ref_cnt -= 1;
174 if (fmi->fmi_ref_cnt > 0) {
175 mutex_exit(&fstrans_mount_lock);
176 return;
177 }
178
179 KASSERT(fmi->fmi_state == FSTRANS_NORMAL);
180 KASSERT(LIST_FIRST(&fmi->fmi_cow_handler) == NULL);
181
182 mp->mnt_iflag &= ~IMNT_HAS_TRANS;
183 mp->mnt_transinfo = NULL;
184
185 mutex_exit(&fstrans_mount_lock);
186
187 kmem_free(fmi, sizeof(*fmi));
188 vfs_rele(mp);
189 }
190
191 /*
192 * Allocate mount state.
193 */
194 int
195 fstrans_mount(struct mount *mp)
196 {
197 struct fstrans_mount_info *newfmi;
198
199 newfmi = kmem_alloc(sizeof(*newfmi), KM_SLEEP);
200 newfmi->fmi_state = FSTRANS_NORMAL;
201 newfmi->fmi_ref_cnt = 1;
202 LIST_INIT(&newfmi->fmi_cow_handler);
203 newfmi->fmi_cow_change = false;
204
205 mutex_enter(&fstrans_mount_lock);
206 mp->mnt_transinfo = newfmi;
207 mp->mnt_iflag |= IMNT_HAS_TRANS;
208 mutex_exit(&fstrans_mount_lock);
209
210 vfs_ref(mp);
211
212 return 0;
213 }
214
215 /*
216 * Deallocate mount state.
217 */
218 void
219 fstrans_unmount(struct mount *mp)
220 {
221
222 if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
223 return;
224
225 KASSERT(mp->mnt_transinfo != NULL);
226
227 fstrans_mount_dtor(mp);
228 }
229
230 /*
231 * Clear mount entries whose mount is gone.
232 */
233 static void
234 fstrans_clear_lwp_info(void)
235 {
236 struct fstrans_lwp_info *fli;
237
238 /*
239 * Scan our list clearing entries whose mount is gone.
240 */
241 for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
242 if (fli->fli_mount != NULL &&
243 (fli->fli_mount->mnt_iflag & IMNT_GONE) != 0 &&
244 fli->fli_trans_cnt == 0 && fli->fli_cow_cnt == 0) {
245 fstrans_mount_dtor(fli->fli_mount);
246 fli->fli_mount = NULL;
247 }
248 }
249 }
250
251 /*
252 * Retrieve the per lwp info for this mount allocating if necessary.
253 */
254 static struct fstrans_lwp_info *
255 fstrans_get_lwp_info(struct mount *mp, bool do_alloc)
256 {
257 struct fstrans_lwp_info *fli;
258 struct fstrans_mount_info *fmi;
259
260 /*
261 * Scan our list for a match.
262 */
263 for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
264 if (fli->fli_mount == mp)
265 return fli;
266 }
267
268 if (! do_alloc)
269 return NULL;
270
271 /*
272 * Try to reuse a cleared entry or allocate a new one.
273 */
274 for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
275 if (fli->fli_mount == NULL) {
276 KASSERT(fli->fli_trans_cnt == 0);
277 KASSERT(fli->fli_cow_cnt == 0);
278 break;
279 }
280 }
281 if (fli == NULL) {
282 mutex_enter(&fstrans_lock);
283 LIST_FOREACH(fli, &fstrans_fli_head, fli_list) {
284 if (fli->fli_self == NULL) {
285 KASSERT(fli->fli_mount == NULL);
286 KASSERT(fli->fli_trans_cnt == 0);
287 KASSERT(fli->fli_cow_cnt == 0);
288 fli->fli_self = curlwp;
289 fli->fli_succ = lwp_getspecific(lwp_data_key);
290 lwp_setspecific(lwp_data_key, fli);
291 break;
292 }
293 }
294 mutex_exit(&fstrans_lock);
295 }
296 if (fli == NULL) {
297 fli = kmem_alloc(sizeof(*fli), KM_SLEEP);
298 mutex_enter(&fstrans_lock);
299 memset(fli, 0, sizeof(*fli));
300 fli->fli_self = curlwp;
301 LIST_INSERT_HEAD(&fstrans_fli_head, fli, fli_list);
302 mutex_exit(&fstrans_lock);
303 fli->fli_succ = lwp_getspecific(lwp_data_key);
304 lwp_setspecific(lwp_data_key, fli);
305 }
306
307 /*
308 * Attach the entry to the mount if its mnt_transinfo is valid.
309 */
310 mutex_enter(&fstrans_mount_lock);
311 fmi = mp->mnt_transinfo;
312 if (__predict_true(fmi != NULL)) {
313 fli->fli_mount = mp;
314 fmi->fmi_ref_cnt += 1;
315 } else {
316 fli = NULL;
317 }
318 mutex_exit(&fstrans_mount_lock);
319
320 return fli;
321 }
322
323 /*
324 * Check if this lock type is granted at this state.
325 */
326 static bool
327 grant_lock(const enum fstrans_state state, const enum fstrans_lock_type type)
328 {
329
330 if (__predict_true(state == FSTRANS_NORMAL))
331 return true;
332 if (type == FSTRANS_EXCL)
333 return true;
334
335 return false;
336 }
337
338 /*
339 * Start a transaction. If this thread already has a transaction on this
340 * file system increment the reference counter.
341 */
342 static inline int
343 _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
344 {
345 int s;
346 struct mount *lmp;
347 struct fstrans_lwp_info *fli;
348 struct fstrans_mount_info *fmi;
349
350 if ((lmp = fstrans_normalize_mount(mp)) == NULL)
351 return 0;
352
353 ASSERT_SLEEPABLE();
354
355 /*
356 * Allocate per lwp info for layered file systems to
357 * get a reference to the mount. No need to increment
358 * the reference counter here.
359 */
360 for (lmp = mp; lmp->mnt_lower; lmp = lmp->mnt_lower) {
361 fli = fstrans_get_lwp_info(lmp, true);
362 }
363
364 if ((fli = fstrans_get_lwp_info(lmp, true)) == NULL)
365 return 0;
366
367 if (fli->fli_trans_cnt > 0) {
368 KASSERT(lock_type != FSTRANS_EXCL);
369 fli->fli_trans_cnt += 1;
370
371 return 0;
372 }
373
374 s = pserialize_read_enter();
375 fmi = lmp->mnt_transinfo;
376 if (__predict_true(grant_lock(fmi->fmi_state, lock_type))) {
377 fli->fli_trans_cnt = 1;
378 fli->fli_lock_type = lock_type;
379 pserialize_read_exit(s);
380
381 return 0;
382 }
383 pserialize_read_exit(s);
384
385 if (! wait)
386 return EBUSY;
387
388 mutex_enter(&fstrans_lock);
389 while (! grant_lock(fmi->fmi_state, lock_type))
390 cv_wait(&fstrans_state_cv, &fstrans_lock);
391 fli->fli_trans_cnt = 1;
392 fli->fli_lock_type = lock_type;
393 mutex_exit(&fstrans_lock);
394
395 return 0;
396 }
397
398 void
399 fstrans_start(struct mount *mp)
400 {
401 int error __diagused;
402
403 error = _fstrans_start(mp, FSTRANS_SHARED, 1);
404 KASSERT(error == 0);
405 }
406
407 int
408 fstrans_start_nowait(struct mount *mp)
409 {
410
411 return _fstrans_start(mp, FSTRANS_SHARED, 0);
412 }
413
414 /*
415 * Finish a transaction.
416 */
417 void
418 fstrans_done(struct mount *mp)
419 {
420 int s;
421 struct fstrans_lwp_info *fli;
422 struct fstrans_mount_info *fmi;
423
424 if ((mp = fstrans_normalize_mount(mp)) == NULL)
425 return;
426 if ((fli = fstrans_get_lwp_info(mp, false)) == NULL)
427 return;
428 KASSERT(fli->fli_trans_cnt > 0);
429
430 if (fli->fli_trans_cnt > 1) {
431 fli->fli_trans_cnt -= 1;
432
433 return;
434 }
435
436 fstrans_clear_lwp_info();
437
438 s = pserialize_read_enter();
439 fmi = mp->mnt_transinfo;
440 if (__predict_true(fmi->fmi_state == FSTRANS_NORMAL)) {
441 fli->fli_trans_cnt = 0;
442 pserialize_read_exit(s);
443
444 return;
445 }
446 pserialize_read_exit(s);
447
448 mutex_enter(&fstrans_lock);
449 fli->fli_trans_cnt = 0;
450 cv_signal(&fstrans_count_cv);
451 mutex_exit(&fstrans_lock);
452 }
453
454 /*
455 * Check if this thread has an exclusive lock.
456 */
457 int
458 fstrans_is_owner(struct mount *mp)
459 {
460 struct fstrans_lwp_info *fli;
461
462 if ((mp = fstrans_normalize_mount(mp)) == NULL)
463 return 0;
464 if ((fli = fstrans_get_lwp_info(mp, false)) == NULL)
465 return 0;
466
467 if (fli->fli_trans_cnt == 0)
468 return 0;
469
470 KASSERT(fli->fli_mount == mp);
471 KASSERT(fli->fli_trans_cnt > 0);
472
473 return (fli->fli_lock_type == FSTRANS_EXCL);
474 }
475
476 /*
477 * True, if no thread is in a transaction not granted at the current state.
478 */
479 static bool
480 state_change_done(const struct mount *mp)
481 {
482 struct fstrans_lwp_info *fli;
483 struct fstrans_mount_info *fmi;
484
485 KASSERT(mutex_owned(&fstrans_lock));
486
487 fmi = mp->mnt_transinfo;
488 LIST_FOREACH(fli, &fstrans_fli_head, fli_list) {
489 if (fli->fli_mount != mp)
490 continue;
491 if (fli->fli_trans_cnt == 0)
492 continue;
493 if (grant_lock(fmi->fmi_state, fli->fli_lock_type))
494 continue;
495
496 return false;
497 }
498
499 return true;
500 }
501
502 /*
503 * Set new file system state.
504 */
505 int
506 fstrans_setstate(struct mount *mp, enum fstrans_state new_state)
507 {
508 int error;
509 enum fstrans_state old_state;
510 struct fstrans_mount_info *fmi;
511
512 fmi = mp->mnt_transinfo;
513 old_state = fmi->fmi_state;
514 if (old_state == new_state)
515 return 0;
516
517 mutex_enter(&fstrans_lock);
518 fmi->fmi_state = new_state;
519 pserialize_perform(fstrans_psz);
520
521 /*
522 * All threads see the new state now.
523 * Wait for transactions invalid at this state to leave.
524 */
525 error = 0;
526 while (! state_change_done(mp)) {
527 error = cv_wait_sig(&fstrans_count_cv, &fstrans_lock);
528 if (error) {
529 new_state = fmi->fmi_state = FSTRANS_NORMAL;
530 break;
531 }
532 }
533 cv_broadcast(&fstrans_state_cv);
534 mutex_exit(&fstrans_lock);
535
536 if (old_state != new_state) {
537 if (old_state == FSTRANS_NORMAL)
538 _fstrans_start(mp, FSTRANS_EXCL, 1);
539 if (new_state == FSTRANS_NORMAL)
540 fstrans_done(mp);
541 }
542
543 return error;
544 }
545
546 /*
547 * Get current file system state.
548 */
549 enum fstrans_state
550 fstrans_getstate(struct mount *mp)
551 {
552 struct fstrans_mount_info *fmi;
553
554 fmi = mp->mnt_transinfo;
555 KASSERT(fmi != NULL);
556
557 return fmi->fmi_state;
558 }
559
560 /*
561 * Request a filesystem to suspend all operations.
562 */
563 int
564 vfs_suspend(struct mount *mp, int nowait)
565 {
566 int error;
567
568 if ((mp = fstrans_normalize_mount(mp)) == NULL)
569 return EOPNOTSUPP;
570 if (nowait) {
571 if (!mutex_tryenter(&vfs_suspend_lock))
572 return EWOULDBLOCK;
573 } else
574 mutex_enter(&vfs_suspend_lock);
575
576 if ((error = VFS_SUSPENDCTL(mp, SUSPEND_SUSPEND)) != 0)
577 mutex_exit(&vfs_suspend_lock);
578
579 return error;
580 }
581
582 /*
583 * Request a filesystem to resume all operations.
584 */
585 void
586 vfs_resume(struct mount *mp)
587 {
588
589 mp = fstrans_normalize_mount(mp);
590 KASSERT(mp != NULL);
591
592 VFS_SUSPENDCTL(mp, SUSPEND_RESUME);
593 mutex_exit(&vfs_suspend_lock);
594 }
595
596
597 /*
598 * True, if no thread is running a cow handler.
599 */
600 static bool
601 cow_state_change_done(const struct mount *mp)
602 {
603 struct fstrans_lwp_info *fli;
604 struct fstrans_mount_info *fmi __diagused;
605
606 fmi = mp->mnt_transinfo;
607
608 KASSERT(mutex_owned(&fstrans_lock));
609 KASSERT(fmi->fmi_cow_change);
610
611 LIST_FOREACH(fli, &fstrans_fli_head, fli_list) {
612 if (fli->fli_mount != mp)
613 continue;
614 if (fli->fli_cow_cnt == 0)
615 continue;
616
617 return false;
618 }
619
620 return true;
621 }
622
623 /*
624 * Prepare for changing this mounts cow list.
625 * Returns with fstrans_lock locked.
626 */
627 static void
628 cow_change_enter(const struct mount *mp)
629 {
630 struct fstrans_mount_info *fmi;
631
632 fmi = mp->mnt_transinfo;
633
634 mutex_enter(&fstrans_lock);
635
636 /*
637 * Wait for other threads changing the list.
638 */
639 while (fmi->fmi_cow_change)
640 cv_wait(&fstrans_state_cv, &fstrans_lock);
641
642 /*
643 * Wait until all threads are aware of a state change.
644 */
645 fmi->fmi_cow_change = true;
646 pserialize_perform(fstrans_psz);
647
648 while (! cow_state_change_done(mp))
649 cv_wait(&fstrans_count_cv, &fstrans_lock);
650 }
651
652 /*
653 * Done changing this mounts cow list.
654 */
655 static void
656 cow_change_done(const struct mount *mp)
657 {
658 struct fstrans_mount_info *fmi;
659
660 KASSERT(mutex_owned(&fstrans_lock));
661
662 fmi = mp->mnt_transinfo;
663
664 fmi->fmi_cow_change = false;
665 pserialize_perform(fstrans_psz);
666
667 cv_broadcast(&fstrans_state_cv);
668
669 mutex_exit(&fstrans_lock);
670 }
671
672 /*
673 * Add a handler to this mount.
674 */
675 int
676 fscow_establish(struct mount *mp, int (*func)(void *, struct buf *, bool),
677 void *arg)
678 {
679 struct fstrans_mount_info *fmi;
680 struct fscow_handler *newch;
681
682 if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
683 return EINVAL;
684
685 fmi = mp->mnt_transinfo;
686 KASSERT(fmi != NULL);
687
688 newch = kmem_alloc(sizeof(*newch), KM_SLEEP);
689 newch->ch_func = func;
690 newch->ch_arg = arg;
691
692 cow_change_enter(mp);
693 LIST_INSERT_HEAD(&fmi->fmi_cow_handler, newch, ch_list);
694 cow_change_done(mp);
695
696 return 0;
697 }
698
699 /*
700 * Remove a handler from this mount.
701 */
702 int
703 fscow_disestablish(struct mount *mp, int (*func)(void *, struct buf *, bool),
704 void *arg)
705 {
706 struct fstrans_mount_info *fmi;
707 struct fscow_handler *hp = NULL;
708
709 if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
710 return EINVAL;
711
712 fmi = mp->mnt_transinfo;
713 KASSERT(fmi != NULL);
714
715 cow_change_enter(mp);
716 LIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list)
717 if (hp->ch_func == func && hp->ch_arg == arg)
718 break;
719 if (hp != NULL) {
720 LIST_REMOVE(hp, ch_list);
721 kmem_free(hp, sizeof(*hp));
722 }
723 cow_change_done(mp);
724
725 return hp ? 0 : EINVAL;
726 }
727
728 /*
729 * Check for need to copy block that is about to be written.
730 */
731 int
732 fscow_run(struct buf *bp, bool data_valid)
733 {
734 int error, s;
735 struct mount *mp;
736 struct fstrans_lwp_info *fli;
737 struct fstrans_mount_info *fmi;
738 struct fscow_handler *hp;
739
740 /*
741 * First check if we need run the copy-on-write handler.
742 */
743 if ((bp->b_flags & B_COWDONE))
744 return 0;
745 if (bp->b_vp == NULL) {
746 bp->b_flags |= B_COWDONE;
747 return 0;
748 }
749 if (bp->b_vp->v_type == VBLK)
750 mp = spec_node_getmountedfs(bp->b_vp);
751 else
752 mp = bp->b_vp->v_mount;
753 if (mp == NULL || (mp->mnt_iflag & IMNT_HAS_TRANS) == 0) {
754 bp->b_flags |= B_COWDONE;
755 return 0;
756 }
757
758 fli = fstrans_get_lwp_info(mp, true);
759 fmi = mp->mnt_transinfo;
760
761 /*
762 * On non-recursed run check if other threads
763 * want to change the list.
764 */
765 if (fli->fli_cow_cnt == 0) {
766 s = pserialize_read_enter();
767 if (__predict_false(fmi->fmi_cow_change)) {
768 pserialize_read_exit(s);
769 mutex_enter(&fstrans_lock);
770 while (fmi->fmi_cow_change)
771 cv_wait(&fstrans_state_cv, &fstrans_lock);
772 fli->fli_cow_cnt = 1;
773 mutex_exit(&fstrans_lock);
774 } else {
775 fli->fli_cow_cnt = 1;
776 pserialize_read_exit(s);
777 }
778 } else
779 fli->fli_cow_cnt += 1;
780
781 /*
782 * Run all copy-on-write handlers, stop on error.
783 */
784 error = 0;
785 LIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list)
786 if ((error = (*hp->ch_func)(hp->ch_arg, bp, data_valid)) != 0)
787 break;
788 if (error == 0)
789 bp->b_flags |= B_COWDONE;
790
791 /*
792 * Check if other threads want to change the list.
793 */
794 if (fli->fli_cow_cnt > 1) {
795 fli->fli_cow_cnt -= 1;
796 } else {
797 s = pserialize_read_enter();
798 if (__predict_false(fmi->fmi_cow_change)) {
799 pserialize_read_exit(s);
800 mutex_enter(&fstrans_lock);
801 fli->fli_cow_cnt = 0;
802 cv_signal(&fstrans_count_cv);
803 mutex_exit(&fstrans_lock);
804 } else {
805 fli->fli_cow_cnt = 0;
806 pserialize_read_exit(s);
807 }
808 }
809
810 return error;
811 }
812
813 #if defined(DDB)
814 void fstrans_dump(int);
815
816 static void
817 fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose)
818 {
819 char prefix[9];
820 struct fstrans_lwp_info *fli;
821
822 snprintf(prefix, sizeof(prefix), "%d.%d", p->p_pid, l->l_lid);
823 LIST_FOREACH(fli, &fstrans_fli_head, fli_list) {
824 if (fli->fli_self != l)
825 continue;
826 if (fli->fli_trans_cnt == 0 && fli->fli_cow_cnt == 0) {
827 if (! verbose)
828 continue;
829 }
830 printf("%-8s", prefix);
831 if (verbose)
832 printf(" @%p", fli);
833 if (fli->fli_mount != NULL)
834 printf(" (%s)", fli->fli_mount->mnt_stat.f_mntonname);
835 else
836 printf(" NULL");
837 if (fli->fli_trans_cnt == 0) {
838 printf(" -");
839 } else {
840 switch (fli->fli_lock_type) {
841 case FSTRANS_SHARED:
842 printf(" shared");
843 break;
844 case FSTRANS_EXCL:
845 printf(" excl");
846 break;
847 default:
848 printf(" %#x", fli->fli_lock_type);
849 break;
850 }
851 }
852 printf(" %d cow %d\n", fli->fli_trans_cnt, fli->fli_cow_cnt);
853 prefix[0] = '\0';
854 }
855 }
856
857 static void
858 fstrans_print_mount(struct mount *mp, int verbose)
859 {
860 struct fstrans_mount_info *fmi;
861
862 fmi = mp->mnt_transinfo;
863 if (!verbose && (fmi == NULL || fmi->fmi_state == FSTRANS_NORMAL))
864 return;
865
866 printf("%-16s ", mp->mnt_stat.f_mntonname);
867 if (fmi == NULL) {
868 printf("(null)\n");
869 return;
870 }
871 switch (fmi->fmi_state) {
872 case FSTRANS_NORMAL:
873 printf("state normal\n");
874 break;
875 case FSTRANS_SUSPENDED:
876 printf("state suspended\n");
877 break;
878 default:
879 printf("state %#x\n", fmi->fmi_state);
880 break;
881 }
882 }
883
884 void
885 fstrans_dump(int full)
886 {
887 const struct proclist_desc *pd;
888 struct proc *p;
889 struct lwp *l;
890 struct mount *mp;
891
892 printf("Fstrans locks by lwp:\n");
893 for (pd = proclists; pd->pd_list != NULL; pd++)
894 PROCLIST_FOREACH(p, pd->pd_list)
895 LIST_FOREACH(l, &p->p_lwps, l_sibling)
896 fstrans_print_lwp(p, l, full == 1);
897
898 printf("Fstrans state by mount:\n");
899 for (mp = _mountlist_next(NULL); mp; mp = _mountlist_next(mp))
900 fstrans_print_mount(mp, full == 1);
901 }
902 #endif /* defined(DDB) */
903