1/* $NetBSD: lfs_subr.c,v 1.103 2020/09/05 16:30:13 riastradh Exp $ */ 2 3/*- 4 * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 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 * Copyright (c) 1991, 1993 33 * The Regents of the University of California. All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * @(#)lfs_subr.c 8.4 (Berkeley) 5/8/95 60 */ 61 62#include <sys/cdefs.h> 63__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.103 2020/09/05 16:30:13 riastradh Exp $"); 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/namei.h> 68#include <sys/vnode.h> 69#include <sys/buf.h> 70#include <sys/mount.h> 71#include <sys/malloc.h> 72#include <sys/proc.h> 73#include <sys/kauth.h> 74 75#include <ufs/lfs/ulfs_inode.h> 76#include <ufs/lfs/lfs.h> 77#include <ufs/lfs/lfs_accessors.h> 78#include <ufs/lfs/lfs_kernel.h> 79#include <ufs/lfs/lfs_extern.h> 80 81#ifdef DEBUG 82const char *lfs_res_names[LFS_NB_COUNT] = { 83 "summary", 84 "superblock", 85 "file block", 86 "cluster", 87 "clean", 88 "blkiov", 89}; 90#endif 91 92int lfs_res_qty[LFS_NB_COUNT] = { 93 LFS_N_SUMMARIES, 94 LFS_N_SBLOCKS, 95 LFS_N_IBLOCKS, 96 LFS_N_CLUSTERS, 97 LFS_N_CLEAN, 98 LFS_N_BLKIOV, 99}; 100 101void 102lfs_setup_resblks(struct lfs *fs) 103{ 104 int i, j; 105 int maxbpp; 106 107 ASSERT_NO_SEGLOCK(fs); 108 fs->lfs_resblk = malloc(LFS_N_TOTAL * sizeof(res_t), M_SEGMENT, 109 M_WAITOK); 110 for (i = 0; i < LFS_N_TOTAL; i++) { 111 fs->lfs_resblk[i].inuse = 0; 112 fs->lfs_resblk[i].p = NULL; 113 } 114 for (i = 0; i < LFS_RESHASH_WIDTH; i++) 115 LIST_INIT(fs->lfs_reshash + i); 116 117 /* 118 * These types of allocations can be larger than a page, 119 * so we can't use the pool subsystem for them. 120 */ 121 for (i = 0, j = 0; j < LFS_N_SUMMARIES; j++, i++) 122 fs->lfs_resblk[i].size = lfs_sb_getsumsize(fs); 123 for (j = 0; j < LFS_N_SBLOCKS; j++, i++) 124 fs->lfs_resblk[i].size = LFS_SBPAD; 125 for (j = 0; j < LFS_N_IBLOCKS; j++, i++) 126 fs->lfs_resblk[i].size = lfs_sb_getbsize(fs); 127 for (j = 0; j < LFS_N_CLUSTERS; j++, i++) 128 fs->lfs_resblk[i].size = MAXPHYS; 129 for (j = 0; j < LFS_N_CLEAN; j++, i++) 130 fs->lfs_resblk[i].size = MAXPHYS; 131 for (j = 0; j < LFS_N_BLKIOV; j++, i++) 132 fs->lfs_resblk[i].size = LFS_MARKV_MAXBLKCNT * sizeof(BLOCK_INFO); 133 134 for (i = 0; i < LFS_N_TOTAL; i++) { 135 fs->lfs_resblk[i].p = malloc(fs->lfs_resblk[i].size, 136 M_SEGMENT, M_WAITOK); 137 } 138 139 /* 140 * Initialize pools for small types (XXX is BPP small?) 141 */ 142 pool_init(&fs->lfs_clpool, sizeof(struct lfs_cluster), 0, 0, 0, 143 "lfsclpl", &pool_allocator_nointr, IPL_NONE); 144 pool_init(&fs->lfs_segpool, sizeof(struct segment), 0, 0, 0, 145 "lfssegpool", &pool_allocator_nointr, IPL_NONE); 146 /* XXX: should this int32 be 32/64? */ 147 maxbpp = ((lfs_sb_getsumsize(fs) - SEGSUM_SIZE(fs)) / sizeof(int32_t) + 2); 148 maxbpp = MIN(maxbpp, lfs_segsize(fs) / lfs_sb_getfsize(fs) + 2); 149 pool_init(&fs->lfs_bpppool, maxbpp * sizeof(struct buf *), 0, 0, 0, 150 "lfsbpppl", &pool_allocator_nointr, IPL_NONE); 151} 152 153void 154lfs_free_resblks(struct lfs *fs) 155{ 156 int i; 157 158 pool_destroy(&fs->lfs_bpppool); 159 pool_destroy(&fs->lfs_segpool); 160 pool_destroy(&fs->lfs_clpool); 161 162 mutex_enter(&lfs_lock); 163 for (i = 0; i < LFS_N_TOTAL; i++) { 164 while (fs->lfs_resblk[i].inuse) 165 mtsleep(&fs->lfs_resblk, PRIBIO + 1, "lfs_free", 0, 166 &lfs_lock); 167 if (fs->lfs_resblk[i].p != NULL) 168 free(fs->lfs_resblk[i].p, M_SEGMENT); 169 } 170 free(fs->lfs_resblk, M_SEGMENT); 171 mutex_exit(&lfs_lock); 172} 173 174static unsigned int 175lfs_mhash(void *vp) 176{ 177 return (unsigned int)(((unsigned long)vp) >> 2) % LFS_RESHASH_WIDTH; 178} 179 180/* 181 * Return memory of the given size for the given purpose, or use one of a 182 * number of spare last-resort buffers, if malloc returns NULL. 183 */ 184void * 185lfs_malloc(struct lfs *fs, size_t size, int type) 186{ 187 struct lfs_res_blk *re; 188 void *r; 189 int i, start; 190 unsigned int h; 191 192 ASSERT_MAYBE_SEGLOCK(fs); 193 r = NULL; 194 195 /* If no mem allocated for this type, it just waits */ 196 if (lfs_res_qty[type] == 0) { 197 r = malloc(size, M_SEGMENT, M_WAITOK); 198 return r; 199 } 200 201 /* Otherwise try a quick malloc, and if it works, great */ 202 if ((r = malloc(size, M_SEGMENT, M_NOWAIT)) != NULL) { 203 return r; 204 } 205 206 /* 207 * If malloc returned NULL, we are forced to use one of our 208 * reserve blocks. We have on hand at least one summary block, 209 * at least one cluster block, at least one superblock, 210 * and several indirect blocks. 211 */ 212 213 mutex_enter(&lfs_lock); 214 /* skip over blocks of other types */ 215 for (i = 0, start = 0; i < type; i++) 216 start += lfs_res_qty[i]; 217 while (r == NULL) { 218 for (i = 0; i < lfs_res_qty[type]; i++) { 219 if (fs->lfs_resblk[start + i].inuse == 0) { 220 re = fs->lfs_resblk + start + i; 221 re->inuse = 1; 222 r = re->p; 223 KASSERT(re->size >= size); 224 h = lfs_mhash(r); 225 LIST_INSERT_HEAD(&fs->lfs_reshash[h], re, res); 226 mutex_exit(&lfs_lock); 227 return r; 228 } 229 } 230 DLOG((DLOG_MALLOC, "sleeping on %s (%d)\n", 231 lfs_res_names[type], lfs_res_qty[type])); 232 mtsleep(&fs->lfs_resblk, PVM, "lfs_malloc", 0, 233 &lfs_lock); 234 DLOG((DLOG_MALLOC, "done sleeping on %s\n", 235 lfs_res_names[type])); 236 } 237 /* NOTREACHED */ 238 mutex_exit(&lfs_lock); 239 return r; 240} 241 242void 243lfs_free(struct lfs *fs, void *p, int type) 244{ 245 unsigned int h; 246 res_t *re; 247 248 ASSERT_MAYBE_SEGLOCK(fs); 249 h = lfs_mhash(p); 250 mutex_enter(&lfs_lock); 251 LIST_FOREACH(re, &fs->lfs_reshash[h], res) { 252 if (re->p == p) { 253 KASSERT(re->inuse == 1); 254 LIST_REMOVE(re, res); 255 re->inuse = 0; 256 wakeup(&fs->lfs_resblk); 257 mutex_exit(&lfs_lock); 258 return; 259 } 260 } 261 262#ifdef notyet /* XXX this assert fires */ 263 for (int i = 0; i < LFS_N_TOTAL; i++) { 264 KDASSERTMSG(fs->lfs_resblk[i].p == p, 265 "lfs_free: inconsistent reserved block"); 266 } 267#endif 268 269 mutex_exit(&lfs_lock); 270 271 /* 272 * If we didn't find it, free it. 273 */ 274 free(p, M_SEGMENT); 275} 276 277/* 278 * lfs_seglock -- 279 * Single thread the segment writer. 280 */ 281int 282lfs_seglock(struct lfs *fs, unsigned long flags) 283{ 284 struct segment *sp; 285 286 mutex_enter(&lfs_lock); 287 if (fs->lfs_seglock) { 288 if (fs->lfs_lockpid == curproc->p_pid && 289 fs->lfs_locklwp == curlwp->l_lid) { 290 ++fs->lfs_seglock; 291 fs->lfs_sp->seg_flags |= flags; 292 mutex_exit(&lfs_lock); 293 return 0; 294 } else if (flags & SEGM_PAGEDAEMON) { 295 mutex_exit(&lfs_lock); 296 return EWOULDBLOCK; 297 } else { 298 while (fs->lfs_seglock) { 299 (void)mtsleep(&fs->lfs_seglock, PRIBIO + 1, 300 "lfs_seglock", 0, &lfs_lock); 301 } 302 } 303 } 304 305 fs->lfs_seglock = 1; 306 fs->lfs_lockpid = curproc->p_pid; 307 fs->lfs_locklwp = curlwp->l_lid; 308 mutex_exit(&lfs_lock); 309 fs->lfs_cleanind = 0; 310 311 LFS_ENTER_LOG("seglock", __FILE__, __LINE__, 0, flags, curproc->p_pid); 312 313 /* Drain fragment size changes out */ 314 rw_enter(&fs->lfs_fraglock, RW_WRITER); 315 316 sp = fs->lfs_sp = pool_get(&fs->lfs_segpool, PR_WAITOK); 317 sp->bpp = pool_get(&fs->lfs_bpppool, PR_WAITOK); 318 sp->seg_flags = flags; 319 sp->vp = NULL; 320 sp->seg_iocount = 0; 321 (void) lfs_initseg(fs); 322 323 /* 324 * Keep a cumulative count of the outstanding I/O operations. If the 325 * disk drive catches up with us it could go to zero before we finish, 326 * so we artificially increment it by one until we've scheduled all of 327 * the writes we intend to do. 328 */ 329 mutex_enter(&lfs_lock); 330 ++fs->lfs_iocount; 331 fs->lfs_startseg = lfs_sb_getcurseg(fs); 332 mutex_exit(&lfs_lock); 333 return 0; 334} 335 336static void lfs_unmark_dirop(struct lfs *); 337 338static void 339lfs_unmark_dirop(struct lfs *fs) 340{ 341 struct inode *ip, *marker; 342 struct vnode *vp; 343 int doit; 344 345 ASSERT_NO_SEGLOCK(fs); 346 mutex_enter(&lfs_lock); 347 doit = !(fs->lfs_flags & LFS_UNDIROP); 348 if (doit) 349 fs->lfs_flags |= LFS_UNDIROP; 350 mutex_exit(&lfs_lock); 351 352 if (!doit) 353 return; 354 355 marker = pool_get(&lfs_inode_pool, PR_WAITOK); 356 KASSERT(fs != NULL); 357 memset(marker, 0, sizeof(*marker)); 358 marker->inode_ext.lfs = pool_get(&lfs_inoext_pool, PR_WAITOK); 359 memset(marker->inode_ext.lfs, 0, sizeof(*marker->inode_ext.lfs)); 360 marker->i_state |= IN_MARKER; 361 362 mutex_enter(&lfs_lock); 363 TAILQ_INSERT_HEAD(&fs->lfs_dchainhd, marker, i_lfs_dchain); 364 while ((ip = TAILQ_NEXT(marker, i_lfs_dchain)) != NULL) { 365 TAILQ_REMOVE(&fs->lfs_dchainhd, marker, i_lfs_dchain); 366 TAILQ_INSERT_AFTER(&fs->lfs_dchainhd, ip, marker, 367 i_lfs_dchain); 368 if (ip->i_state & IN_MARKER) 369 continue; 370 vp = ITOV(ip); 371 if ((ip->i_state & (IN_ADIROP | IN_CDIROP)) == IN_CDIROP) { 372 --lfs_dirvcount; 373 --fs->lfs_dirvcount; 374 vp->v_uflag &= ~VU_DIROP; 375 TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain); 376 wakeup(&lfs_dirvcount); 377 fs->lfs_unlockvp = vp; 378 mutex_exit(&lfs_lock); 379 vrele(vp); 380 mutex_enter(&lfs_lock); 381 fs->lfs_unlockvp = NULL; 382 ip->i_state &= ~IN_CDIROP; 383 } 384 } 385 TAILQ_REMOVE(&fs->lfs_dchainhd, marker, i_lfs_dchain); 386 fs->lfs_flags &= ~LFS_UNDIROP; 387 wakeup(&fs->lfs_flags); 388 mutex_exit(&lfs_lock); 389 390 pool_put(&lfs_inoext_pool, marker->inode_ext.lfs); 391 pool_put(&lfs_inode_pool, marker); 392} 393 394static void 395lfs_auto_segclean(struct lfs *fs) 396{ 397 int i, error, waited; 398 399 ASSERT_SEGLOCK(fs); 400 /* 401 * Now that we've swapped lfs_activesb, but while we still 402 * hold the segment lock, run through the segment list marking 403 * the empty ones clean. 404 * XXX - do we really need to do them all at once? 405 */ 406 waited = 0; 407 for (i = 0; i < lfs_sb_getnseg(fs); i++) { 408 if ((fs->lfs_suflags[0][i] & 409 (SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) == 410 (SEGUSE_DIRTY | SEGUSE_EMPTY) && 411 (fs->lfs_suflags[1][i] & 412 (SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) == 413 (SEGUSE_DIRTY | SEGUSE_EMPTY)) { 414 415 /* Make sure the sb is written before we clean */ 416 mutex_enter(&lfs_lock); 417 while (waited == 0 && fs->lfs_sbactive) 418 mtsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs asb", 419 0, &lfs_lock); 420 mutex_exit(&lfs_lock); 421 waited = 1; 422 423 if ((error = lfs_do_segclean(fs, i)) != 0) { 424 DLOG((DLOG_CLEAN, "lfs_auto_segclean: lfs_do_segclean returned %d for seg %d\n", error, i)); 425 } 426 } 427 fs->lfs_suflags[1 - fs->lfs_activesb][i] = 428 fs->lfs_suflags[fs->lfs_activesb][i]; 429 } 430} 431 432/* 433 * lfs_segunlock -- 434 * Single thread the segment writer. 435 */ 436void 437lfs_segunlock(struct lfs *fs) 438{ 439 struct segment *sp; 440 unsigned long sync, ckp; 441 struct buf *bp; 442 int do_unmark_dirop = 0; 443 444 sp = fs->lfs_sp; 445 446 mutex_enter(&lfs_lock); 447 448 if (!LFS_SEGLOCK_HELD(fs)) 449 panic("lfs seglock not held"); 450 451 if (fs->lfs_seglock == 1) { 452 if ((sp->seg_flags & (SEGM_PROT | SEGM_CLEAN)) == 0) 453 do_unmark_dirop = 1; 454 mutex_exit(&lfs_lock); 455 sync = sp->seg_flags & SEGM_SYNC; 456 ckp = sp->seg_flags & SEGM_CKP; 457 458 /* We should have a segment summary, and nothing else */ 459 KASSERT(sp->cbpp == sp->bpp + 1); 460 461 /* Free allocated segment summary */ 462 lfs_sb_suboffset(fs, lfs_btofsb(fs, lfs_sb_getsumsize(fs))); 463 bp = *sp->bpp; 464 lfs_freebuf(fs, bp); 465 466 pool_put(&fs->lfs_bpppool, sp->bpp); 467 sp->bpp = NULL; 468 469 /* 470 * If we're not sync, we're done with sp, get rid of it. 471 * Otherwise, we keep a local copy around but free 472 * fs->lfs_sp so another process can use it (we have to 473 * wait but they don't have to wait for us). 474 */ 475 if (!sync) 476 pool_put(&fs->lfs_segpool, sp); 477 fs->lfs_sp = NULL; 478 479 /* 480 * If the I/O count is non-zero, sleep until it reaches zero. 481 * At the moment, the user's process hangs around so we can 482 * sleep. 483 */ 484 mutex_enter(&lfs_lock); 485 if (--fs->lfs_iocount <= 1) 486 wakeup(&fs->lfs_iocount); 487 mutex_exit(&lfs_lock); 488 489 /* 490 * If we're not checkpointing, we don't have to block 491 * other processes to wait for a synchronous write 492 * to complete. 493 */ 494 if (!ckp) { 495 LFS_ENTER_LOG("segunlock_std", __FILE__, __LINE__, 0, 0, curproc->p_pid); 496 497 mutex_enter(&lfs_lock); 498 --fs->lfs_seglock; 499 fs->lfs_lockpid = 0; 500 fs->lfs_locklwp = 0; 501 mutex_exit(&lfs_lock); 502 wakeup(&fs->lfs_seglock); 503 } 504 /* 505 * We let checkpoints happen asynchronously. That means 506 * that during recovery, we have to roll forward between 507 * the two segments described by the first and second 508 * superblocks to make sure that the checkpoint described 509 * by a superblock completed. 510 */ 511 mutex_enter(&lfs_lock); 512 while (ckp && sync && fs->lfs_iocount) { 513 (void)mtsleep(&fs->lfs_iocount, PRIBIO + 1, 514 "lfs_iocount", 0, &lfs_lock); 515 DLOG((DLOG_SEG, "sleeping on iocount %x == %d\n", fs, fs->lfs_iocount)); 516 } 517 while (sync && sp->seg_iocount) { 518 (void)mtsleep(&sp->seg_iocount, PRIBIO + 1, 519 "seg_iocount", 0, &lfs_lock); 520 DLOG((DLOG_SEG, "sleeping on iocount %x == %d\n", sp, sp->seg_iocount)); 521 } 522 mutex_exit(&lfs_lock); 523 if (sync) 524 pool_put(&fs->lfs_segpool, sp); 525 526 if (ckp) { 527 fs->lfs_nactive = 0; 528 /* If we *know* everything's on disk, write both sbs */ 529 /* XXX should wait for this one */ 530 if (sync) 531 lfs_writesuper(fs, lfs_sb_getsboff(fs, fs->lfs_activesb)); 532 lfs_writesuper(fs, lfs_sb_getsboff(fs, 1 - fs->lfs_activesb)); 533 if (!(fs->lfs_ivnode->v_mount->mnt_iflag & IMNT_UNMOUNT)) { 534 lfs_auto_segclean(fs); 535 /* If sync, we can clean the remainder too */ 536 if (sync) 537 lfs_auto_segclean(fs); 538 } 539 fs->lfs_activesb = 1 - fs->lfs_activesb; 540 541 LFS_ENTER_LOG("segunlock_ckp", __FILE__, __LINE__, 0, 0, curproc->p_pid); 542 543 mutex_enter(&lfs_lock); 544 --fs->lfs_seglock; 545 fs->lfs_lockpid = 0; 546 fs->lfs_locklwp = 0; 547 mutex_exit(&lfs_lock); 548 wakeup(&fs->lfs_seglock); 549 } 550 /* Reenable fragment size changes */ 551 rw_exit(&fs->lfs_fraglock); 552 if (do_unmark_dirop) 553 lfs_unmark_dirop(fs); 554 } else { 555 --fs->lfs_seglock; 556 KASSERT(fs->lfs_seglock != 0); 557 mutex_exit(&lfs_lock); 558 } 559} 560 561/* 562 * Drain dirops and start writer. 563 * 564 * No simple_locks are held when we enter and none are held when we return. 565 */ 566void 567lfs_writer_enter(struct lfs *fs, const char *wmesg) 568{ 569 int error __diagused; 570 571 ASSERT_NO_SEGLOCK(fs); 572 mutex_enter(&lfs_lock); 573 574 /* disallow dirops during flush */ 575 fs->lfs_writer++; 576 577 while (fs->lfs_dirops > 0) { 578 ++fs->lfs_diropwait; 579 error = mtsleep(&fs->lfs_writer, PRIBIO+1, wmesg, 0, 580 &lfs_lock); 581 KASSERT(error == 0); 582 --fs->lfs_diropwait; 583 } 584 585 mutex_exit(&lfs_lock); 586} 587 588int 589lfs_writer_tryenter(struct lfs *fs) 590{ 591 int writer_set; 592 593 ASSERT_MAYBE_SEGLOCK(fs); 594 mutex_enter(&lfs_lock); 595 writer_set = (fs->lfs_dirops == 0); 596 if (writer_set) 597 fs->lfs_writer++; 598 mutex_exit(&lfs_lock); 599 600 return writer_set; 601} 602 603void 604lfs_writer_leave(struct lfs *fs) 605{ 606 bool dowakeup; 607 608 ASSERT_MAYBE_SEGLOCK(fs); 609 mutex_enter(&lfs_lock); 610 dowakeup = !(--fs->lfs_writer); 611 if (dowakeup) 612 cv_broadcast(&fs->lfs_diropscv); 613 mutex_exit(&lfs_lock); 614} 615 616/* 617 * Unlock, wait for the cleaner, then relock to where we were before. 618 * To be used only at a fairly high level, to address a paucity of free 619 * segments propagated back from lfs_gop_write(). 620 */ 621void 622lfs_segunlock_relock(struct lfs *fs) 623{ 624 int n = fs->lfs_seglock; 625 u_int16_t seg_flags; 626 CLEANERINFO *cip; 627 struct buf *bp; 628 629 if (n == 0) 630 return; 631 632 /* Write anything we've already gathered to disk */ 633 lfs_writeseg(fs, fs->lfs_sp); 634 635 /* Tell cleaner */ 636 LFS_CLEANERINFO(cip, fs, bp); 637 lfs_ci_setflags(fs, cip, 638 lfs_ci_getflags(fs, cip) | LFS_CLEANER_MUST_CLEAN); 639 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 640 641 /* Save segment flags for later */ 642 seg_flags = fs->lfs_sp->seg_flags; 643 644 fs->lfs_sp->seg_flags |= SEGM_PROT; /* Don't unmark dirop nodes */ 645 while(fs->lfs_seglock) 646 lfs_segunlock(fs); 647 648 /* Wait for the cleaner */ 649 lfs_wakeup_cleaner(fs); 650 mutex_enter(&lfs_lock); 651 while (LFS_STARVED_FOR_SEGS(fs)) 652 mtsleep(&fs->lfs_availsleep, PRIBIO, "relock", 0, 653 &lfs_lock); 654 mutex_exit(&lfs_lock); 655 656 /* Put the segment lock back the way it was. */ 657 while(n--) 658 lfs_seglock(fs, seg_flags); 659 660 /* Cleaner can relax now */ 661 LFS_CLEANERINFO(cip, fs, bp); 662 lfs_ci_setflags(fs, cip, 663 lfs_ci_getflags(fs, cip) & ~LFS_CLEANER_MUST_CLEAN); 664 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 665 666 return; 667} 668 669/* 670 * Wake up the cleaner, provided that nowrap is not set. 671 */ 672void 673lfs_wakeup_cleaner(struct lfs *fs) 674{ 675 if (fs->lfs_nowrap > 0) 676 return; 677 678 cv_broadcast(&fs->lfs_nextsegsleep); 679 cv_broadcast(&lfs_allclean_wakeup); 680} 681