xref: /csrg-svn/sys/ufs/lfs/lfs_bio.c (revision 56865)
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