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