Commit | Line | Data |
---|---|---|
8c6ec179 | 1 | /* |
ad0f93d2 KB |
2 | * Copyright (c) 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
8c6ec179 KB |
4 | * |
5 | * %sccs.include.redist.c% | |
6 | * | |
89e2bb79 | 7 | * @(#)lfs_bio.c 8.5 (Berkeley) %G% |
8c6ec179 KB |
8 | */ |
9 | ||
a5219e6e KB |
10 | #include <sys/param.h> |
11 | #include <sys/proc.h> | |
12 | #include <sys/buf.h> | |
5c5f0f67 | 13 | #include <sys/vnode.h> |
a5219e6e | 14 | #include <sys/resourcevar.h> |
5c5f0f67 | 15 | #include <sys/mount.h> |
1e0be126 | 16 | #include <sys/kernel.h> |
5c5f0f67 KB |
17 | |
18 | #include <ufs/ufs/quota.h> | |
19 | #include <ufs/ufs/inode.h> | |
20 | #include <ufs/ufs/ufsmount.h> | |
a5219e6e | 21 | |
785154a8 KB |
22 | #include <ufs/lfs/lfs.h> |
23 | #include <ufs/lfs/lfs_extern.h> | |
8c6ec179 | 24 | |
5c5f0f67 KB |
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 | */ | |
9e867303 | 32 | int lfs_allclean_wakeup; /* Cleaner wakeup address. */ |
5c5f0f67 | 33 | int locked_queue_count; /* XXX Count of locked-down buffers. */ |
edc34597 KB |
34 | int lfs_writing; /* Set if already kicked off a writer |
35 | because of buffer space */ | |
f5e3f593 | 36 | /* |
edc34597 KB |
37 | #define WRITE_THRESHHOLD ((nbuf >> 2) - 10) |
38 | #define WAIT_THRESHHOLD ((nbuf >> 1) - 10) | |
f5e3f593 MS |
39 | */ |
40 | #define WAIT_THRESHHOLD (nbuf - (nbuf >> 2) - 10) | |
41 | #define WRITE_THRESHHOLD ((nbuf >> 1) - 10) | |
1e0be126 | 42 | #define LFS_BUFWAIT 2 |
5c5f0f67 | 43 | |
a5219e6e | 44 | int |
9e673f96 KM |
45 | lfs_bwrite(ap) |
46 | struct vop_bwrite_args /* { | |
47 | struct buf *a_bp; | |
48 | } */ *ap; | |
8c6ec179 | 49 | { |
406c9a0d | 50 | register struct buf *bp = ap->a_bp; |
edc34597 KB |
51 | struct lfs *fs; |
52 | struct inode *ip; | |
1e0be126 | 53 | int error, s; |
fa870596 | 54 | |
9a1dcf8a | 55 | /* |
5c5f0f67 KB |
56 | * Set the delayed write flag and use reassignbuf to move the buffer |
57 | * from the clean list to the dirty one. | |
9a1dcf8a | 58 | * |
5c5f0f67 KB |
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. | |
41ba8073 MS |
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. | |
9a1dcf8a | 68 | */ |
406c9a0d | 69 | if (!(bp->b_flags & B_LOCKED)) { |
edc34597 | 70 | fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; |
1e0be126 | 71 | while (!LFS_FITS(fs, fsbtodb(fs, 1)) && !IS_IFILE(bp) && |
41ba8073 | 72 | bp->b_lblkno > 0) { |
1e0be126 | 73 | /* Out of space, need cleaner to run */ |
9e867303 | 74 | wakeup(&lfs_allclean_wakeup); |
1e0be126 MS |
75 | if (error = tsleep(&fs->lfs_avail, PCATCH | PUSER, |
76 | "cleaner", NULL)) { | |
77 | brelse(bp); | |
78 | return (error); | |
79 | } | |
edc34597 KB |
80 | } |
81 | ip = VTOI((bp)->b_vp); | |
cf5ef508 | 82 | if (!(ip->i_flag & IN_MODIFIED)) |
edc34597 | 83 | ++fs->lfs_uinodes; |
cf5ef508 | 84 | ip->i_flag |= IN_CHANGE | IN_MODIFIED | IN_UPDATE; |
edc34597 | 85 | fs->lfs_avail -= fsbtodb(fs, 1); |
5c5f0f67 | 86 | ++locked_queue_count; |
406c9a0d | 87 | bp->b_flags |= B_DELWRI | B_LOCKED; |
edc34597 | 88 | bp->b_flags &= ~(B_READ | B_ERROR); |
9f1a72f3 | 89 | s = splbio(); |
406c9a0d | 90 | reassignbuf(bp, bp->b_vp); |
9f1a72f3 CS |
91 | splx(s); |
92 | } | |
406c9a0d | 93 | brelse(bp); |
a5219e6e | 94 | return (0); |
8c6ec179 | 95 | } |
5c5f0f67 KB |
96 | |
97 | /* | |
98 | * XXX | |
99 | * This routine flushes buffers out of the B_LOCKED queue when LFS has too | |
100 | * many locked down. Eventually the pageout daemon will simply call LFS | |
b9258e30 KB |
101 | * when pages need to be reclaimed. Note, we have one static count of locked |
102 | * buffers, so we can't have more than a single file system. To make this | |
103 | * work for multiple file systems, put the count into the mount structure. | |
5c5f0f67 KB |
104 | */ |
105 | void | |
106 | lfs_flush() | |
107 | { | |
108 | register struct mount *mp; | |
5c5f0f67 | 109 | |
f5e3f593 MS |
110 | #ifdef DOSTATS |
111 | ++lfs_stats.write_exceeded; | |
112 | #endif | |
edc34597 | 113 | if (lfs_writing) |
5c5f0f67 | 114 | return; |
edc34597 | 115 | lfs_writing = 1; |
b740ac27 | 116 | for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { |
edc34597 | 117 | /* The lock check below is to avoid races with unmount. */ |
5c5f0f67 | 118 | if (mp->mnt_stat.f_type == MOUNT_LFS && |
edc34597 KB |
119 | (mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_UNMOUNT)) == 0 && |
120 | !((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) { | |
b3cee2e6 KB |
121 | /* |
122 | * We set the queue to 0 here because we are about to | |
123 | * write all the dirty buffers we have. If more come | |
124 | * in while we're writing the segment, they may not | |
125 | * get written, so we want the count to reflect these | |
126 | * new writes after the segwrite completes. | |
127 | */ | |
f5e3f593 MS |
128 | #ifdef DOSTATS |
129 | ++lfs_stats.flush_invoked; | |
130 | #endif | |
5c5f0f67 | 131 | lfs_segwrite(mp, 0); |
edc34597 | 132 | } |
b740ac27 | 133 | } |
edc34597 KB |
134 | lfs_writing = 0; |
135 | } | |
136 | ||
137 | int | |
138 | lfs_check(vp, blkno) | |
139 | struct vnode *vp; | |
89e2bb79 | 140 | ufs_daddr_t blkno; |
edc34597 KB |
141 | { |
142 | extern int lfs_allclean_wakeup; | |
143 | int error; | |
144 | ||
1e0be126 | 145 | error = 0; |
edc34597 KB |
146 | if (incore(vp, blkno)) |
147 | return (0); | |
148 | if (locked_queue_count > WRITE_THRESHHOLD) | |
149 | lfs_flush(); | |
1e0be126 MS |
150 | |
151 | /* If out of buffers, wait on writer */ | |
f5e3f593 MS |
152 | while (locked_queue_count > WAIT_THRESHHOLD) { |
153 | #ifdef DOSTATS | |
154 | ++lfs_stats.wait_exceeded; | |
155 | #endif | |
1e0be126 MS |
156 | error = tsleep(&locked_queue_count, PCATCH | PUSER, "buffers", |
157 | hz * LFS_BUFWAIT); | |
f5e3f593 | 158 | } |
1e0be126 | 159 | |
edc34597 | 160 | return (error); |
5c5f0f67 | 161 | } |