Commit | Line | Data |
---|---|---|
8c6ec179 | 1 | /* |
785154a8 | 2 | * Copyright (c) 1991 Regents of the University of California. |
8c6ec179 KB |
3 | * All rights reserved. |
4 | * | |
5 | * %sccs.include.redist.c% | |
6 | * | |
1e0be126 | 7 | * @(#)lfs_bio.c 7.18 (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 */ | |
36 | #define WRITE_THRESHHOLD ((nbuf >> 2) - 10) | |
37 | #define WAIT_THRESHHOLD ((nbuf >> 1) - 10) | |
1e0be126 | 38 | #define LFS_BUFWAIT 2 |
5c5f0f67 | 39 | |
a5219e6e | 40 | int |
9e673f96 KM |
41 | lfs_bwrite(ap) |
42 | struct vop_bwrite_args /* { | |
43 | struct buf *a_bp; | |
44 | } */ *ap; | |
8c6ec179 | 45 | { |
406c9a0d | 46 | register struct buf *bp = ap->a_bp; |
edc34597 KB |
47 | struct lfs *fs; |
48 | struct inode *ip; | |
1e0be126 | 49 | int error, s; |
fa870596 | 50 | |
9a1dcf8a | 51 | /* |
5c5f0f67 KB |
52 | * Set the delayed write flag and use reassignbuf to move the buffer |
53 | * from the clean list to the dirty one. | |
9a1dcf8a | 54 | * |
5c5f0f67 KB |
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. | |
41ba8073 MS |
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. | |
9a1dcf8a | 64 | */ |
406c9a0d | 65 | if (!(bp->b_flags & B_LOCKED)) { |
edc34597 | 66 | fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; |
1e0be126 | 67 | while (!LFS_FITS(fs, fsbtodb(fs, 1)) && !IS_IFILE(bp) && |
41ba8073 | 68 | bp->b_lblkno > 0) { |
1e0be126 | 69 | /* Out of space, need cleaner to run */ |
9e867303 | 70 | wakeup(&lfs_allclean_wakeup); |
1e0be126 MS |
71 | if (error = tsleep(&fs->lfs_avail, PCATCH | PUSER, |
72 | "cleaner", NULL)) { | |
73 | brelse(bp); | |
74 | return (error); | |
75 | } | |
edc34597 KB |
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); | |
5c5f0f67 | 82 | ++locked_queue_count; |
406c9a0d | 83 | bp->b_flags |= B_DELWRI | B_LOCKED; |
edc34597 | 84 | bp->b_flags &= ~(B_READ | B_ERROR); |
9f1a72f3 | 85 | s = splbio(); |
406c9a0d | 86 | reassignbuf(bp, bp->b_vp); |
9f1a72f3 CS |
87 | splx(s); |
88 | } | |
406c9a0d | 89 | brelse(bp); |
a5219e6e | 90 | return (0); |
8c6ec179 | 91 | } |
5c5f0f67 KB |
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 | |
b9258e30 KB |
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. | |
5c5f0f67 KB |
100 | */ |
101 | void | |
102 | lfs_flush() | |
103 | { | |
104 | register struct mount *mp; | |
5c5f0f67 | 105 | |
edc34597 | 106 | if (lfs_writing) |
5c5f0f67 | 107 | return; |
edc34597 | 108 | lfs_writing = 1; |
5c5f0f67 KB |
109 | mp = rootfs; |
110 | do { | |
edc34597 | 111 | /* The lock check below is to avoid races with unmount. */ |
5c5f0f67 | 112 | if (mp->mnt_stat.f_type == MOUNT_LFS && |
edc34597 KB |
113 | (mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_UNMOUNT)) == 0 && |
114 | !((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) { | |
b3cee2e6 KB |
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 | */ | |
5c5f0f67 | 122 | lfs_segwrite(mp, 0); |
edc34597 KB |
123 | } |
124 | mp = mp->mnt_next; | |
5c5f0f67 | 125 | } while (mp != rootfs); |
edc34597 KB |
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 | ||
1e0be126 | 137 | error = 0; |
edc34597 KB |
138 | if (incore(vp, blkno)) |
139 | return (0); | |
140 | if (locked_queue_count > WRITE_THRESHHOLD) | |
141 | lfs_flush(); | |
1e0be126 MS |
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 | ||
edc34597 | 148 | return (error); |
5c5f0f67 | 149 | } |