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 | * | |
4597dd33 | 17 | * @(#)vfs_bio.c 7.28 (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"); | |
751af33e KM |
350 | /* |
351 | * To prevent overflow of 32-bit ints when converting block | |
352 | * numbers to byte offsets, blknos > 2^32 / DEV_BSIZE are set | |
353 | * to the maximum number that can be converted to a byte offset | |
354 | * without overflow. This is historic code; what bug it fixed, | |
355 | * or whether it is still a reasonable thing to do is open to | |
356 | * dispute. mkm 9/85 | |
edadbc2c KM |
357 | * |
358 | * Make it a panic to see if it ever really happens. mkm 11/89 | |
751af33e | 359 | */ |
edadbc2c KM |
360 | if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-DEV_BSHIFT)) { |
361 | panic("getblk: blkno too big"); | |
751af33e | 362 | blkno = 1 << ((sizeof(int)*NBBY-DEV_BSHIFT) + 1); |
edadbc2c | 363 | } |
3efdd860 KM |
364 | /* |
365 | * Search the cache for the block. If we hit, but | |
366 | * the buffer is in use for i/o, then we wait until | |
367 | * the i/o has completed. | |
368 | */ | |
7188ac27 | 369 | dp = BUFHASH(vp, blkno); |
3efdd860 | 370 | loop: |
46387ee3 | 371 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { |
edadbc2c | 372 | if (bp->b_lblkno != blkno || bp->b_vp != vp || |
46387ee3 | 373 | bp->b_flags&B_INVAL) |
663dbc72 | 374 | continue; |
a5e62f37 | 375 | s = splbio(); |
663dbc72 BJ |
376 | if (bp->b_flags&B_BUSY) { |
377 | bp->b_flags |= B_WANTED; | |
378 | sleep((caddr_t)bp, PRIBIO+1); | |
23900030 | 379 | splx(s); |
663dbc72 BJ |
380 | goto loop; |
381 | } | |
c669f646 KM |
382 | bremfree(bp); |
383 | bp->b_flags |= B_BUSY; | |
23900030 | 384 | splx(s); |
32a56bda | 385 | if (bp->b_bcount != size) { |
edadbc2c KM |
386 | printf("getblk: stray size"); |
387 | bp->b_flags |= B_INVAL; | |
388 | bwrite(bp); | |
9d6d37ce | 389 | goto loop; |
edadbc2c | 390 | } |
663dbc72 | 391 | bp->b_flags |= B_CACHE; |
a5e62f37 | 392 | return (bp); |
663dbc72 | 393 | } |
4f083fd7 | 394 | bp = getnewbuf(); |
ad30fb67 | 395 | bfree(bp); |
3efdd860 | 396 | bremhash(bp); |
edadbc2c KM |
397 | bgetvp(vp, bp); |
398 | bp->b_lblkno = blkno; | |
ec67a3ce MK |
399 | #ifdef SECSIZE |
400 | bp->b_blksize = secsize; | |
401 | #endif SECSIZE | |
ad30fb67 | 402 | bp->b_blkno = blkno; |
4f083fd7 | 403 | bp->b_error = 0; |
7188ac27 KM |
404 | bp->b_resid = 0; |
405 | binshash(bp, dp); | |
edadbc2c | 406 | brealloc(bp, size); |
a5e62f37 | 407 | return (bp); |
663dbc72 BJ |
408 | } |
409 | ||
410 | /* | |
411 | * get an empty block, | |
412 | * not assigned to any particular device | |
413 | */ | |
414 | struct buf * | |
ad30fb67 KM |
415 | geteblk(size) |
416 | int size; | |
663dbc72 | 417 | { |
4f083fd7 | 418 | register struct buf *bp, *flist; |
663dbc72 | 419 | |
00a6a148 KM |
420 | if (size > MAXBSIZE) |
421 | panic("geteblk: size too big"); | |
4f083fd7 SL |
422 | bp = getnewbuf(); |
423 | bp->b_flags |= B_INVAL; | |
3efdd860 KM |
424 | bfree(bp); |
425 | bremhash(bp); | |
4f083fd7 | 426 | flist = &bfreelist[BQ_AGE]; |
ec67a3ce MK |
427 | #ifdef SECSIZE |
428 | bp->b_blksize = DEV_BSIZE; | |
429 | #endif SECSIZE | |
4f083fd7 | 430 | bp->b_error = 0; |
7188ac27 KM |
431 | bp->b_resid = 0; |
432 | binshash(bp, flist); | |
edadbc2c | 433 | brealloc(bp, size); |
a5e62f37 | 434 | return (bp); |
663dbc72 BJ |
435 | } |
436 | ||
ad30fb67 KM |
437 | /* |
438 | * Allocate space associated with a buffer. | |
439 | */ | |
440 | brealloc(bp, size) | |
441 | register struct buf *bp; | |
442 | int size; | |
443 | { | |
444 | daddr_t start, last; | |
445 | register struct buf *ep; | |
446 | struct buf *dp; | |
447 | int s; | |
448 | ||
ad30fb67 | 449 | if (size == bp->b_bcount) |
edadbc2c KM |
450 | return; |
451 | allocbuf(bp, size); | |
4f083fd7 SL |
452 | } |
453 | ||
4f083fd7 SL |
454 | /* |
455 | * Find a buffer which is available for use. | |
456 | * Select something from a free list. | |
457 | * Preference is to AGE list, then LRU list. | |
458 | */ | |
459 | struct buf * | |
460 | getnewbuf() | |
461 | { | |
462 | register struct buf *bp, *dp; | |
a937f856 | 463 | register struct ucred *cred; |
4f083fd7 SL |
464 | int s; |
465 | ||
466 | loop: | |
a5e62f37 | 467 | s = splbio(); |
4f083fd7 SL |
468 | for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) |
469 | if (dp->av_forw != dp) | |
470 | break; | |
471 | if (dp == bfreelist) { /* no free blocks */ | |
472 | dp->b_flags |= B_WANTED; | |
473 | sleep((caddr_t)dp, PRIBIO+1); | |
4b7d506c | 474 | splx(s); |
4f083fd7 SL |
475 | goto loop; |
476 | } | |
4f083fd7 | 477 | bp = dp->av_forw; |
c669f646 KM |
478 | bremfree(bp); |
479 | bp->b_flags |= B_BUSY; | |
480 | splx(s); | |
4f083fd7 | 481 | if (bp->b_flags & B_DELWRI) { |
033a786e | 482 | (void) bawrite(bp); |
4f083fd7 SL |
483 | goto loop; |
484 | } | |
c5a600cf | 485 | trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); |
edadbc2c KM |
486 | if (bp->b_vp) |
487 | brelvp(bp); | |
a937f856 KM |
488 | if (bp->b_rcred != NOCRED) { |
489 | cred = bp->b_rcred; | |
490 | bp->b_rcred = NOCRED; | |
491 | crfree(cred); | |
492 | } | |
493 | if (bp->b_wcred != NOCRED) { | |
494 | cred = bp->b_wcred; | |
495 | bp->b_wcred = NOCRED; | |
496 | crfree(cred); | |
497 | } | |
4f083fd7 SL |
498 | bp->b_flags = B_BUSY; |
499 | return (bp); | |
500 | } | |
501 | ||
663dbc72 BJ |
502 | /* |
503 | * Wait for I/O completion on the buffer; return errors | |
504 | * to the user. | |
505 | */ | |
3efdd860 | 506 | biowait(bp) |
ad30fb67 | 507 | register struct buf *bp; |
663dbc72 | 508 | { |
530d0032 | 509 | int s; |
663dbc72 | 510 | |
a5e62f37 | 511 | s = splbio(); |
a937f856 | 512 | while ((bp->b_flags & B_DONE) == 0) |
663dbc72 | 513 | sleep((caddr_t)bp, PRIBIO); |
530d0032 | 514 | splx(s); |
7188ac27 KM |
515 | /* |
516 | * Pick up the device's error number and pass it to the user; | |
517 | * if there is an error but the number is 0 set a generalized code. | |
518 | */ | |
519 | if ((bp->b_flags & B_ERROR) == 0) | |
520 | return (0); | |
521 | if (bp->b_error) | |
522 | return (bp->b_error); | |
523 | return (EIO); | |
663dbc72 BJ |
524 | } |
525 | ||
663dbc72 | 526 | /* |
af04ce66 SL |
527 | * Mark I/O complete on a buffer. |
528 | * If someone should be called, e.g. the pageout | |
529 | * daemon, do so. Otherwise, wake up anyone | |
530 | * waiting for it. | |
663dbc72 | 531 | */ |
3efdd860 KM |
532 | biodone(bp) |
533 | register struct buf *bp; | |
663dbc72 | 534 | { |
c669f646 | 535 | register struct vnode *vp; |
663dbc72 | 536 | |
80e7c811 | 537 | if (bp->b_flags & B_DONE) |
3efdd860 | 538 | panic("dup biodone"); |
663dbc72 | 539 | bp->b_flags |= B_DONE; |
c669f646 | 540 | if ((bp->b_flags & B_READ) == 0) { |
a937f856 | 541 | bp->b_dirtyoff = bp->b_dirtyend = 0; |
c669f646 KM |
542 | if (vp = bp->b_vp) { |
543 | vp->v_numoutput--; | |
544 | if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { | |
545 | if (vp->v_numoutput < 0) | |
546 | panic("biodone: neg numoutput"); | |
547 | vp->v_flag &= ~VBWAIT; | |
548 | wakeup((caddr_t)&vp->v_numoutput); | |
549 | } | |
550 | } | |
551 | } | |
961945a8 SL |
552 | if (bp->b_flags & B_CALL) { |
553 | bp->b_flags &= ~B_CALL; | |
554 | (*bp->b_iodone)(bp); | |
555 | return; | |
556 | } | |
663dbc72 BJ |
557 | if (bp->b_flags&B_ASYNC) |
558 | brelse(bp); | |
559 | else { | |
560 | bp->b_flags &= ~B_WANTED; | |
561 | wakeup((caddr_t)bp); | |
562 | } | |
563 | } | |
564 | ||
663dbc72 | 565 | /* |
7188ac27 | 566 | * Make sure all write-behind blocks associated |
a937f856 | 567 | * with mount point are flushed out (from sync). |
663dbc72 | 568 | */ |
edadbc2c | 569 | mntflushbuf(mountp, flags) |
a937f856 | 570 | struct mount *mountp; |
edadbc2c | 571 | int flags; |
663dbc72 | 572 | { |
099798da | 573 | register struct vnode *vp; |
edadbc2c | 574 | |
54fb9dc2 | 575 | if ((mountp->mnt_flag & MNT_MPBUSY) == 0) |
17c2edaa | 576 | panic("mntflushbuf: not busy"); |
edadbc2c | 577 | loop: |
4597dd33 | 578 | for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { |
edadbc2c KM |
579 | if (vget(vp)) |
580 | goto loop; | |
581 | vflushbuf(vp, flags); | |
582 | vput(vp); | |
4597dd33 KM |
583 | if (vp->v_mount != mountp) |
584 | goto loop; | |
edadbc2c KM |
585 | } |
586 | } | |
587 | ||
588 | /* | |
589 | * Flush all dirty buffers associated with a vnode. | |
590 | */ | |
591 | vflushbuf(vp, flags) | |
592 | register struct vnode *vp; | |
593 | int flags; | |
594 | { | |
595 | register struct buf *bp; | |
596 | struct buf *nbp; | |
530d0032 | 597 | int s; |
663dbc72 BJ |
598 | |
599 | loop: | |
a5e62f37 | 600 | s = splbio(); |
c669f646 | 601 | for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { |
edadbc2c KM |
602 | nbp = bp->b_blockf; |
603 | if ((bp->b_flags & B_BUSY)) | |
604 | continue; | |
605 | if ((bp->b_flags & B_DELWRI) == 0) | |
c669f646 KM |
606 | panic("vflushbuf: not dirty"); |
607 | bremfree(bp); | |
608 | bp->b_flags |= B_BUSY; | |
edadbc2c | 609 | splx(s); |
c669f646 KM |
610 | /* |
611 | * Wait for I/O associated with indirect blocks to complete, | |
612 | * since there is no way to quickly wait for them below. | |
613 | * NB - This is really specific to ufs, but is done here | |
614 | * as it is easier and quicker. | |
615 | */ | |
616 | if (bp->b_vp == vp || (flags & B_SYNC) == 0) { | |
617 | (void) bawrite(bp); | |
93d6e9b8 | 618 | s = splbio(); |
c669f646 KM |
619 | } else { |
620 | (void) bwrite(bp); | |
621 | goto loop; | |
622 | } | |
edadbc2c | 623 | } |
9c1dffd6 | 624 | splx(s); |
edadbc2c KM |
625 | if ((flags & B_SYNC) == 0) |
626 | return; | |
edadbc2c | 627 | s = splbio(); |
c669f646 KM |
628 | while (vp->v_numoutput) { |
629 | vp->v_flag |= VBWAIT; | |
630 | sleep((caddr_t)&vp->v_numoutput, PRIBIO+1); | |
7188ac27 | 631 | } |
9c1dffd6 | 632 | splx(s); |
c669f646 KM |
633 | if (vp->v_dirtyblkhd) { |
634 | vprint("vflushbuf: dirty", vp); | |
635 | goto loop; | |
636 | } | |
663dbc72 | 637 | } |
7b8b5a01 RE |
638 | |
639 | /* | |
640 | * Invalidate in core blocks belonging to closed or umounted filesystem | |
641 | * | |
edadbc2c KM |
642 | * Go through the list of vnodes associated with the file system; |
643 | * for each vnode invalidate any buffers that it holds. Normally | |
644 | * this routine is preceeded by a bflush call, so that on a quiescent | |
645 | * filesystem there will be no dirty buffers when we are done. Binval | |
646 | * returns the count of dirty buffers when it is finished. | |
7b8b5a01 | 647 | */ |
edadbc2c | 648 | mntinvalbuf(mountp) |
a937f856 | 649 | struct mount *mountp; |
7b8b5a01 | 650 | { |
099798da | 651 | register struct vnode *vp; |
edadbc2c KM |
652 | int dirty = 0; |
653 | ||
54fb9dc2 | 654 | if ((mountp->mnt_flag & MNT_MPBUSY) == 0) |
17c2edaa | 655 | panic("mntinvalbuf: not busy"); |
edadbc2c | 656 | loop: |
4597dd33 | 657 | for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { |
edadbc2c KM |
658 | if (vget(vp)) |
659 | goto loop; | |
660 | dirty += vinvalbuf(vp, 1); | |
661 | vput(vp); | |
4597dd33 KM |
662 | if (vp->v_mount != mountp) |
663 | goto loop; | |
edadbc2c KM |
664 | } |
665 | return (dirty); | |
666 | } | |
667 | ||
668 | /* | |
669 | * Flush out and invalidate all buffers associated with a vnode. | |
670 | * Called with the underlying object locked. | |
671 | */ | |
672 | vinvalbuf(vp, save) | |
673 | register struct vnode *vp; | |
674 | int save; | |
675 | { | |
676 | register struct buf *bp; | |
c669f646 | 677 | struct buf *nbp, *blist; |
1a24c701 | 678 | int s, dirty = 0; |
7b8b5a01 | 679 | |
c669f646 KM |
680 | for (;;) { |
681 | if (blist = vp->v_dirtyblkhd) | |
682 | /* void */; | |
683 | else if (blist = vp->v_cleanblkhd) | |
684 | /* void */; | |
685 | else | |
686 | break; | |
687 | for (bp = blist; bp; bp = nbp) { | |
688 | nbp = bp->b_blockf; | |
689 | s = splbio(); | |
690 | if (bp->b_flags & B_BUSY) { | |
691 | bp->b_flags |= B_WANTED; | |
692 | sleep((caddr_t)bp, PRIBIO+1); | |
693 | splx(s); | |
694 | break; | |
695 | } | |
696 | bremfree(bp); | |
697 | bp->b_flags |= B_BUSY; | |
5a3e32e2 | 698 | splx(s); |
c669f646 | 699 | if (save && (bp->b_flags & B_DELWRI)) { |
033a786e | 700 | dirty++; |
edadbc2c | 701 | (void) bwrite(bp); |
c669f646 | 702 | break; |
7188ac27 | 703 | } |
05a0ddc9 KM |
704 | if (bp->b_vp != vp) |
705 | reassignbuf(bp, bp->b_vp); | |
706 | else | |
707 | bp->b_flags |= B_INVAL; | |
c669f646 | 708 | brelse(bp); |
033a786e KM |
709 | } |
710 | } | |
c669f646 | 711 | if (vp->v_dirtyblkhd || vp->v_cleanblkhd) |
edadbc2c | 712 | panic("vinvalbuf: flush failed"); |
033a786e | 713 | return (dirty); |
7188ac27 KM |
714 | } |
715 | ||
edadbc2c KM |
716 | /* |
717 | * Associate a buffer with a vnode. | |
718 | */ | |
719 | bgetvp(vp, bp) | |
720 | register struct vnode *vp; | |
721 | register struct buf *bp; | |
722 | { | |
723 | ||
724 | if (bp->b_vp) | |
725 | panic("bgetvp: not free"); | |
79b10da1 | 726 | VHOLD(vp); |
edadbc2c KM |
727 | bp->b_vp = vp; |
728 | if (vp->v_type == VBLK || vp->v_type == VCHR) | |
729 | bp->b_dev = vp->v_rdev; | |
730 | else | |
731 | bp->b_dev = NODEV; | |
732 | /* | |
733 | * Insert onto list for new vnode. | |
734 | */ | |
c669f646 KM |
735 | if (vp->v_cleanblkhd) { |
736 | bp->b_blockf = vp->v_cleanblkhd; | |
737 | bp->b_blockb = &vp->v_cleanblkhd; | |
738 | vp->v_cleanblkhd->b_blockb = &bp->b_blockf; | |
739 | vp->v_cleanblkhd = bp; | |
edadbc2c | 740 | } else { |
c669f646 KM |
741 | vp->v_cleanblkhd = bp; |
742 | bp->b_blockb = &vp->v_cleanblkhd; | |
edadbc2c KM |
743 | bp->b_blockf = NULL; |
744 | } | |
745 | } | |
746 | ||
747 | /* | |
748 | * Disassociate a buffer from a vnode. | |
749 | */ | |
7188ac27 | 750 | brelvp(bp) |
edadbc2c | 751 | register struct buf *bp; |
7188ac27 | 752 | { |
edadbc2c | 753 | struct buf *bq; |
7188ac27 KM |
754 | struct vnode *vp; |
755 | ||
756 | if (bp->b_vp == (struct vnode *) 0) | |
edadbc2c KM |
757 | panic("brelvp: NULL"); |
758 | /* | |
759 | * Delete from old vnode list, if on one. | |
760 | */ | |
761 | if (bp->b_blockb) { | |
762 | if (bq = bp->b_blockf) | |
763 | bq->b_blockb = bp->b_blockb; | |
764 | *bp->b_blockb = bq; | |
765 | bp->b_blockf = NULL; | |
766 | bp->b_blockb = NULL; | |
767 | } | |
7188ac27 KM |
768 | vp = bp->b_vp; |
769 | bp->b_vp = (struct vnode *) 0; | |
79b10da1 | 770 | HOLDRELE(vp); |
7b8b5a01 | 771 | } |
edadbc2c KM |
772 | |
773 | /* | |
774 | * Reassign a buffer from one vnode to another. | |
775 | * Used to assign file specific control information | |
776 | * (indirect blocks) to the vnode to which they belong. | |
777 | */ | |
778 | reassignbuf(bp, newvp) | |
779 | register struct buf *bp; | |
780 | register struct vnode *newvp; | |
781 | { | |
c669f646 | 782 | register struct buf *bq, **listheadp; |
edadbc2c | 783 | |
c669f646 KM |
784 | if (newvp == NULL) |
785 | panic("reassignbuf: NULL"); | |
edadbc2c KM |
786 | /* |
787 | * Delete from old vnode list, if on one. | |
788 | */ | |
789 | if (bp->b_blockb) { | |
790 | if (bq = bp->b_blockf) | |
791 | bq->b_blockb = bp->b_blockb; | |
792 | *bp->b_blockb = bq; | |
793 | } | |
794 | /* | |
c669f646 KM |
795 | * If dirty, put on list of dirty buffers; |
796 | * otherwise insert onto list of clean buffers. | |
edadbc2c | 797 | */ |
c669f646 KM |
798 | if (bp->b_flags & B_DELWRI) |
799 | listheadp = &newvp->v_dirtyblkhd; | |
800 | else | |
801 | listheadp = &newvp->v_cleanblkhd; | |
802 | if (*listheadp) { | |
803 | bp->b_blockf = *listheadp; | |
804 | bp->b_blockb = listheadp; | |
805 | bp->b_blockf->b_blockb = &bp->b_blockf; | |
806 | *listheadp = bp; | |
edadbc2c | 807 | } else { |
c669f646 KM |
808 | *listheadp = bp; |
809 | bp->b_blockb = listheadp; | |
edadbc2c KM |
810 | bp->b_blockf = NULL; |
811 | } | |
812 | } |