1 /* 2 * Copyright (c) 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_bio.c 7.18 (Berkeley) 11/17/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/proc.h> 12 #include <sys/buf.h> 13 #include <sys/vnode.h> 14 #include <sys/resourcevar.h> 15 #include <sys/mount.h> 16 #include <sys/kernel.h> 17 18 #include <ufs/ufs/quota.h> 19 #include <ufs/ufs/inode.h> 20 #include <ufs/ufs/ufsmount.h> 21 22 #include <ufs/lfs/lfs.h> 23 #include <ufs/lfs/lfs_extern.h> 24 25 /* 26 * LFS block write function. 27 * 28 * XXX 29 * No write cost accounting is done. 30 * This is almost certainly wrong for synchronous operations and NFS. 31 */ 32 int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 33 int locked_queue_count; /* XXX Count of locked-down buffers. */ 34 int lfs_writing; /* Set if already kicked off a writer 35 because of buffer space */ 36 #define WRITE_THRESHHOLD ((nbuf >> 2) - 10) 37 #define WAIT_THRESHHOLD ((nbuf >> 1) - 10) 38 #define LFS_BUFWAIT 2 39 40 int 41 lfs_bwrite(ap) 42 struct vop_bwrite_args /* { 43 struct buf *a_bp; 44 } */ *ap; 45 { 46 register struct buf *bp = ap->a_bp; 47 struct lfs *fs; 48 struct inode *ip; 49 int error, s; 50 51 /* 52 * Set the delayed write flag and use reassignbuf to move the buffer 53 * from the clean list to the dirty one. 54 * 55 * Set the B_LOCKED flag and unlock the buffer, causing brelse to move 56 * the buffer onto the LOCKED free list. This is necessary, otherwise 57 * getnewbuf() would try to reclaim the buffers using bawrite, which 58 * isn't going to work. 59 * 60 * XXX we don't let meta-data writes run out of space because they can 61 * come from the segment writer. We need to make sure that there is 62 * enough space reserved so that there's room to write meta-data 63 * blocks. 64 */ 65 if (!(bp->b_flags & B_LOCKED)) { 66 fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 67 while (!LFS_FITS(fs, fsbtodb(fs, 1)) && !IS_IFILE(bp) && 68 bp->b_lblkno > 0) { 69 /* Out of space, need cleaner to run */ 70 wakeup(&lfs_allclean_wakeup); 71 if (error = tsleep(&fs->lfs_avail, PCATCH | PUSER, 72 "cleaner", NULL)) { 73 brelse(bp); 74 return (error); 75 } 76 } 77 ip = VTOI((bp)->b_vp); 78 if (!(ip->i_flag & IMOD)) 79 ++fs->lfs_uinodes; 80 ip->i_flag |= IMOD | ICHG | IUPD; \ 81 fs->lfs_avail -= fsbtodb(fs, 1); 82 ++locked_queue_count; 83 bp->b_flags |= B_DELWRI | B_LOCKED; 84 bp->b_flags &= ~(B_READ | B_ERROR); 85 s = splbio(); 86 reassignbuf(bp, bp->b_vp); 87 splx(s); 88 } 89 brelse(bp); 90 return (0); 91 } 92 93 /* 94 * XXX 95 * This routine flushes buffers out of the B_LOCKED queue when LFS has too 96 * many locked down. Eventually the pageout daemon will simply call LFS 97 * when pages need to be reclaimed. Note, we have one static count of locked 98 * buffers, so we can't have more than a single file system. To make this 99 * work for multiple file systems, put the count into the mount structure. 100 */ 101 void 102 lfs_flush() 103 { 104 register struct mount *mp; 105 106 if (lfs_writing) 107 return; 108 lfs_writing = 1; 109 mp = rootfs; 110 do { 111 /* The lock check below is to avoid races with unmount. */ 112 if (mp->mnt_stat.f_type == MOUNT_LFS && 113 (mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_UNMOUNT)) == 0 && 114 !((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) { 115 /* 116 * We set the queue to 0 here because we are about to 117 * write all the dirty buffers we have. If more come 118 * in while we're writing the segment, they may not 119 * get written, so we want the count to reflect these 120 * new writes after the segwrite completes. 121 */ 122 lfs_segwrite(mp, 0); 123 } 124 mp = mp->mnt_next; 125 } while (mp != rootfs); 126 lfs_writing = 0; 127 } 128 129 int 130 lfs_check(vp, blkno) 131 struct vnode *vp; 132 daddr_t blkno; 133 { 134 extern int lfs_allclean_wakeup; 135 int error; 136 137 error = 0; 138 if (incore(vp, blkno)) 139 return (0); 140 if (locked_queue_count > WRITE_THRESHHOLD) 141 lfs_flush(); 142 143 /* If out of buffers, wait on writer */ 144 while (locked_queue_count > WAIT_THRESHHOLD) 145 error = tsleep(&locked_queue_count, PCATCH | PUSER, "buffers", 146 hz * LFS_BUFWAIT); 147 148 return (error); 149 } 150