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