lfs_subr.c revision 1.78
1/* $NetBSD: lfs_subr.c,v 1.78 2013/06/06 00:44:40 dholland 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.78 2013/06/06 00:44:40 dholland 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_extern.h> 78 79#include <uvm/uvm.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 = (res_t *)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 = fs->lfs_sumsize; 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 = fs->lfs_bsize; 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 maxbpp = ((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / sizeof(int32_t) + 2); 147 maxbpp = MIN(maxbpp, segsize(fs) / fs->lfs_fsize + 2); 148 pool_init(&fs->lfs_bpppool, maxbpp * sizeof(struct buf *), 0, 0, 0, 149 "lfsbpppl", &pool_allocator_nointr, IPL_NONE); 150} 151 152void 153lfs_free_resblks(struct lfs *fs) 154{ 155 int i; 156 157 pool_destroy(&fs->lfs_bpppool); 158 pool_destroy(&fs->lfs_segpool); 159 pool_destroy(&fs->lfs_clpool); 160 161 mutex_enter(&lfs_lock); 162 for (i = 0; i < LFS_N_TOTAL; i++) { 163 while (fs->lfs_resblk[i].inuse) 164 mtsleep(&fs->lfs_resblk, PRIBIO + 1, "lfs_free", 0, 165 &lfs_lock); 166 if (fs->lfs_resblk[i].p != NULL) 167 free(fs->lfs_resblk[i].p, M_SEGMENT); 168 } 169 free(fs->lfs_resblk, M_SEGMENT); 170 mutex_exit(&lfs_lock); 171} 172 173static unsigned int 174lfs_mhash(void *vp) 175{ 176 return (unsigned int)(((unsigned long)vp) >> 2) % LFS_RESHASH_WIDTH; 177} 178 179/* 180 * Return memory of the given size for the given purpose, or use one of a 181 * number of spare last-resort buffers, if malloc returns NULL. 182 */ 183void * 184lfs_malloc(struct lfs *fs, size_t size, int type) 185{ 186 struct lfs_res_blk *re; 187 void *r; 188 int i, s, start; 189 unsigned int h; 190 191 ASSERT_MAYBE_SEGLOCK(fs); 192 r = NULL; 193 194 /* If no mem allocated for this type, it just waits */ 195 if (lfs_res_qty[type] == 0) { 196 r = malloc(size, M_SEGMENT, M_WAITOK); 197 return r; 198 } 199 200 /* Otherwise try a quick malloc, and if it works, great */ 201 if ((r = malloc(size, M_SEGMENT, M_NOWAIT)) != NULL) { 202 return r; 203 } 204 205 /* 206 * If malloc returned NULL, we are forced to use one of our 207 * reserve blocks. We have on hand at least one summary block, 208 * at least one cluster block, at least one superblock, 209 * and several indirect blocks. 210 */ 211 212 mutex_enter(&lfs_lock); 213 /* skip over blocks of other types */ 214 for (i = 0, start = 0; i < type; i++) 215 start += lfs_res_qty[i]; 216 while (r == NULL) { 217 for (i = 0; i < lfs_res_qty[type]; i++) { 218 if (fs->lfs_resblk[start + i].inuse == 0) { 219 re = fs->lfs_resblk + start + i; 220 re->inuse = 1; 221 r = re->p; 222 KASSERT(re->size >= size); 223 h = lfs_mhash(r); 224 s = splbio(); 225 LIST_INSERT_HEAD(&fs->lfs_reshash[h], re, res); 226 splx(s); 227 mutex_exit(&lfs_lock); 228 return r; 229 } 230 } 231 DLOG((DLOG_MALLOC, "sleeping on %s (%d)\n", 232 lfs_res_names[type], lfs_res_qty[type])); 233 mtsleep(&fs->lfs_resblk, PVM, "lfs_malloc", 0, 234 &lfs_lock); 235 DLOG((DLOG_MALLOC, "done sleeping on %s\n", 236 lfs_res_names[type])); 237 } 238 /* NOTREACHED */ 239 mutex_exit(&lfs_lock); 240 return r; 241} 242 243void 244lfs_free(struct lfs *fs, void *p, int type) 245{ 246 int s; 247 unsigned int h; 248 res_t *re; 249#ifdef DEBUG 250 int i; 251#endif 252 253 ASSERT_MAYBE_SEGLOCK(fs); 254 h = lfs_mhash(p); 255 mutex_enter(&lfs_lock); 256 s = splbio(); 257 LIST_FOREACH(re, &fs->lfs_reshash[h], res) { 258 if (re->p == p) { 259 KASSERT(re->inuse == 1); 260 LIST_REMOVE(re, res); 261 re->inuse = 0; 262 wakeup(&fs->lfs_resblk); 263 splx(s); 264 mutex_exit(&lfs_lock); 265 return; 266 } 267 } 268#ifdef DEBUG 269 for (i = 0; i < LFS_N_TOTAL; i++) { 270 if (fs->lfs_resblk[i].p == p) 271 panic("lfs_free: inconsistent reserved block"); 272 } 273#endif 274 splx(s); 275 mutex_exit(&lfs_lock); 276 277 /* 278 * If we didn't find it, free it. 279 */ 280 free(p, M_SEGMENT); 281} 282 283/* 284 * lfs_seglock -- 285 * Single thread the segment writer. 286 */ 287int 288lfs_seglock(struct lfs *fs, unsigned long flags) 289{ 290 struct segment *sp; 291 292 mutex_enter(&lfs_lock); 293 if (fs->lfs_seglock) { 294 if (fs->lfs_lockpid == curproc->p_pid && 295 fs->lfs_locklwp == curlwp->l_lid) { 296 ++fs->lfs_seglock; 297 fs->lfs_sp->seg_flags |= flags; 298 mutex_exit(&lfs_lock); 299 return 0; 300 } else if (flags & SEGM_PAGEDAEMON) { 301 mutex_exit(&lfs_lock); 302 return EWOULDBLOCK; 303 } else { 304 while (fs->lfs_seglock) { 305 (void)mtsleep(&fs->lfs_seglock, PRIBIO + 1, 306 "lfs_seglock", 0, &lfs_lock); 307 } 308 } 309 } 310 311 fs->lfs_seglock = 1; 312 fs->lfs_lockpid = curproc->p_pid; 313 fs->lfs_locklwp = curlwp->l_lid; 314 mutex_exit(&lfs_lock); 315 fs->lfs_cleanind = 0; 316 317#ifdef DEBUG 318 LFS_ENTER_LOG("seglock", __FILE__, __LINE__, 0, flags, curproc->p_pid); 319#endif 320 /* Drain fragment size changes out */ 321 rw_enter(&fs->lfs_fraglock, RW_WRITER); 322 323 sp = fs->lfs_sp = pool_get(&fs->lfs_segpool, PR_WAITOK); 324 sp->bpp = pool_get(&fs->lfs_bpppool, PR_WAITOK); 325 sp->seg_flags = flags; 326 sp->vp = NULL; 327 sp->seg_iocount = 0; 328 (void) lfs_initseg(fs); 329 330 /* 331 * Keep a cumulative count of the outstanding I/O operations. If the 332 * disk drive catches up with us it could go to zero before we finish, 333 * so we artificially increment it by one until we've scheduled all of 334 * the writes we intend to do. 335 */ 336 mutex_enter(&lfs_lock); 337 ++fs->lfs_iocount; 338 fs->lfs_startseg = fs->lfs_curseg; 339 mutex_exit(&lfs_lock); 340 return 0; 341} 342 343static void lfs_unmark_dirop(struct lfs *); 344 345static void 346lfs_unmark_dirop(struct lfs *fs) 347{ 348 struct inode *ip, *nip; 349 struct vnode *vp; 350 int doit; 351 352 ASSERT_NO_SEGLOCK(fs); 353 mutex_enter(&lfs_lock); 354 doit = !(fs->lfs_flags & LFS_UNDIROP); 355 if (doit) 356 fs->lfs_flags |= LFS_UNDIROP; 357 if (!doit) { 358 mutex_exit(&lfs_lock); 359 return; 360 } 361 362 for (ip = TAILQ_FIRST(&fs->lfs_dchainhd); ip != NULL; ip = nip) { 363 nip = TAILQ_NEXT(ip, i_lfs_dchain); 364 vp = ITOV(ip); 365 if ((ip->i_flag & (IN_ADIROP | IN_CDIROP)) == IN_CDIROP) { 366 --lfs_dirvcount; 367 --fs->lfs_dirvcount; 368 vp->v_uflag &= ~VU_DIROP; 369 TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain); 370 wakeup(&lfs_dirvcount); 371 fs->lfs_unlockvp = vp; 372 mutex_exit(&lfs_lock); 373 vrele(vp); 374 mutex_enter(&lfs_lock); 375 fs->lfs_unlockvp = NULL; 376 ip->i_flag &= ~IN_CDIROP; 377 } 378 } 379 380 fs->lfs_flags &= ~LFS_UNDIROP; 381 wakeup(&fs->lfs_flags); 382 mutex_exit(&lfs_lock); 383} 384 385static void 386lfs_auto_segclean(struct lfs *fs) 387{ 388 int i, error, s, waited; 389 390 ASSERT_SEGLOCK(fs); 391 /* 392 * Now that we've swapped lfs_activesb, but while we still 393 * hold the segment lock, run through the segment list marking 394 * the empty ones clean. 395 * XXX - do we really need to do them all at once? 396 */ 397 waited = 0; 398 for (i = 0; i < fs->lfs_nseg; i++) { 399 if ((fs->lfs_suflags[0][i] & 400 (SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) == 401 (SEGUSE_DIRTY | SEGUSE_EMPTY) && 402 (fs->lfs_suflags[1][i] & 403 (SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) == 404 (SEGUSE_DIRTY | SEGUSE_EMPTY)) { 405 406 /* Make sure the sb is written before we clean */ 407 mutex_enter(&lfs_lock); 408 s = splbio(); 409 while (waited == 0 && fs->lfs_sbactive) 410 mtsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs asb", 411 0, &lfs_lock); 412 splx(s); 413 mutex_exit(&lfs_lock); 414 waited = 1; 415 416 if ((error = lfs_do_segclean(fs, i)) != 0) { 417 DLOG((DLOG_CLEAN, "lfs_auto_segclean: lfs_do_segclean returned %d for seg %d\n", error, i)); 418 } 419 } 420 fs->lfs_suflags[1 - fs->lfs_activesb][i] = 421 fs->lfs_suflags[fs->lfs_activesb][i]; 422 } 423} 424 425/* 426 * lfs_segunlock -- 427 * Single thread the segment writer. 428 */ 429void 430lfs_segunlock(struct lfs *fs) 431{ 432 struct segment *sp; 433 unsigned long sync, ckp; 434 struct buf *bp; 435 int do_unmark_dirop = 0; 436 437 sp = fs->lfs_sp; 438 439 mutex_enter(&lfs_lock); 440 KASSERT(LFS_SEGLOCK_HELD(fs)); 441 if (fs->lfs_seglock == 1) { 442 if ((sp->seg_flags & (SEGM_PROT | SEGM_CLEAN)) == 0) 443 do_unmark_dirop = 1; 444 mutex_exit(&lfs_lock); 445 sync = sp->seg_flags & SEGM_SYNC; 446 ckp = sp->seg_flags & SEGM_CKP; 447 448 /* We should have a segment summary, and nothing else */ 449 KASSERT(sp->cbpp == sp->bpp + 1); 450 451 /* Free allocated segment summary */ 452 fs->lfs_offset -= btofsb(fs, fs->lfs_sumsize); 453 bp = *sp->bpp; 454 lfs_freebuf(fs, bp); 455 456 pool_put(&fs->lfs_bpppool, sp->bpp); 457 sp->bpp = NULL; 458 459 /* 460 * If we're not sync, we're done with sp, get rid of it. 461 * Otherwise, we keep a local copy around but free 462 * fs->lfs_sp so another process can use it (we have to 463 * wait but they don't have to wait for us). 464 */ 465 if (!sync) 466 pool_put(&fs->lfs_segpool, sp); 467 fs->lfs_sp = NULL; 468 469 /* 470 * If the I/O count is non-zero, sleep until it reaches zero. 471 * At the moment, the user's process hangs around so we can 472 * sleep. 473 */ 474 mutex_enter(&lfs_lock); 475 if (--fs->lfs_iocount == 0) { 476 LFS_DEBUG_COUNTLOCKED("lfs_segunlock"); 477 } 478 if (fs->lfs_iocount <= 1) 479 wakeup(&fs->lfs_iocount); 480 mutex_exit(&lfs_lock); 481 /* 482 * If we're not checkpointing, we don't have to block 483 * other processes to wait for a synchronous write 484 * to complete. 485 */ 486 if (!ckp) { 487#ifdef DEBUG 488 LFS_ENTER_LOG("segunlock_std", __FILE__, __LINE__, 0, 0, curproc->p_pid); 489#endif 490 mutex_enter(&lfs_lock); 491 --fs->lfs_seglock; 492 fs->lfs_lockpid = 0; 493 fs->lfs_locklwp = 0; 494 mutex_exit(&lfs_lock); 495 wakeup(&fs->lfs_seglock); 496 } 497 /* 498 * We let checkpoints happen asynchronously. That means 499 * that during recovery, we have to roll forward between 500 * the two segments described by the first and second 501 * superblocks to make sure that the checkpoint described 502 * by a superblock completed. 503 */ 504 mutex_enter(&lfs_lock); 505 while (ckp && sync && fs->lfs_iocount) { 506 (void)mtsleep(&fs->lfs_iocount, PRIBIO + 1, 507 "lfs_iocount", 0, &lfs_lock); 508 DLOG((DLOG_SEG, "sleeping on iocount %x == %d\n", fs, fs->lfs_iocount)); 509 } 510 while (sync && sp->seg_iocount) { 511 (void)mtsleep(&sp->seg_iocount, PRIBIO + 1, 512 "seg_iocount", 0, &lfs_lock); 513 DLOG((DLOG_SEG, "sleeping on iocount %x == %d\n", sp, sp->seg_iocount)); 514 } 515 mutex_exit(&lfs_lock); 516 if (sync) 517 pool_put(&fs->lfs_segpool, sp); 518 519 if (ckp) { 520 fs->lfs_nactive = 0; 521 /* If we *know* everything's on disk, write both sbs */ 522 /* XXX should wait for this one */ 523 if (sync) 524 lfs_writesuper(fs, fs->lfs_sboffs[fs->lfs_activesb]); 525 lfs_writesuper(fs, fs->lfs_sboffs[1 - fs->lfs_activesb]); 526 if (!(fs->lfs_ivnode->v_mount->mnt_iflag & IMNT_UNMOUNT)) { 527 lfs_auto_segclean(fs); 528 /* If sync, we can clean the remainder too */ 529 if (sync) 530 lfs_auto_segclean(fs); 531 } 532 fs->lfs_activesb = 1 - fs->lfs_activesb; 533#ifdef DEBUG 534 LFS_ENTER_LOG("segunlock_ckp", __FILE__, __LINE__, 0, 0, curproc->p_pid); 535#endif 536 mutex_enter(&lfs_lock); 537 --fs->lfs_seglock; 538 fs->lfs_lockpid = 0; 539 fs->lfs_locklwp = 0; 540 mutex_exit(&lfs_lock); 541 wakeup(&fs->lfs_seglock); 542 } 543 /* Reenable fragment size changes */ 544 rw_exit(&fs->lfs_fraglock); 545 if (do_unmark_dirop) 546 lfs_unmark_dirop(fs); 547 } else if (fs->lfs_seglock == 0) { 548 mutex_exit(&lfs_lock); 549 panic ("Seglock not held"); 550 } else { 551 --fs->lfs_seglock; 552 mutex_exit(&lfs_lock); 553 } 554} 555 556/* 557 * Drain dirops and start writer. 558 * 559 * No simple_locks are held when we enter and none are held when we return. 560 */ 561int 562lfs_writer_enter(struct lfs *fs, const char *wmesg) 563{ 564 int error = 0; 565 566 ASSERT_MAYBE_SEGLOCK(fs); 567 mutex_enter(&lfs_lock); 568 569 /* disallow dirops during flush */ 570 fs->lfs_writer++; 571 572 while (fs->lfs_dirops > 0) { 573 ++fs->lfs_diropwait; 574 error = mtsleep(&fs->lfs_writer, PRIBIO+1, wmesg, 0, 575 &lfs_lock); 576 --fs->lfs_diropwait; 577 } 578 579 if (error) 580 fs->lfs_writer--; 581 582 mutex_exit(&lfs_lock); 583 584 return error; 585} 586 587void 588lfs_writer_leave(struct lfs *fs) 589{ 590 bool dowakeup; 591 592 ASSERT_MAYBE_SEGLOCK(fs); 593 mutex_enter(&lfs_lock); 594 dowakeup = !(--fs->lfs_writer); 595 mutex_exit(&lfs_lock); 596 if (dowakeup) 597 wakeup(&fs->lfs_dirops); 598} 599 600/* 601 * Unlock, wait for the cleaner, then relock to where we were before. 602 * To be used only at a fairly high level, to address a paucity of free 603 * segments propagated back from lfs_gop_write(). 604 */ 605void 606lfs_segunlock_relock(struct lfs *fs) 607{ 608 int n = fs->lfs_seglock; 609 u_int16_t seg_flags; 610 CLEANERINFO *cip; 611 struct buf *bp; 612 613 if (n == 0) 614 return; 615 616 /* Write anything we've already gathered to disk */ 617 lfs_writeseg(fs, fs->lfs_sp); 618 619 /* Tell cleaner */ 620 LFS_CLEANERINFO(cip, fs, bp); 621 cip->flags |= LFS_CLEANER_MUST_CLEAN; 622 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 623 624 /* Save segment flags for later */ 625 seg_flags = fs->lfs_sp->seg_flags; 626 627 fs->lfs_sp->seg_flags |= SEGM_PROT; /* Don't unmark dirop nodes */ 628 while(fs->lfs_seglock) 629 lfs_segunlock(fs); 630 631 /* Wait for the cleaner */ 632 lfs_wakeup_cleaner(fs); 633 mutex_enter(&lfs_lock); 634 while (LFS_STARVED_FOR_SEGS(fs)) 635 mtsleep(&fs->lfs_avail, PRIBIO, "relock", 0, 636 &lfs_lock); 637 mutex_exit(&lfs_lock); 638 639 /* Put the segment lock back the way it was. */ 640 while(n--) 641 lfs_seglock(fs, seg_flags); 642 643 /* Cleaner can relax now */ 644 LFS_CLEANERINFO(cip, fs, bp); 645 cip->flags &= ~LFS_CLEANER_MUST_CLEAN; 646 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 647 648 return; 649} 650 651/* 652 * Wake up the cleaner, provided that nowrap is not set. 653 */ 654void 655lfs_wakeup_cleaner(struct lfs *fs) 656{ 657 if (fs->lfs_nowrap > 0) 658 return; 659 660 wakeup(&fs->lfs_nextseg); 661 wakeup(&lfs_allclean_wakeup); 662} 663