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
lfs_bwrite(ap)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
lfs_flush()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
lfs_check(vp,blkno)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