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