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