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