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