1 /* 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_bio.c 8.10 (Berkeley) 06/10/95 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 /* 37 #define WRITE_THRESHHOLD ((nbuf >> 2) - 10) 38 #define WAIT_THRESHHOLD ((nbuf >> 1) - 10) 39 */ 40 #define WAIT_THRESHHOLD (nbuf - (nbuf >> 2) - 10) 41 #define WRITE_THRESHHOLD ((nbuf >> 1) - 10) 42 #define LFS_BUFWAIT 2 43 44 int 45 lfs_bwrite(ap) 46 struct vop_bwrite_args /* { 47 struct buf *a_bp; 48 } */ *ap; 49 { 50 register struct buf *bp = ap->a_bp; 51 struct lfs *fs; 52 struct inode *ip; 53 int db, error, s; 54 55 /* 56 * Set the delayed write flag and use reassignbuf to move the buffer 57 * from the clean list to the dirty one. 58 * 59 * Set the B_LOCKED flag and unlock the buffer, causing brelse to move 60 * the buffer onto the LOCKED free list. This is necessary, otherwise 61 * getnewbuf() would try to reclaim the buffers using bawrite, which 62 * isn't going to work. 63 * 64 * XXX we don't let meta-data writes run out of space because they can 65 * come from the segment writer. We need to make sure that there is 66 * enough space reserved so that there's room to write meta-data 67 * blocks. 68 */ 69 if (!(bp->b_flags & B_LOCKED)) { 70 fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 71 db = fragstodb(fs, numfrags(fs, bp->b_bcount)); 72 while (!LFS_FITS(fs, db) && !IS_IFILE(bp) && 73 bp->b_lblkno > 0) { 74 /* Out of space, need cleaner to run */ 75 wakeup(&lfs_allclean_wakeup); 76 wakeup(&fs->lfs_nextseg); 77 if (error = tsleep(&fs->lfs_avail, PCATCH | PUSER, 78 "cleaner", NULL)) { 79 brelse(bp); 80 return (error); 81 } 82 } 83 ip = VTOI((bp)->b_vp); 84 if (!(ip->i_flag & IN_MODIFIED)) 85 ++fs->lfs_uinodes; 86 ip->i_flag |= IN_CHANGE | IN_MODIFIED | IN_UPDATE; 87 fs->lfs_avail -= db; 88 ++locked_queue_count; 89 bp->b_flags |= B_DELWRI | B_LOCKED; 90 bp->b_flags &= ~(B_READ | B_ERROR); 91 s = splbio(); 92 reassignbuf(bp, bp->b_vp); 93 splx(s); 94 } 95 brelse(bp); 96 return (0); 97 } 98 99 /* 100 * XXX 101 * This routine flushes buffers out of the B_LOCKED queue when LFS has too 102 * many locked down. Eventually the pageout daemon will simply call LFS 103 * when pages need to be reclaimed. Note, we have one static count of locked 104 * buffers, so we can't have more than a single file system. To make this 105 * work for multiple file systems, put the count into the mount structure. 106 */ 107 void 108 lfs_flush() 109 { 110 register struct mount *mp, *nmp; 111 struct proc *p = curproc; /* XXX */ 112 113 #ifdef DOSTATS 114 ++lfs_stats.write_exceeded; 115 #endif 116 if (lfs_writing) 117 return; 118 lfs_writing = 1; 119 simple_lock(&mountlist_slock); 120 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 121 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 122 nmp = mp->mnt_list.cqe_next; 123 continue; 124 } 125 if (mp->mnt_stat.f_type == lfs_mount_type && 126 (mp->mnt_flag & MNT_RDONLY) == 0 && 127 !((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) { 128 /* 129 * We set the queue to 0 here because we are about to 130 * write all the dirty buffers we have. If more come 131 * in while we're writing the segment, they may not 132 * get written, so we want the count to reflect these 133 * new writes after the segwrite completes. 134 */ 135 #ifdef DOSTATS 136 ++lfs_stats.flush_invoked; 137 #endif 138 lfs_segwrite(mp, 0); 139 } 140 simple_lock(&mountlist_slock); 141 nmp = mp->mnt_list.cqe_next; 142 vfs_unbusy(mp, p); 143 } 144 simple_unlock(&mountlist_slock); 145 lfs_writing = 0; 146 } 147 148 int 149 lfs_check(vp, blkno) 150 struct vnode *vp; 151 ufs_daddr_t blkno; 152 { 153 extern int lfs_allclean_wakeup; 154 int error; 155 156 error = 0; 157 if (incore(vp, blkno)) 158 return (0); 159 if (locked_queue_count > WRITE_THRESHHOLD) 160 lfs_flush(); 161 162 /* If out of buffers, wait on writer */ 163 while (locked_queue_count > WAIT_THRESHHOLD) { 164 #ifdef DOSTATS 165 ++lfs_stats.wait_exceeded; 166 #endif 167 error = tsleep(&locked_queue_count, PCATCH | PUSER, "buffers", 168 hz * LFS_BUFWAIT); 169 } 170 171 return (error); 172 } 173