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