Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
7188ac27 KM |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
7188ac27 | 6 | * |
1c89915d | 7 | * @(#)vfs_bio.c 7.33 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
961945a8 | 9 | |
94368568 | 10 | #include "param.h" |
94368568 JB |
11 | #include "user.h" |
12 | #include "buf.h" | |
7188ac27 | 13 | #include "vnode.h" |
0f93ba7b | 14 | #include "specdev.h" |
edadbc2c | 15 | #include "mount.h" |
94368568 | 16 | #include "trace.h" |
a937f856 | 17 | #include "ucred.h" |
663dbc72 | 18 | |
663dbc72 | 19 | /* |
d42a4811 KM |
20 | * Find the block in the buffer pool. |
21 | * If the buffer is not present, allocate a new buffer and load | |
22 | * its contents according to the filesystem fill routine. | |
663dbc72 | 23 | */ |
a937f856 | 24 | bread(vp, blkno, size, cred, bpp) |
7188ac27 | 25 | struct vnode *vp; |
ad30fb67 KM |
26 | daddr_t blkno; |
27 | int size; | |
a937f856 | 28 | struct ucred *cred; |
7188ac27 | 29 | struct buf **bpp; |
ec67a3ce MK |
30 | #ifdef SECSIZE |
31 | long secsize; | |
32 | #endif SECSIZE | |
663dbc72 BJ |
33 | { |
34 | register struct buf *bp; | |
35 | ||
4f083fd7 SL |
36 | if (size == 0) |
37 | panic("bread: size 0"); | |
ec67a3ce MK |
38 | #ifdef SECSIZE |
39 | bp = getblk(dev, blkno, size, secsize); | |
40 | #else SECSIZE | |
7188ac27 | 41 | *bpp = bp = getblk(vp, blkno, size); |
ec67a3ce | 42 | #endif SECSIZE |
d42a4811 | 43 | if (bp->b_flags & (B_DONE | B_DELWRI)) { |
c5a600cf | 44 | trace(TR_BREADHIT, pack(vp, size), blkno); |
7188ac27 | 45 | return (0); |
663dbc72 BJ |
46 | } |
47 | bp->b_flags |= B_READ; | |
4f083fd7 SL |
48 | if (bp->b_bcount > bp->b_bufsize) |
49 | panic("bread"); | |
a937f856 KM |
50 | if (bp->b_rcred == NOCRED && cred != NOCRED) { |
51 | crhold(cred); | |
52 | bp->b_rcred = cred; | |
53 | } | |
7188ac27 | 54 | VOP_STRATEGY(bp); |
c5a600cf | 55 | trace(TR_BREADMISS, pack(vp, size), blkno); |
fb99a9a1 | 56 | u.u_ru.ru_inblock++; /* pay for read */ |
7188ac27 | 57 | return (biowait(bp)); |
663dbc72 BJ |
58 | } |
59 | ||
60 | /* | |
d42a4811 KM |
61 | * Operates like bread, but also starts I/O on the specified |
62 | * read-ahead block. | |
663dbc72 | 63 | */ |
a937f856 | 64 | breada(vp, blkno, size, rablkno, rabsize, cred, bpp) |
7188ac27 | 65 | struct vnode *vp; |
84baaab3 | 66 | daddr_t blkno; int size; |
ec67a3ce MK |
67 | #ifdef SECSIZE |
68 | long secsize; | |
69 | #endif SECSIZE | |
a8d3bf7f | 70 | daddr_t rablkno; int rabsize; |
a937f856 | 71 | struct ucred *cred; |
7188ac27 | 72 | struct buf **bpp; |
663dbc72 BJ |
73 | { |
74 | register struct buf *bp, *rabp; | |
75 | ||
76 | bp = NULL; | |
3efdd860 | 77 | /* |
d42a4811 KM |
78 | * If the block is not memory resident, |
79 | * allocate a buffer and start I/O. | |
3efdd860 | 80 | */ |
7188ac27 KM |
81 | if (!incore(vp, blkno)) { |
82 | *bpp = bp = getblk(vp, blkno, size); | |
ec67a3ce | 83 | #endif SECSIZE |
d42a4811 | 84 | if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) { |
663dbc72 | 85 | bp->b_flags |= B_READ; |
4f083fd7 SL |
86 | if (bp->b_bcount > bp->b_bufsize) |
87 | panic("breada"); | |
a937f856 KM |
88 | if (bp->b_rcred == NOCRED && cred != NOCRED) { |
89 | crhold(cred); | |
90 | bp->b_rcred = cred; | |
91 | } | |
7188ac27 | 92 | VOP_STRATEGY(bp); |
c5a600cf | 93 | trace(TR_BREADMISS, pack(vp, size), blkno); |
fb99a9a1 | 94 | u.u_ru.ru_inblock++; /* pay for read */ |
3efdd860 | 95 | } else |
c5a600cf | 96 | trace(TR_BREADHIT, pack(vp, size), blkno); |
663dbc72 | 97 | } |
3efdd860 KM |
98 | |
99 | /* | |
d42a4811 | 100 | * If there is a read-ahead block, start I/O on it too. |
3efdd860 | 101 | */ |
ee19707c | 102 | if (!incore(vp, rablkno)) { |
7188ac27 | 103 | rabp = getblk(vp, rablkno, rabsize); |
ec67a3ce | 104 | #endif SECSIZE |
d42a4811 | 105 | if (rabp->b_flags & (B_DONE | B_DELWRI)) { |
663dbc72 | 106 | brelse(rabp); |
c5a600cf | 107 | trace(TR_BREADHITRA, pack(vp, rabsize), rablkno); |
973ecc4f | 108 | } else { |
d42a4811 | 109 | rabp->b_flags |= B_ASYNC | B_READ; |
4f083fd7 SL |
110 | if (rabp->b_bcount > rabp->b_bufsize) |
111 | panic("breadrabp"); | |
5062ac4a | 112 | if (rabp->b_rcred == NOCRED && cred != NOCRED) { |
a937f856 | 113 | crhold(cred); |
5062ac4a | 114 | rabp->b_rcred = cred; |
a937f856 | 115 | } |
7188ac27 | 116 | VOP_STRATEGY(rabp); |
c5a600cf | 117 | trace(TR_BREADMISSRA, pack(vp, rabsize), rablkno); |
fb99a9a1 | 118 | u.u_ru.ru_inblock++; /* pay in advance */ |
663dbc72 BJ |
119 | } |
120 | } | |
3efdd860 KM |
121 | |
122 | /* | |
d42a4811 KM |
123 | * If block was memory resident, let bread get it. |
124 | * If block was not memory resident, the read was | |
125 | * started above, so just wait for the read to complete. | |
3efdd860 | 126 | */ |
84baaab3 | 127 | if (bp == NULL) |
ec67a3ce MK |
128 | #ifdef SECSIZE |
129 | return (bread(dev, blkno, size, secsize)); | |
130 | #else SECSIZE | |
a937f856 | 131 | return (bread(vp, blkno, size, cred, bpp)); |
7188ac27 | 132 | return (biowait(bp)); |
663dbc72 BJ |
133 | } |
134 | ||
135 | /* | |
d42a4811 KM |
136 | * Synchronous write. |
137 | * Release buffer on completion. | |
663dbc72 BJ |
138 | */ |
139 | bwrite(bp) | |
3efdd860 | 140 | register struct buf *bp; |
663dbc72 | 141 | { |
7188ac27 | 142 | register int flag; |
86e7dd3b | 143 | int s, error; |
663dbc72 BJ |
144 | |
145 | flag = bp->b_flags; | |
f844ee62 | 146 | bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); |
d42a4811 | 147 | if ((flag & B_DELWRI) == 0) |
fb99a9a1 | 148 | u.u_ru.ru_oublock++; /* noone paid yet */ |
c669f646 KM |
149 | else |
150 | reassignbuf(bp, bp->b_vp); | |
c5a600cf | 151 | trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno); |
4f083fd7 SL |
152 | if (bp->b_bcount > bp->b_bufsize) |
153 | panic("bwrite"); | |
86e7dd3b | 154 | s = splbio(); |
c669f646 | 155 | bp->b_vp->v_numoutput++; |
86e7dd3b | 156 | splx(s); |
7188ac27 | 157 | VOP_STRATEGY(bp); |
3efdd860 KM |
158 | |
159 | /* | |
d42a4811 | 160 | * If the write was synchronous, then await I/O completion. |
3efdd860 | 161 | * If the write was "delayed", then we put the buffer on |
d42a4811 | 162 | * the queue of blocks awaiting I/O completion status. |
3efdd860 | 163 | */ |
d42a4811 | 164 | if ((flag & B_ASYNC) == 0) { |
7188ac27 | 165 | error = biowait(bp); |
663dbc72 | 166 | brelse(bp); |
7188ac27 | 167 | } else if (flag & B_DELWRI) { |
663dbc72 | 168 | bp->b_flags |= B_AGE; |
7188ac27 KM |
169 | error = 0; |
170 | } | |
171 | return (error); | |
663dbc72 BJ |
172 | } |
173 | ||
174 | /* | |
d42a4811 KM |
175 | * Delayed write. |
176 | * | |
177 | * The buffer is marked dirty, but is not queued for I/O. | |
178 | * This routine should be used when the buffer is expected | |
179 | * to be modified again soon, typically a small write that | |
180 | * partially fills a buffer. | |
181 | * | |
182 | * NB: magnetic tapes cannot be delayed; they must be | |
183 | * written in the order that the writes are requested. | |
663dbc72 BJ |
184 | */ |
185 | bdwrite(bp) | |
3efdd860 | 186 | register struct buf *bp; |
663dbc72 | 187 | { |
663dbc72 | 188 | |
c669f646 KM |
189 | if ((bp->b_flags & B_DELWRI) == 0) { |
190 | bp->b_flags |= B_DELWRI; | |
191 | reassignbuf(bp, bp->b_vp); | |
fb99a9a1 | 192 | u.u_ru.ru_oublock++; /* noone paid yet */ |
c669f646 | 193 | } |
7188ac27 | 194 | /* |
edadbc2c | 195 | * If this is a tape drive, the write must be initiated. |
7188ac27 | 196 | */ |
ec67a3ce | 197 | if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE) |
663dbc72 | 198 | bawrite(bp); |
edadbc2c | 199 | } else { |
d42a4811 | 200 | bp->b_flags |= (B_DONE | B_DELWRI); |
663dbc72 BJ |
201 | brelse(bp); |
202 | } | |
203 | } | |
204 | ||
205 | /* | |
d42a4811 KM |
206 | * Asynchronous write. |
207 | * Start I/O on a buffer, but do not wait for it to complete. | |
208 | * The buffer is released when the I/O completes. | |
663dbc72 BJ |
209 | */ |
210 | bawrite(bp) | |
3efdd860 | 211 | register struct buf *bp; |
663dbc72 BJ |
212 | { |
213 | ||
d42a4811 KM |
214 | /* |
215 | * Setting the ASYNC flag causes bwrite to return | |
216 | * after starting the I/O. | |
217 | */ | |
663dbc72 | 218 | bp->b_flags |= B_ASYNC; |
7188ac27 | 219 | (void) bwrite(bp); |
663dbc72 BJ |
220 | } |
221 | ||
222 | /* | |
d42a4811 KM |
223 | * Release a buffer. |
224 | * Even if the buffer is dirty, no I/O is started. | |
663dbc72 BJ |
225 | */ |
226 | brelse(bp) | |
3efdd860 | 227 | register struct buf *bp; |
663dbc72 | 228 | { |
46387ee3 | 229 | register struct buf *flist; |
d42a4811 | 230 | int s; |
663dbc72 | 231 | |
c5a600cf | 232 | trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); |
3efdd860 | 233 | /* |
edadbc2c KM |
234 | * If a process is waiting for the buffer, or |
235 | * is waiting for a free buffer, awaken it. | |
3efdd860 | 236 | */ |
d42a4811 | 237 | if (bp->b_flags & B_WANTED) |
663dbc72 | 238 | wakeup((caddr_t)bp); |
d42a4811 | 239 | if (bfreelist[0].b_flags & B_WANTED) { |
46387ee3 BJ |
240 | bfreelist[0].b_flags &= ~B_WANTED; |
241 | wakeup((caddr_t)bfreelist); | |
663dbc72 | 242 | } |
edadbc2c KM |
243 | /* |
244 | * Retry I/O for locked buffers rather than invalidating them. | |
245 | */ | |
246 | if ((bp->b_flags & B_ERROR) && (bp->b_flags & B_LOCKED)) | |
247 | bp->b_flags &= ~B_ERROR; | |
edadbc2c KM |
248 | /* |
249 | * Disassociate buffers that are no longer valid. | |
250 | */ | |
d42a4811 | 251 | if (bp->b_flags & (B_NOCACHE | B_ERROR)) |
7188ac27 | 252 | bp->b_flags |= B_INVAL; |
d42a4811 | 253 | if ((bp->b_bufsize <= 0) || (bp->b_flags & (B_ERROR | B_INVAL))) { |
edadbc2c KM |
254 | if (bp->b_vp) |
255 | brelvp(bp); | |
256 | bp->b_flags &= ~B_DELWRI; | |
7188ac27 | 257 | } |
3efdd860 KM |
258 | /* |
259 | * Stick the buffer back on a free list. | |
260 | */ | |
a5e62f37 | 261 | s = splbio(); |
4f083fd7 SL |
262 | if (bp->b_bufsize <= 0) { |
263 | /* block has no buffer ... put at front of unused buffer list */ | |
264 | flist = &bfreelist[BQ_EMPTY]; | |
265 | binsheadfree(bp, flist); | |
d42a4811 | 266 | } else if (bp->b_flags & (B_ERROR | B_INVAL)) { |
46387ee3 | 267 | /* block has no info ... put at front of most free list */ |
4f083fd7 | 268 | flist = &bfreelist[BQ_AGE]; |
3efdd860 | 269 | binsheadfree(bp, flist); |
663dbc72 | 270 | } else { |
46387ee3 BJ |
271 | if (bp->b_flags & B_LOCKED) |
272 | flist = &bfreelist[BQ_LOCKED]; | |
273 | else if (bp->b_flags & B_AGE) | |
274 | flist = &bfreelist[BQ_AGE]; | |
275 | else | |
276 | flist = &bfreelist[BQ_LRU]; | |
3efdd860 | 277 | binstailfree(bp, flist); |
663dbc72 | 278 | } |
d42a4811 | 279 | bp->b_flags &= ~(B_WANTED | B_BUSY | B_ASYNC | B_AGE | B_NOCACHE); |
663dbc72 BJ |
280 | splx(s); |
281 | } | |
282 | ||
283 | /* | |
d42a4811 | 284 | * Check to see if a block is currently memory resident. |
663dbc72 | 285 | */ |
7188ac27 KM |
286 | incore(vp, blkno) |
287 | struct vnode *vp; | |
3efdd860 | 288 | daddr_t blkno; |
663dbc72 BJ |
289 | { |
290 | register struct buf *bp; | |
46387ee3 | 291 | register struct buf *dp; |
663dbc72 | 292 | |
243d4743 | 293 | dp = BUFHASH(vp, blkno); |
46387ee3 | 294 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) |
edadbc2c | 295 | if (bp->b_lblkno == blkno && bp->b_vp == vp && |
3efdd860 | 296 | (bp->b_flags & B_INVAL) == 0) |
5603d07d | 297 | return (1); |
5603d07d | 298 | return (0); |
663dbc72 BJ |
299 | } |
300 | ||
edadbc2c | 301 | /* |
d42a4811 KM |
302 | * Check to see if a block is currently memory resident. |
303 | * If it is resident, return it. If it is not resident, | |
304 | * allocate a new buffer and assign it to the block. | |
663dbc72 BJ |
305 | */ |
306 | struct buf * | |
ec67a3ce MK |
307 | #ifdef SECSIZE |
308 | getblk(dev, blkno, size, secsize) | |
309 | #else SECSIZE | |
7188ac27 KM |
310 | getblk(vp, blkno, size) |
311 | register struct vnode *vp; | |
ad30fb67 KM |
312 | daddr_t blkno; |
313 | int size; | |
ec67a3ce MK |
314 | #ifdef SECSIZE |
315 | long secsize; | |
316 | #endif SECSIZE | |
663dbc72 | 317 | { |
4f083fd7 | 318 | register struct buf *bp, *dp; |
23900030 | 319 | int s; |
663dbc72 | 320 | |
00a6a148 KM |
321 | if (size > MAXBSIZE) |
322 | panic("getblk: size too big"); | |
3efdd860 | 323 | /* |
d42a4811 KM |
324 | * Search the cache for the block. If the buffer is found, |
325 | * but it is currently locked, the we must wait for it to | |
326 | * become available. | |
3efdd860 | 327 | */ |
7188ac27 | 328 | dp = BUFHASH(vp, blkno); |
3efdd860 | 329 | loop: |
46387ee3 | 330 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { |
edadbc2c | 331 | if (bp->b_lblkno != blkno || bp->b_vp != vp || |
d42a4811 | 332 | (bp->b_flags & B_INVAL)) |
663dbc72 | 333 | continue; |
a5e62f37 | 334 | s = splbio(); |
d42a4811 | 335 | if (bp->b_flags & B_BUSY) { |
663dbc72 | 336 | bp->b_flags |= B_WANTED; |
d42a4811 | 337 | sleep((caddr_t)bp, PRIBIO + 1); |
23900030 | 338 | splx(s); |
663dbc72 BJ |
339 | goto loop; |
340 | } | |
c669f646 KM |
341 | bremfree(bp); |
342 | bp->b_flags |= B_BUSY; | |
23900030 | 343 | splx(s); |
32a56bda | 344 | if (bp->b_bcount != size) { |
edadbc2c KM |
345 | printf("getblk: stray size"); |
346 | bp->b_flags |= B_INVAL; | |
347 | bwrite(bp); | |
9d6d37ce | 348 | goto loop; |
edadbc2c | 349 | } |
663dbc72 | 350 | bp->b_flags |= B_CACHE; |
a5e62f37 | 351 | return (bp); |
663dbc72 | 352 | } |
4f083fd7 | 353 | bp = getnewbuf(); |
3efdd860 | 354 | bremhash(bp); |
edadbc2c | 355 | bgetvp(vp, bp); |
521a4688 | 356 | bp->b_bcount = 0; |
edadbc2c | 357 | bp->b_lblkno = blkno; |
ec67a3ce MK |
358 | #ifdef SECSIZE |
359 | bp->b_blksize = secsize; | |
360 | #endif SECSIZE | |
ad30fb67 | 361 | bp->b_blkno = blkno; |
4f083fd7 | 362 | bp->b_error = 0; |
7188ac27 KM |
363 | bp->b_resid = 0; |
364 | binshash(bp, dp); | |
521a4688 | 365 | allocbuf(bp, size); |
a5e62f37 | 366 | return (bp); |
663dbc72 BJ |
367 | } |
368 | ||
369 | /* | |
d42a4811 KM |
370 | * Allocate a buffer. |
371 | * The caller will assign it to a block. | |
663dbc72 BJ |
372 | */ |
373 | struct buf * | |
ad30fb67 KM |
374 | geteblk(size) |
375 | int size; | |
663dbc72 | 376 | { |
4f083fd7 | 377 | register struct buf *bp, *flist; |
663dbc72 | 378 | |
00a6a148 KM |
379 | if (size > MAXBSIZE) |
380 | panic("geteblk: size too big"); | |
4f083fd7 SL |
381 | bp = getnewbuf(); |
382 | bp->b_flags |= B_INVAL; | |
3efdd860 | 383 | bremhash(bp); |
4f083fd7 | 384 | flist = &bfreelist[BQ_AGE]; |
521a4688 | 385 | bp->b_bcount = 0; |
ec67a3ce MK |
386 | #ifdef SECSIZE |
387 | bp->b_blksize = DEV_BSIZE; | |
388 | #endif SECSIZE | |
4f083fd7 | 389 | bp->b_error = 0; |
7188ac27 KM |
390 | bp->b_resid = 0; |
391 | binshash(bp, flist); | |
521a4688 | 392 | allocbuf(bp, size); |
a5e62f37 | 393 | return (bp); |
663dbc72 BJ |
394 | } |
395 | ||
ad30fb67 | 396 | /* |
521a4688 | 397 | * Expand or contract the actual memory allocated to a buffer. |
d42a4811 | 398 | * If no memory is available, release buffer and take error exit. |
ad30fb67 | 399 | */ |
521a4688 KM |
400 | allocbuf(tp, size) |
401 | register struct buf *tp; | |
ad30fb67 KM |
402 | int size; |
403 | { | |
521a4688 KM |
404 | register struct buf *bp, *ep; |
405 | int sizealloc, take, s; | |
ad30fb67 | 406 | |
521a4688 KM |
407 | sizealloc = roundup(size, CLBYTES); |
408 | /* | |
409 | * Buffer size does not change | |
410 | */ | |
411 | if (sizealloc == tp->b_bufsize) | |
412 | goto out; | |
413 | /* | |
414 | * Buffer size is shrinking. | |
415 | * Place excess space in a buffer header taken from the | |
416 | * BQ_EMPTY buffer list and placed on the "most free" list. | |
417 | * If no extra buffer headers are available, leave the | |
418 | * extra space in the present buffer. | |
419 | */ | |
420 | if (sizealloc < tp->b_bufsize) { | |
421 | ep = bfreelist[BQ_EMPTY].av_forw; | |
422 | if (ep == &bfreelist[BQ_EMPTY]) | |
423 | goto out; | |
424 | s = splbio(); | |
425 | bremfree(ep); | |
426 | ep->b_flags |= B_BUSY; | |
427 | splx(s); | |
428 | pagemove(tp->b_un.b_addr + sizealloc, ep->b_un.b_addr, | |
429 | (int)tp->b_bufsize - sizealloc); | |
430 | ep->b_bufsize = tp->b_bufsize - sizealloc; | |
431 | tp->b_bufsize = sizealloc; | |
432 | ep->b_flags |= B_INVAL; | |
433 | ep->b_bcount = 0; | |
434 | brelse(ep); | |
435 | goto out; | |
436 | } | |
437 | /* | |
438 | * More buffer space is needed. Get it out of buffers on | |
439 | * the "most free" list, placing the empty headers on the | |
440 | * BQ_EMPTY buffer header list. | |
441 | */ | |
442 | while (tp->b_bufsize < sizealloc) { | |
443 | take = sizealloc - tp->b_bufsize; | |
444 | bp = getnewbuf(); | |
445 | if (take >= bp->b_bufsize) | |
446 | take = bp->b_bufsize; | |
447 | pagemove(&bp->b_un.b_addr[bp->b_bufsize - take], | |
448 | &tp->b_un.b_addr[tp->b_bufsize], take); | |
449 | tp->b_bufsize += take; | |
450 | bp->b_bufsize = bp->b_bufsize - take; | |
451 | if (bp->b_bcount > bp->b_bufsize) | |
452 | bp->b_bcount = bp->b_bufsize; | |
453 | if (bp->b_bufsize <= 0) { | |
454 | bremhash(bp); | |
455 | binshash(bp, &bfreelist[BQ_EMPTY]); | |
d42a4811 | 456 | bp->b_dev = NODEV; |
521a4688 KM |
457 | bp->b_error = 0; |
458 | bp->b_flags |= B_INVAL; | |
459 | } | |
460 | brelse(bp); | |
461 | } | |
462 | out: | |
463 | tp->b_bcount = size; | |
464 | return (1); | |
4f083fd7 SL |
465 | } |
466 | ||
4f083fd7 SL |
467 | /* |
468 | * Find a buffer which is available for use. | |
469 | * Select something from a free list. | |
470 | * Preference is to AGE list, then LRU list. | |
471 | */ | |
472 | struct buf * | |
473 | getnewbuf() | |
474 | { | |
475 | register struct buf *bp, *dp; | |
a937f856 | 476 | register struct ucred *cred; |
4f083fd7 SL |
477 | int s; |
478 | ||
479 | loop: | |
a5e62f37 | 480 | s = splbio(); |
4f083fd7 SL |
481 | for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) |
482 | if (dp->av_forw != dp) | |
483 | break; | |
484 | if (dp == bfreelist) { /* no free blocks */ | |
485 | dp->b_flags |= B_WANTED; | |
d42a4811 | 486 | sleep((caddr_t)dp, PRIBIO + 1); |
4b7d506c | 487 | splx(s); |
4f083fd7 SL |
488 | goto loop; |
489 | } | |
4f083fd7 | 490 | bp = dp->av_forw; |
c669f646 KM |
491 | bremfree(bp); |
492 | bp->b_flags |= B_BUSY; | |
493 | splx(s); | |
4f083fd7 | 494 | if (bp->b_flags & B_DELWRI) { |
033a786e | 495 | (void) bawrite(bp); |
4f083fd7 SL |
496 | goto loop; |
497 | } | |
c5a600cf | 498 | trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); |
edadbc2c KM |
499 | if (bp->b_vp) |
500 | brelvp(bp); | |
a937f856 KM |
501 | if (bp->b_rcred != NOCRED) { |
502 | cred = bp->b_rcred; | |
503 | bp->b_rcred = NOCRED; | |
504 | crfree(cred); | |
505 | } | |
506 | if (bp->b_wcred != NOCRED) { | |
507 | cred = bp->b_wcred; | |
508 | bp->b_wcred = NOCRED; | |
509 | crfree(cred); | |
510 | } | |
4f083fd7 | 511 | bp->b_flags = B_BUSY; |
1c89915d | 512 | bp->b_dirtyoff = bp->b_dirtyend = 0; |
4f083fd7 SL |
513 | return (bp); |
514 | } | |
515 | ||
663dbc72 | 516 | /* |
d42a4811 KM |
517 | * Wait for I/O to complete. |
518 | * | |
519 | * Extract and return any errors associated with the I/O. | |
520 | * If the error flag is set, but no specific error is | |
521 | * given, return EIO. | |
663dbc72 | 522 | */ |
3efdd860 | 523 | biowait(bp) |
ad30fb67 | 524 | register struct buf *bp; |
663dbc72 | 525 | { |
530d0032 | 526 | int s; |
663dbc72 | 527 | |
a5e62f37 | 528 | s = splbio(); |
a937f856 | 529 | while ((bp->b_flags & B_DONE) == 0) |
663dbc72 | 530 | sleep((caddr_t)bp, PRIBIO); |
530d0032 | 531 | splx(s); |
7188ac27 KM |
532 | if ((bp->b_flags & B_ERROR) == 0) |
533 | return (0); | |
534 | if (bp->b_error) | |
535 | return (bp->b_error); | |
536 | return (EIO); | |
663dbc72 BJ |
537 | } |
538 | ||
663dbc72 | 539 | /* |
af04ce66 | 540 | * Mark I/O complete on a buffer. |
d42a4811 KM |
541 | * |
542 | * If a callback has been requested, e.g. the pageout | |
543 | * daemon, do so. Otherwise, awaken waiting processes. | |
663dbc72 | 544 | */ |
3efdd860 KM |
545 | biodone(bp) |
546 | register struct buf *bp; | |
663dbc72 | 547 | { |
c669f646 | 548 | register struct vnode *vp; |
663dbc72 | 549 | |
80e7c811 | 550 | if (bp->b_flags & B_DONE) |
3efdd860 | 551 | panic("dup biodone"); |
663dbc72 | 552 | bp->b_flags |= B_DONE; |
c669f646 | 553 | if ((bp->b_flags & B_READ) == 0) { |
a937f856 | 554 | bp->b_dirtyoff = bp->b_dirtyend = 0; |
c669f646 KM |
555 | if (vp = bp->b_vp) { |
556 | vp->v_numoutput--; | |
557 | if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { | |
558 | if (vp->v_numoutput < 0) | |
559 | panic("biodone: neg numoutput"); | |
560 | vp->v_flag &= ~VBWAIT; | |
561 | wakeup((caddr_t)&vp->v_numoutput); | |
562 | } | |
563 | } | |
564 | } | |
961945a8 SL |
565 | if (bp->b_flags & B_CALL) { |
566 | bp->b_flags &= ~B_CALL; | |
567 | (*bp->b_iodone)(bp); | |
568 | return; | |
569 | } | |
d42a4811 | 570 | if (bp->b_flags & B_ASYNC) |
663dbc72 BJ |
571 | brelse(bp); |
572 | else { | |
573 | bp->b_flags &= ~B_WANTED; | |
574 | wakeup((caddr_t)bp); | |
575 | } | |
576 | } | |
577 | ||
663dbc72 | 578 | /* |
7188ac27 | 579 | * Make sure all write-behind blocks associated |
a937f856 | 580 | * with mount point are flushed out (from sync). |
663dbc72 | 581 | */ |
edadbc2c | 582 | mntflushbuf(mountp, flags) |
a937f856 | 583 | struct mount *mountp; |
edadbc2c | 584 | int flags; |
663dbc72 | 585 | { |
099798da | 586 | register struct vnode *vp; |
edadbc2c | 587 | |
54fb9dc2 | 588 | if ((mountp->mnt_flag & MNT_MPBUSY) == 0) |
17c2edaa | 589 | panic("mntflushbuf: not busy"); |
edadbc2c | 590 | loop: |
4597dd33 | 591 | for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { |
edadbc2c KM |
592 | if (vget(vp)) |
593 | goto loop; | |
594 | vflushbuf(vp, flags); | |
595 | vput(vp); | |
4597dd33 KM |
596 | if (vp->v_mount != mountp) |
597 | goto loop; | |
edadbc2c KM |
598 | } |
599 | } | |
600 | ||
601 | /* | |
602 | * Flush all dirty buffers associated with a vnode. | |
603 | */ | |
604 | vflushbuf(vp, flags) | |
605 | register struct vnode *vp; | |
606 | int flags; | |
607 | { | |
608 | register struct buf *bp; | |
609 | struct buf *nbp; | |
530d0032 | 610 | int s; |
663dbc72 BJ |
611 | |
612 | loop: | |
a5e62f37 | 613 | s = splbio(); |
c669f646 | 614 | for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { |
edadbc2c KM |
615 | nbp = bp->b_blockf; |
616 | if ((bp->b_flags & B_BUSY)) | |
617 | continue; | |
618 | if ((bp->b_flags & B_DELWRI) == 0) | |
c669f646 KM |
619 | panic("vflushbuf: not dirty"); |
620 | bremfree(bp); | |
621 | bp->b_flags |= B_BUSY; | |
edadbc2c | 622 | splx(s); |
c669f646 KM |
623 | /* |
624 | * Wait for I/O associated with indirect blocks to complete, | |
625 | * since there is no way to quickly wait for them below. | |
d42a4811 | 626 | * NB: This is really specific to ufs, but is done here |
c669f646 KM |
627 | * as it is easier and quicker. |
628 | */ | |
629 | if (bp->b_vp == vp || (flags & B_SYNC) == 0) { | |
630 | (void) bawrite(bp); | |
93d6e9b8 | 631 | s = splbio(); |
c669f646 KM |
632 | } else { |
633 | (void) bwrite(bp); | |
634 | goto loop; | |
635 | } | |
edadbc2c | 636 | } |
9c1dffd6 | 637 | splx(s); |
edadbc2c KM |
638 | if ((flags & B_SYNC) == 0) |
639 | return; | |
edadbc2c | 640 | s = splbio(); |
c669f646 KM |
641 | while (vp->v_numoutput) { |
642 | vp->v_flag |= VBWAIT; | |
d42a4811 | 643 | sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); |
7188ac27 | 644 | } |
9c1dffd6 | 645 | splx(s); |
c669f646 KM |
646 | if (vp->v_dirtyblkhd) { |
647 | vprint("vflushbuf: dirty", vp); | |
648 | goto loop; | |
649 | } | |
663dbc72 | 650 | } |
7b8b5a01 RE |
651 | |
652 | /* | |
653 | * Invalidate in core blocks belonging to closed or umounted filesystem | |
654 | * | |
edadbc2c KM |
655 | * Go through the list of vnodes associated with the file system; |
656 | * for each vnode invalidate any buffers that it holds. Normally | |
657 | * this routine is preceeded by a bflush call, so that on a quiescent | |
658 | * filesystem there will be no dirty buffers when we are done. Binval | |
659 | * returns the count of dirty buffers when it is finished. | |
7b8b5a01 | 660 | */ |
edadbc2c | 661 | mntinvalbuf(mountp) |
a937f856 | 662 | struct mount *mountp; |
7b8b5a01 | 663 | { |
099798da | 664 | register struct vnode *vp; |
edadbc2c KM |
665 | int dirty = 0; |
666 | ||
54fb9dc2 | 667 | if ((mountp->mnt_flag & MNT_MPBUSY) == 0) |
17c2edaa | 668 | panic("mntinvalbuf: not busy"); |
edadbc2c | 669 | loop: |
4597dd33 | 670 | for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { |
edadbc2c KM |
671 | if (vget(vp)) |
672 | goto loop; | |
673 | dirty += vinvalbuf(vp, 1); | |
674 | vput(vp); | |
4597dd33 KM |
675 | if (vp->v_mount != mountp) |
676 | goto loop; | |
edadbc2c KM |
677 | } |
678 | return (dirty); | |
679 | } | |
680 | ||
681 | /* | |
682 | * Flush out and invalidate all buffers associated with a vnode. | |
683 | * Called with the underlying object locked. | |
684 | */ | |
685 | vinvalbuf(vp, save) | |
686 | register struct vnode *vp; | |
687 | int save; | |
688 | { | |
689 | register struct buf *bp; | |
c669f646 | 690 | struct buf *nbp, *blist; |
1a24c701 | 691 | int s, dirty = 0; |
7b8b5a01 | 692 | |
c669f646 KM |
693 | for (;;) { |
694 | if (blist = vp->v_dirtyblkhd) | |
695 | /* void */; | |
696 | else if (blist = vp->v_cleanblkhd) | |
697 | /* void */; | |
698 | else | |
699 | break; | |
700 | for (bp = blist; bp; bp = nbp) { | |
701 | nbp = bp->b_blockf; | |
702 | s = splbio(); | |
703 | if (bp->b_flags & B_BUSY) { | |
704 | bp->b_flags |= B_WANTED; | |
d42a4811 | 705 | sleep((caddr_t)bp, PRIBIO + 1); |
c669f646 KM |
706 | splx(s); |
707 | break; | |
708 | } | |
709 | bremfree(bp); | |
710 | bp->b_flags |= B_BUSY; | |
5a3e32e2 | 711 | splx(s); |
c669f646 | 712 | if (save && (bp->b_flags & B_DELWRI)) { |
033a786e | 713 | dirty++; |
edadbc2c | 714 | (void) bwrite(bp); |
c669f646 | 715 | break; |
7188ac27 | 716 | } |
05a0ddc9 KM |
717 | if (bp->b_vp != vp) |
718 | reassignbuf(bp, bp->b_vp); | |
719 | else | |
720 | bp->b_flags |= B_INVAL; | |
c669f646 | 721 | brelse(bp); |
033a786e KM |
722 | } |
723 | } | |
c669f646 | 724 | if (vp->v_dirtyblkhd || vp->v_cleanblkhd) |
edadbc2c | 725 | panic("vinvalbuf: flush failed"); |
033a786e | 726 | return (dirty); |
7188ac27 KM |
727 | } |
728 | ||
edadbc2c KM |
729 | /* |
730 | * Associate a buffer with a vnode. | |
731 | */ | |
732 | bgetvp(vp, bp) | |
733 | register struct vnode *vp; | |
734 | register struct buf *bp; | |
735 | { | |
736 | ||
737 | if (bp->b_vp) | |
738 | panic("bgetvp: not free"); | |
79b10da1 | 739 | VHOLD(vp); |
edadbc2c KM |
740 | bp->b_vp = vp; |
741 | if (vp->v_type == VBLK || vp->v_type == VCHR) | |
742 | bp->b_dev = vp->v_rdev; | |
743 | else | |
744 | bp->b_dev = NODEV; | |
745 | /* | |
746 | * Insert onto list for new vnode. | |
747 | */ | |
c669f646 KM |
748 | if (vp->v_cleanblkhd) { |
749 | bp->b_blockf = vp->v_cleanblkhd; | |
750 | bp->b_blockb = &vp->v_cleanblkhd; | |
751 | vp->v_cleanblkhd->b_blockb = &bp->b_blockf; | |
752 | vp->v_cleanblkhd = bp; | |
edadbc2c | 753 | } else { |
c669f646 KM |
754 | vp->v_cleanblkhd = bp; |
755 | bp->b_blockb = &vp->v_cleanblkhd; | |
edadbc2c KM |
756 | bp->b_blockf = NULL; |
757 | } | |
758 | } | |
759 | ||
760 | /* | |
761 | * Disassociate a buffer from a vnode. | |
762 | */ | |
7188ac27 | 763 | brelvp(bp) |
edadbc2c | 764 | register struct buf *bp; |
7188ac27 | 765 | { |
edadbc2c | 766 | struct buf *bq; |
7188ac27 KM |
767 | struct vnode *vp; |
768 | ||
769 | if (bp->b_vp == (struct vnode *) 0) | |
edadbc2c KM |
770 | panic("brelvp: NULL"); |
771 | /* | |
772 | * Delete from old vnode list, if on one. | |
773 | */ | |
774 | if (bp->b_blockb) { | |
775 | if (bq = bp->b_blockf) | |
776 | bq->b_blockb = bp->b_blockb; | |
777 | *bp->b_blockb = bq; | |
778 | bp->b_blockf = NULL; | |
779 | bp->b_blockb = NULL; | |
780 | } | |
7188ac27 KM |
781 | vp = bp->b_vp; |
782 | bp->b_vp = (struct vnode *) 0; | |
79b10da1 | 783 | HOLDRELE(vp); |
7b8b5a01 | 784 | } |
edadbc2c KM |
785 | |
786 | /* | |
787 | * Reassign a buffer from one vnode to another. | |
788 | * Used to assign file specific control information | |
789 | * (indirect blocks) to the vnode to which they belong. | |
790 | */ | |
791 | reassignbuf(bp, newvp) | |
792 | register struct buf *bp; | |
793 | register struct vnode *newvp; | |
794 | { | |
c669f646 | 795 | register struct buf *bq, **listheadp; |
edadbc2c | 796 | |
c669f646 KM |
797 | if (newvp == NULL) |
798 | panic("reassignbuf: NULL"); | |
edadbc2c KM |
799 | /* |
800 | * Delete from old vnode list, if on one. | |
801 | */ | |
802 | if (bp->b_blockb) { | |
803 | if (bq = bp->b_blockf) | |
804 | bq->b_blockb = bp->b_blockb; | |
805 | *bp->b_blockb = bq; | |
806 | } | |
807 | /* | |
c669f646 KM |
808 | * If dirty, put on list of dirty buffers; |
809 | * otherwise insert onto list of clean buffers. | |
edadbc2c | 810 | */ |
c669f646 KM |
811 | if (bp->b_flags & B_DELWRI) |
812 | listheadp = &newvp->v_dirtyblkhd; | |
813 | else | |
814 | listheadp = &newvp->v_cleanblkhd; | |
815 | if (*listheadp) { | |
816 | bp->b_blockf = *listheadp; | |
817 | bp->b_blockb = listheadp; | |
818 | bp->b_blockf->b_blockb = &bp->b_blockf; | |
819 | *listheadp = bp; | |
edadbc2c | 820 | } else { |
c669f646 KM |
821 | *listheadp = bp; |
822 | bp->b_blockb = listheadp; | |
edadbc2c KM |
823 | bp->b_blockf = NULL; |
824 | } | |
825 | } |