Commit | Line | Data |
---|---|---|
f844ee62 | 1 | /* vfs_cluster.c 4.41 82/12/19 */ |
961945a8 SL |
2 | |
3 | #include "../machine/pte.h" | |
663dbc72 BJ |
4 | |
5 | #include "../h/param.h" | |
6 | #include "../h/systm.h" | |
7 | #include "../h/dir.h" | |
8 | #include "../h/user.h" | |
9 | #include "../h/buf.h" | |
10 | #include "../h/conf.h" | |
11 | #include "../h/proc.h" | |
12 | #include "../h/seg.h" | |
663dbc72 | 13 | #include "../h/vm.h" |
973ecc4f | 14 | #include "../h/trace.h" |
663dbc72 | 15 | |
663dbc72 BJ |
16 | /* |
17 | * Read in (if necessary) the block and return a buffer pointer. | |
18 | */ | |
19 | struct buf * | |
ad30fb67 KM |
20 | bread(dev, blkno, size) |
21 | dev_t dev; | |
22 | daddr_t blkno; | |
23 | int size; | |
663dbc72 BJ |
24 | { |
25 | register struct buf *bp; | |
26 | ||
4f083fd7 SL |
27 | if (size == 0) |
28 | panic("bread: size 0"); | |
ad30fb67 | 29 | bp = getblk(dev, blkno, size); |
663dbc72 | 30 | if (bp->b_flags&B_DONE) { |
15f77b9b | 31 | trace(TR_BREADHIT, dev, blkno); |
663dbc72 BJ |
32 | return(bp); |
33 | } | |
34 | bp->b_flags |= B_READ; | |
4f083fd7 SL |
35 | if (bp->b_bcount > bp->b_bufsize) |
36 | panic("bread"); | |
663dbc72 | 37 | (*bdevsw[major(dev)].d_strategy)(bp); |
15f77b9b | 38 | trace(TR_BREADMISS, dev, blkno); |
fb99a9a1 | 39 | u.u_ru.ru_inblock++; /* pay for read */ |
3efdd860 | 40 | biowait(bp); |
663dbc72 BJ |
41 | return(bp); |
42 | } | |
43 | ||
44 | /* | |
45 | * Read in the block, like bread, but also start I/O on the | |
46 | * read-ahead block (which is not allocated to the caller) | |
47 | */ | |
48 | struct buf * | |
a8d3bf7f | 49 | breada(dev, blkno, size, rablkno, rabsize) |
ad30fb67 | 50 | dev_t dev; |
84baaab3 | 51 | daddr_t blkno; int size; |
a8d3bf7f | 52 | daddr_t rablkno; int rabsize; |
663dbc72 BJ |
53 | { |
54 | register struct buf *bp, *rabp; | |
55 | ||
56 | bp = NULL; | |
3efdd860 KM |
57 | /* |
58 | * If the block isn't in core, then allocate | |
59 | * a buffer and initiate i/o (getblk checks | |
60 | * for a cache hit). | |
61 | */ | |
663dbc72 | 62 | if (!incore(dev, blkno)) { |
ad30fb67 | 63 | bp = getblk(dev, blkno, size); |
663dbc72 BJ |
64 | if ((bp->b_flags&B_DONE) == 0) { |
65 | bp->b_flags |= B_READ; | |
4f083fd7 SL |
66 | if (bp->b_bcount > bp->b_bufsize) |
67 | panic("breada"); | |
663dbc72 | 68 | (*bdevsw[major(dev)].d_strategy)(bp); |
15f77b9b | 69 | trace(TR_BREADMISS, dev, blkno); |
fb99a9a1 | 70 | u.u_ru.ru_inblock++; /* pay for read */ |
3efdd860 | 71 | } else |
15f77b9b | 72 | trace(TR_BREADHIT, dev, blkno); |
663dbc72 | 73 | } |
3efdd860 KM |
74 | |
75 | /* | |
76 | * If there's a read-ahead block, start i/o | |
77 | * on it also (as above). | |
78 | */ | |
663dbc72 | 79 | if (rablkno && !incore(dev, rablkno)) { |
a8d3bf7f | 80 | rabp = getblk(dev, rablkno, rabsize); |
973ecc4f | 81 | if (rabp->b_flags & B_DONE) { |
663dbc72 | 82 | brelse(rabp); |
15f77b9b | 83 | trace(TR_BREADHITRA, dev, blkno); |
973ecc4f | 84 | } else { |
663dbc72 | 85 | rabp->b_flags |= B_READ|B_ASYNC; |
4f083fd7 SL |
86 | if (rabp->b_bcount > rabp->b_bufsize) |
87 | panic("breadrabp"); | |
663dbc72 | 88 | (*bdevsw[major(dev)].d_strategy)(rabp); |
15f77b9b | 89 | trace(TR_BREADMISSRA, dev, rablock); |
fb99a9a1 | 90 | u.u_ru.ru_inblock++; /* pay in advance */ |
663dbc72 BJ |
91 | } |
92 | } | |
3efdd860 KM |
93 | |
94 | /* | |
84baaab3 KM |
95 | * If block was in core, let bread get it. |
96 | * If block wasn't in core, then the read was started | |
97 | * above, and just wait for it. | |
3efdd860 | 98 | */ |
84baaab3 KM |
99 | if (bp == NULL) |
100 | return (bread(dev, blkno, size)); | |
3efdd860 | 101 | biowait(bp); |
84baaab3 | 102 | return (bp); |
663dbc72 BJ |
103 | } |
104 | ||
105 | /* | |
106 | * Write the buffer, waiting for completion. | |
107 | * Then release the buffer. | |
108 | */ | |
109 | bwrite(bp) | |
3efdd860 | 110 | register struct buf *bp; |
663dbc72 BJ |
111 | { |
112 | register flag; | |
113 | ||
114 | flag = bp->b_flags; | |
f844ee62 | 115 | bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); |
663dbc72 | 116 | if ((flag&B_DELWRI) == 0) |
fb99a9a1 | 117 | u.u_ru.ru_oublock++; /* noone paid yet */ |
53f9ca20 | 118 | trace(TR_BWRITE, bp->b_dev, bp->b_blkno); |
4f083fd7 SL |
119 | if (bp->b_bcount > bp->b_bufsize) |
120 | panic("bwrite"); | |
663dbc72 | 121 | (*bdevsw[major(bp->b_dev)].d_strategy)(bp); |
3efdd860 KM |
122 | |
123 | /* | |
124 | * If the write was synchronous, then await i/o completion. | |
125 | * If the write was "delayed", then we put the buffer on | |
126 | * the q of blocks awaiting i/o completion status. | |
3efdd860 | 127 | */ |
663dbc72 | 128 | if ((flag&B_ASYNC) == 0) { |
3efdd860 | 129 | biowait(bp); |
663dbc72 BJ |
130 | brelse(bp); |
131 | } else if (flag & B_DELWRI) | |
132 | bp->b_flags |= B_AGE; | |
663dbc72 BJ |
133 | } |
134 | ||
135 | /* | |
136 | * Release the buffer, marking it so that if it is grabbed | |
137 | * for another purpose it will be written out before being | |
138 | * given up (e.g. when writing a partial block where it is | |
139 | * assumed that another write for the same block will soon follow). | |
140 | * This can't be done for magtape, since writes must be done | |
141 | * in the same order as requested. | |
142 | */ | |
143 | bdwrite(bp) | |
3efdd860 | 144 | register struct buf *bp; |
663dbc72 | 145 | { |
e1e57888 | 146 | register int flags; |
663dbc72 BJ |
147 | |
148 | if ((bp->b_flags&B_DELWRI) == 0) | |
fb99a9a1 | 149 | u.u_ru.ru_oublock++; /* noone paid yet */ |
e1e57888 RE |
150 | flags = bdevsw[major(bp->b_dev)].d_flags; |
151 | if(flags & B_TAPE) | |
663dbc72 BJ |
152 | bawrite(bp); |
153 | else { | |
154 | bp->b_flags |= B_DELWRI | B_DONE; | |
155 | brelse(bp); | |
156 | } | |
157 | } | |
158 | ||
159 | /* | |
160 | * Release the buffer, start I/O on it, but don't wait for completion. | |
161 | */ | |
162 | bawrite(bp) | |
3efdd860 | 163 | register struct buf *bp; |
663dbc72 BJ |
164 | { |
165 | ||
166 | bp->b_flags |= B_ASYNC; | |
167 | bwrite(bp); | |
168 | } | |
169 | ||
170 | /* | |
3efdd860 | 171 | * Release the buffer, with no I/O implied. |
663dbc72 BJ |
172 | */ |
173 | brelse(bp) | |
3efdd860 | 174 | register struct buf *bp; |
663dbc72 | 175 | { |
46387ee3 | 176 | register struct buf *flist; |
663dbc72 BJ |
177 | register s; |
178 | ||
3efdd860 KM |
179 | /* |
180 | * If someone's waiting for the buffer, or | |
181 | * is waiting for a buffer wake 'em up. | |
182 | */ | |
663dbc72 BJ |
183 | if (bp->b_flags&B_WANTED) |
184 | wakeup((caddr_t)bp); | |
46387ee3 BJ |
185 | if (bfreelist[0].b_flags&B_WANTED) { |
186 | bfreelist[0].b_flags &= ~B_WANTED; | |
187 | wakeup((caddr_t)bfreelist); | |
663dbc72 | 188 | } |
60a71525 BJ |
189 | if (bp->b_flags&B_ERROR) |
190 | if (bp->b_flags & B_LOCKED) | |
191 | bp->b_flags &= ~B_ERROR; /* try again later */ | |
192 | else | |
193 | bp->b_dev = NODEV; /* no assoc */ | |
3efdd860 KM |
194 | |
195 | /* | |
196 | * Stick the buffer back on a free list. | |
197 | */ | |
663dbc72 | 198 | s = spl6(); |
4f083fd7 SL |
199 | if (bp->b_bufsize <= 0) { |
200 | /* block has no buffer ... put at front of unused buffer list */ | |
201 | flist = &bfreelist[BQ_EMPTY]; | |
202 | binsheadfree(bp, flist); | |
203 | } else if (bp->b_flags & (B_ERROR|B_INVAL)) { | |
46387ee3 | 204 | /* block has no info ... put at front of most free list */ |
4f083fd7 | 205 | flist = &bfreelist[BQ_AGE]; |
3efdd860 | 206 | binsheadfree(bp, flist); |
663dbc72 | 207 | } else { |
46387ee3 BJ |
208 | if (bp->b_flags & B_LOCKED) |
209 | flist = &bfreelist[BQ_LOCKED]; | |
210 | else if (bp->b_flags & B_AGE) | |
211 | flist = &bfreelist[BQ_AGE]; | |
212 | else | |
213 | flist = &bfreelist[BQ_LRU]; | |
3efdd860 | 214 | binstailfree(bp, flist); |
663dbc72 BJ |
215 | } |
216 | bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); | |
217 | splx(s); | |
218 | } | |
219 | ||
220 | /* | |
221 | * See if the block is associated with some buffer | |
222 | * (mainly to avoid getting hung up on a wait in breada) | |
223 | */ | |
224 | incore(dev, blkno) | |
3efdd860 KM |
225 | dev_t dev; |
226 | daddr_t blkno; | |
663dbc72 BJ |
227 | { |
228 | register struct buf *bp; | |
46387ee3 | 229 | register struct buf *dp; |
663dbc72 | 230 | |
ad30fb67 | 231 | dp = BUFHASH(dev, blkno); |
46387ee3 | 232 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) |
ad30fb67 | 233 | if (bp->b_blkno == blkno && bp->b_dev == dev && |
3efdd860 | 234 | (bp->b_flags & B_INVAL) == 0) |
5603d07d | 235 | return (1); |
5603d07d | 236 | return (0); |
663dbc72 BJ |
237 | } |
238 | ||
239 | struct buf * | |
ad30fb67 KM |
240 | baddr(dev, blkno, size) |
241 | dev_t dev; | |
242 | daddr_t blkno; | |
243 | int size; | |
663dbc72 BJ |
244 | { |
245 | ||
246 | if (incore(dev, blkno)) | |
ad30fb67 | 247 | return (bread(dev, blkno, size)); |
663dbc72 BJ |
248 | return (0); |
249 | } | |
250 | ||
251 | /* | |
252 | * Assign a buffer for the given block. If the appropriate | |
253 | * block is already associated, return it; otherwise search | |
254 | * for the oldest non-busy buffer and reassign it. | |
23900030 BJ |
255 | * |
256 | * We use splx here because this routine may be called | |
257 | * on the interrupt stack during a dump, and we don't | |
258 | * want to lower the ipl back to 0. | |
663dbc72 BJ |
259 | */ |
260 | struct buf * | |
ad30fb67 KM |
261 | getblk(dev, blkno, size) |
262 | dev_t dev; | |
263 | daddr_t blkno; | |
264 | int size; | |
663dbc72 | 265 | { |
4f083fd7 | 266 | register struct buf *bp, *dp; |
23900030 | 267 | int s; |
663dbc72 | 268 | |
961945a8 | 269 | if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT)) /* XXX */ |
01659974 | 270 | blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1); |
3efdd860 KM |
271 | /* |
272 | * Search the cache for the block. If we hit, but | |
273 | * the buffer is in use for i/o, then we wait until | |
274 | * the i/o has completed. | |
275 | */ | |
ad30fb67 | 276 | dp = BUFHASH(dev, blkno); |
3efdd860 | 277 | loop: |
46387ee3 | 278 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { |
ad30fb67 | 279 | if (bp->b_blkno != blkno || bp->b_dev != dev || |
46387ee3 | 280 | bp->b_flags&B_INVAL) |
663dbc72 | 281 | continue; |
23900030 | 282 | s = spl6(); |
663dbc72 BJ |
283 | if (bp->b_flags&B_BUSY) { |
284 | bp->b_flags |= B_WANTED; | |
285 | sleep((caddr_t)bp, PRIBIO+1); | |
23900030 | 286 | splx(s); |
663dbc72 BJ |
287 | goto loop; |
288 | } | |
23900030 | 289 | splx(s); |
663dbc72 | 290 | notavail(bp); |
9d6d37ce BJ |
291 | if (brealloc(bp, size) == 0) |
292 | goto loop; | |
663dbc72 BJ |
293 | bp->b_flags |= B_CACHE; |
294 | return(bp); | |
295 | } | |
5603d07d BJ |
296 | if (major(dev) >= nblkdev) |
297 | panic("blkdev"); | |
4f083fd7 | 298 | bp = getnewbuf(); |
ad30fb67 | 299 | bfree(bp); |
3efdd860 KM |
300 | bremhash(bp); |
301 | binshash(bp, dp); | |
663dbc72 | 302 | bp->b_dev = dev; |
ad30fb67 | 303 | bp->b_blkno = blkno; |
4f083fd7 | 304 | bp->b_error = 0; |
9d6d37ce BJ |
305 | if (brealloc(bp, size) == 0) |
306 | goto loop; | |
663dbc72 BJ |
307 | return(bp); |
308 | } | |
309 | ||
310 | /* | |
311 | * get an empty block, | |
312 | * not assigned to any particular device | |
313 | */ | |
314 | struct buf * | |
ad30fb67 KM |
315 | geteblk(size) |
316 | int size; | |
663dbc72 | 317 | { |
4f083fd7 | 318 | register struct buf *bp, *flist; |
663dbc72 BJ |
319 | |
320 | loop: | |
4f083fd7 SL |
321 | bp = getnewbuf(); |
322 | bp->b_flags |= B_INVAL; | |
3efdd860 KM |
323 | bfree(bp); |
324 | bremhash(bp); | |
4f083fd7 SL |
325 | flist = &bfreelist[BQ_AGE]; |
326 | binshash(bp, flist); | |
663dbc72 | 327 | bp->b_dev = (dev_t)NODEV; |
4f083fd7 | 328 | bp->b_error = 0; |
9d6d37ce BJ |
329 | if (brealloc(bp, size) == 0) |
330 | goto loop; | |
663dbc72 BJ |
331 | return(bp); |
332 | } | |
333 | ||
ad30fb67 KM |
334 | /* |
335 | * Allocate space associated with a buffer. | |
961945a8 | 336 | * If can't get space, buffer is released |
ad30fb67 KM |
337 | */ |
338 | brealloc(bp, size) | |
339 | register struct buf *bp; | |
340 | int size; | |
341 | { | |
342 | daddr_t start, last; | |
343 | register struct buf *ep; | |
344 | struct buf *dp; | |
345 | int s; | |
346 | ||
347 | /* | |
348 | * First need to make sure that all overlaping previous I/O | |
349 | * is dispatched with. | |
350 | */ | |
351 | if (size == bp->b_bcount) | |
9d6d37ce BJ |
352 | return (1); |
353 | if (size < bp->b_bcount) { | |
354 | if (bp->b_flags & B_DELWRI) { | |
355 | bwrite(bp); | |
356 | return (0); | |
357 | } | |
358 | if (bp->b_flags & B_LOCKED) | |
359 | panic("brealloc"); | |
961945a8 | 360 | return (allocbuf(bp, size)); |
ad30fb67 | 361 | } |
9d6d37ce | 362 | bp->b_flags &= ~B_DONE; |
961945a8 SL |
363 | if (bp->b_dev == NODEV) |
364 | return (allocbuf(bp, size)); | |
9d6d37ce BJ |
365 | |
366 | /* | |
367 | * Search cache for any buffers that overlap the one that we | |
368 | * are trying to allocate. Overlapping buffers must be marked | |
369 | * invalid, after being written out if they are dirty. (indicated | |
370 | * by B_DELWRI) A disk block must be mapped by at most one buffer | |
371 | * at any point in time. Care must be taken to avoid deadlocking | |
372 | * when two buffer are trying to get the same set of disk blocks. | |
373 | */ | |
374 | start = bp->b_blkno; | |
375 | last = start + (size / DEV_BSIZE) - 1; | |
ad30fb67 KM |
376 | dp = BUFHASH(bp->b_dev, bp->b_blkno); |
377 | loop: | |
ad30fb67 | 378 | for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { |
9d6d37ce BJ |
379 | if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL)) |
380 | continue; | |
381 | /* look for overlap */ | |
382 | if (ep->b_bcount == 0 || ep->b_blkno > last || | |
383 | ep->b_blkno + (ep->b_bcount / DEV_BSIZE) <= start) | |
ad30fb67 KM |
384 | continue; |
385 | s = spl6(); | |
386 | if (ep->b_flags&B_BUSY) { | |
387 | ep->b_flags |= B_WANTED; | |
388 | sleep((caddr_t)ep, PRIBIO+1); | |
4f083fd7 | 389 | splx(s); |
ad30fb67 KM |
390 | goto loop; |
391 | } | |
4f083fd7 | 392 | splx(s); |
9d6d37ce | 393 | notavail(ep); |
ad30fb67 | 394 | if (ep->b_flags & B_DELWRI) { |
ad30fb67 KM |
395 | bwrite(ep); |
396 | goto loop; | |
397 | } | |
9d6d37ce BJ |
398 | ep->b_flags |= B_INVAL; |
399 | brelse(ep); | |
ad30fb67 | 400 | } |
961945a8 | 401 | return (allocbuf(bp, size)); |
4f083fd7 SL |
402 | } |
403 | ||
404 | /* | |
405 | * Expand or contract the actual memory allocated to a buffer. | |
961945a8 | 406 | * If no memory is available, release buffer and take error exit |
4f083fd7 SL |
407 | */ |
408 | allocbuf(tp, size) | |
409 | register struct buf *tp; | |
410 | int size; | |
411 | { | |
412 | register struct buf *bp, *ep; | |
413 | int sizealloc, take; | |
961945a8 SL |
414 | #ifdef sun |
415 | register char *a; | |
416 | int osize; | |
417 | #endif | |
4f083fd7 | 418 | |
961945a8 | 419 | #ifndef sun |
4f083fd7 | 420 | sizealloc = roundup(size, CLBYTES); |
961945a8 SL |
421 | #else |
422 | sizealloc = roundup(size, BUFALLOCSIZE); | |
423 | #endif | |
4f083fd7 SL |
424 | /* |
425 | * Buffer size does not change | |
426 | */ | |
427 | if (sizealloc == tp->b_bufsize) | |
428 | goto out; | |
961945a8 | 429 | #ifndef sun |
4f083fd7 SL |
430 | /* |
431 | * Buffer size is shrinking. | |
432 | * Place excess space in a buffer header taken from the | |
433 | * BQ_EMPTY buffer list and placed on the "most free" list. | |
434 | * If no extra buffer headers are available, leave the | |
435 | * extra space in the present buffer. | |
436 | */ | |
437 | if (sizealloc < tp->b_bufsize) { | |
438 | ep = bfreelist[BQ_EMPTY].av_forw; | |
439 | if (ep == &bfreelist[BQ_EMPTY]) | |
440 | goto out; | |
441 | notavail(ep); | |
442 | pagemove(tp->b_un.b_addr + sizealloc, ep->b_un.b_addr, | |
443 | (int)tp->b_bufsize - sizealloc); | |
444 | ep->b_bufsize = tp->b_bufsize - sizealloc; | |
445 | tp->b_bufsize = sizealloc; | |
446 | ep->b_flags |= B_INVAL; | |
447 | ep->b_bcount = 0; | |
448 | brelse(ep); | |
449 | goto out; | |
450 | } | |
ad30fb67 | 451 | /* |
4f083fd7 SL |
452 | * More buffer space is needed. Get it out of buffers on |
453 | * the "most free" list, placing the empty headers on the | |
454 | * BQ_EMPTY buffer header list. | |
ad30fb67 | 455 | */ |
4f083fd7 SL |
456 | while (tp->b_bufsize < sizealloc) { |
457 | take = sizealloc - tp->b_bufsize; | |
458 | bp = getnewbuf(); | |
459 | if (take >= bp->b_bufsize) | |
460 | take = bp->b_bufsize; | |
461 | pagemove(&bp->b_un.b_addr[bp->b_bufsize - take], | |
462 | &tp->b_un.b_addr[tp->b_bufsize], take); | |
463 | tp->b_bufsize += take; | |
464 | bp->b_bufsize = bp->b_bufsize - take; | |
465 | if (bp->b_bcount > bp->b_bufsize) | |
466 | bp->b_bcount = bp->b_bufsize; | |
467 | if (bp->b_bufsize <= 0) { | |
468 | bremhash(bp); | |
469 | binshash(bp, &bfreelist[BQ_EMPTY]); | |
470 | bp->b_dev = (dev_t)NODEV; | |
471 | bp->b_error = 0; | |
472 | bp->b_flags |= B_INVAL; | |
473 | } | |
474 | brelse(bp); | |
475 | } | |
961945a8 SL |
476 | #else |
477 | /* | |
478 | * Buffer size is shrinking | |
479 | * Just put the tail end back in the map | |
480 | */ | |
481 | if (sizealloc < tp->b_bufsize) { | |
482 | rmfree(buffermap, (long)(tp->b_bufsize - sizealloc), | |
483 | (long)(tp->b_un.b_addr + sizealloc)); | |
484 | tp->b_bufsize = sizealloc; | |
485 | goto out; | |
486 | } | |
487 | /* | |
488 | * Buffer is being expanded or created | |
489 | * If being expanded, attempt to get contiguous | |
490 | * section, otherwise get a new chunk and copy. | |
491 | * If no space, free up a buffer on the AGE list | |
492 | * and try again. | |
493 | */ | |
494 | do { | |
495 | if ((osize = tp->b_bufsize)) { | |
496 | a = (char *)rmget(buffermap, (long)(sizealloc-osize), | |
497 | (long)(tp->b_un.b_addr + osize)); | |
498 | if (a == 0) { | |
499 | a = (char *)rmalloc(buffermap, (long)sizealloc); | |
500 | if (a != 0) { | |
501 | bcopy(tp->b_un.b_addr, a, osize); | |
502 | rmfree(buffermap, (long)osize, | |
503 | (long)tp->b_un.b_addr); | |
504 | tp->b_un.b_addr = a; | |
505 | } | |
506 | } | |
507 | } else { | |
508 | a = (char *)rmalloc(buffermap, (long)sizealloc); | |
509 | if (a != 0) | |
510 | tp->b_un.b_addr = a; | |
511 | } | |
512 | } while (a == 0 && bfreemem()); | |
513 | if (a == 0) { | |
514 | brelse(tp); | |
515 | return (0); | |
516 | } | |
517 | tp->b_bufsize = sizealloc; | |
518 | #endif | |
4f083fd7 SL |
519 | out: |
520 | tp->b_bcount = size; | |
961945a8 | 521 | return (1); |
ad30fb67 KM |
522 | } |
523 | ||
524 | /* | |
525 | * Release space associated with a buffer. | |
526 | */ | |
527 | bfree(bp) | |
528 | struct buf *bp; | |
529 | { | |
961945a8 SL |
530 | #ifdef sun |
531 | if (bp->b_bufsize) { | |
532 | rmfree(buffermap, (long)bp->b_bufsize, (long)bp->b_un.b_addr); | |
533 | bp->b_bufsize = 0; | |
534 | } | |
535 | #endif | |
ad30fb67 KM |
536 | bp->b_bcount = 0; |
537 | } | |
538 | ||
961945a8 SL |
539 | #ifdef sun |
540 | /* | |
541 | * Attempt to free up buffer space by flushing | |
542 | * something in the free list. | |
543 | * Don't wait for something, that could cause deadlocks | |
544 | * We start with BQ_AGE because we know BQ_EMPTY take no memory. | |
545 | */ | |
546 | bfreemem() | |
547 | { | |
548 | register struct buf *bp, *dp; | |
549 | int s; | |
550 | ||
551 | loop: | |
552 | s = spl6(); | |
553 | for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) | |
554 | if (dp->av_forw != dp) | |
555 | break; | |
556 | splx(s); | |
557 | if (dp == bfreelist) { /* no free blocks */ | |
558 | return (0); | |
559 | } | |
560 | bp = dp->av_forw; | |
561 | notavail(bp); | |
562 | if (bp->b_flags & B_DELWRI) { | |
563 | bp->b_flags |= B_ASYNC; | |
564 | bwrite(bp); | |
565 | goto loop; | |
566 | } | |
567 | trace(TR_BRELSE, bp->b_dev, bp->b_blkno); | |
568 | bp->b_flags = B_BUSY | B_INVAL; | |
569 | bfree(bp); | |
570 | bremhash(bp); | |
571 | binshash(bp, &bfreelist[BQ_EMPTY]); | |
572 | bp->b_dev = (dev_t)NODEV; | |
573 | bp->b_error = 0; | |
574 | brelse(bp); | |
575 | return (1); | |
576 | } | |
577 | #endif | |
578 | ||
4f083fd7 SL |
579 | /* |
580 | * Find a buffer which is available for use. | |
581 | * Select something from a free list. | |
582 | * Preference is to AGE list, then LRU list. | |
583 | */ | |
584 | struct buf * | |
585 | getnewbuf() | |
586 | { | |
587 | register struct buf *bp, *dp; | |
588 | int s; | |
589 | ||
590 | loop: | |
591 | s = spl6(); | |
961945a8 | 592 | #ifndef sun |
4f083fd7 | 593 | for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) |
961945a8 SL |
594 | #else |
595 | for (dp = &bfreelist[BQ_EMPTY]; dp > bfreelist; dp--) | |
596 | #endif | |
4f083fd7 SL |
597 | if (dp->av_forw != dp) |
598 | break; | |
599 | if (dp == bfreelist) { /* no free blocks */ | |
600 | dp->b_flags |= B_WANTED; | |
601 | sleep((caddr_t)dp, PRIBIO+1); | |
602 | goto loop; | |
603 | } | |
604 | splx(s); | |
605 | bp = dp->av_forw; | |
606 | notavail(bp); | |
607 | if (bp->b_flags & B_DELWRI) { | |
608 | bp->b_flags |= B_ASYNC; | |
609 | bwrite(bp); | |
610 | goto loop; | |
611 | } | |
612 | trace(TR_BRELSE, bp->b_dev, bp->b_blkno); | |
613 | bp->b_flags = B_BUSY; | |
614 | return (bp); | |
615 | } | |
616 | ||
663dbc72 BJ |
617 | /* |
618 | * Wait for I/O completion on the buffer; return errors | |
619 | * to the user. | |
620 | */ | |
3efdd860 | 621 | biowait(bp) |
ad30fb67 | 622 | register struct buf *bp; |
663dbc72 | 623 | { |
530d0032 | 624 | int s; |
663dbc72 | 625 | |
530d0032 | 626 | s = spl6(); |
663dbc72 BJ |
627 | while ((bp->b_flags&B_DONE)==0) |
628 | sleep((caddr_t)bp, PRIBIO); | |
530d0032 | 629 | splx(s); |
d6d7360b | 630 | u.u_error = geterror(bp); |
663dbc72 BJ |
631 | } |
632 | ||
663dbc72 BJ |
633 | /* |
634 | * Mark I/O complete on a buffer. If the header | |
635 | * indicates a dirty page push completion, the | |
636 | * header is inserted into the ``cleaned'' list | |
637 | * to be processed by the pageout daemon. Otherwise | |
638 | * release it if I/O is asynchronous, and wake | |
639 | * up anyone waiting for it. | |
640 | */ | |
3efdd860 KM |
641 | biodone(bp) |
642 | register struct buf *bp; | |
663dbc72 BJ |
643 | { |
644 | register int s; | |
645 | ||
80e7c811 | 646 | if (bp->b_flags & B_DONE) |
3efdd860 | 647 | panic("dup biodone"); |
663dbc72 BJ |
648 | bp->b_flags |= B_DONE; |
649 | if (bp->b_flags & B_DIRTY) { | |
650 | if (bp->b_flags & B_ERROR) | |
651 | panic("IO err in push"); | |
652 | s = spl6(); | |
663dbc72 BJ |
653 | bp->av_forw = bclnlist; |
654 | bp->b_bcount = swsize[bp - swbuf]; | |
655 | bp->b_pfcent = swpf[bp - swbuf]; | |
796c66c0 BJ |
656 | cnt.v_pgout++; |
657 | cnt.v_pgpgout += bp->b_bcount / NBPG; | |
663dbc72 BJ |
658 | bclnlist = bp; |
659 | if (bswlist.b_flags & B_WANTED) | |
660 | wakeup((caddr_t)&proc[2]); | |
661 | splx(s); | |
a3ee1d55 | 662 | return; |
663dbc72 | 663 | } |
961945a8 SL |
664 | if (bp->b_flags & B_CALL) { |
665 | bp->b_flags &= ~B_CALL; | |
666 | (*bp->b_iodone)(bp); | |
667 | return; | |
668 | } | |
663dbc72 BJ |
669 | if (bp->b_flags&B_ASYNC) |
670 | brelse(bp); | |
671 | else { | |
672 | bp->b_flags &= ~B_WANTED; | |
673 | wakeup((caddr_t)bp); | |
674 | } | |
675 | } | |
676 | ||
4f083fd7 SL |
677 | /* |
678 | * Insure that no part of a specified block is in an incore buffer. | |
679 | */ | |
680 | blkflush(dev, blkno, size) | |
681 | dev_t dev; | |
682 | daddr_t blkno; | |
683 | long size; | |
684 | { | |
685 | register struct buf *ep; | |
686 | struct buf *dp; | |
687 | daddr_t start, last; | |
688 | int s; | |
689 | ||
690 | start = blkno; | |
691 | last = start + (size / DEV_BSIZE) - 1; | |
692 | dp = BUFHASH(dev, blkno); | |
693 | loop: | |
694 | for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { | |
695 | if (ep->b_dev != dev || (ep->b_flags&B_INVAL)) | |
696 | continue; | |
697 | /* look for overlap */ | |
698 | if (ep->b_bcount == 0 || ep->b_blkno > last || | |
699 | ep->b_blkno + (ep->b_bcount / DEV_BSIZE) <= start) | |
700 | continue; | |
701 | s = spl6(); | |
702 | if (ep->b_flags&B_BUSY) { | |
703 | ep->b_flags |= B_WANTED; | |
704 | sleep((caddr_t)ep, PRIBIO+1); | |
705 | splx(s); | |
706 | goto loop; | |
707 | } | |
708 | if (ep->b_flags & B_DELWRI) { | |
709 | splx(s); | |
710 | notavail(ep); | |
711 | bwrite(ep); | |
712 | goto loop; | |
713 | } | |
714 | splx(s); | |
715 | } | |
716 | } | |
717 | ||
663dbc72 BJ |
718 | /* |
719 | * make sure all write-behind blocks | |
720 | * on dev (or NODEV for all) | |
721 | * are flushed out. | |
722 | * (from umount and update) | |
ad30fb67 | 723 | * (and temporarily pagein) |
663dbc72 BJ |
724 | */ |
725 | bflush(dev) | |
3efdd860 | 726 | dev_t dev; |
663dbc72 BJ |
727 | { |
728 | register struct buf *bp; | |
46387ee3 | 729 | register struct buf *flist; |
530d0032 | 730 | int s; |
663dbc72 BJ |
731 | |
732 | loop: | |
530d0032 | 733 | s = spl6(); |
4f083fd7 | 734 | for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) |
46387ee3 | 735 | for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { |
3efdd860 KM |
736 | if ((bp->b_flags & B_DELWRI) == 0) |
737 | continue; | |
738 | if (dev == NODEV || dev == bp->b_dev) { | |
663dbc72 BJ |
739 | bp->b_flags |= B_ASYNC; |
740 | notavail(bp); | |
741 | bwrite(bp); | |
742 | goto loop; | |
743 | } | |
744 | } | |
530d0032 | 745 | splx(s); |
663dbc72 BJ |
746 | } |
747 | ||
663dbc72 BJ |
748 | /* |
749 | * Pick up the device's error number and pass it to the user; | |
750 | * if there is an error but the number is 0 set a generalized | |
751 | * code. Actually the latter is always true because devices | |
752 | * don't yet return specific errors. | |
753 | */ | |
754 | geterror(bp) | |
3efdd860 | 755 | register struct buf *bp; |
663dbc72 | 756 | { |
d6d7360b | 757 | int error = 0; |
663dbc72 BJ |
758 | |
759 | if (bp->b_flags&B_ERROR) | |
d6d7360b BJ |
760 | if ((error = bp->b_error)==0) |
761 | return (EIO); | |
762 | return (error); | |
663dbc72 | 763 | } |
7b8b5a01 RE |
764 | |
765 | /* | |
766 | * Invalidate in core blocks belonging to closed or umounted filesystem | |
767 | * | |
768 | * This is not nicely done at all - the buffer ought to be removed from the | |
769 | * hash chains & have its dev/blkno fields clobbered, but unfortunately we | |
770 | * can't do that here, as it is quite possible that the block is still | |
771 | * being used for i/o. Eventually, all disc drivers should be forced to | |
772 | * have a close routine, which ought ensure that the queue is empty, then | |
773 | * properly flush the queues. Until that happy day, this suffices for | |
774 | * correctness. ... kre | |
775 | */ | |
776 | binval(dev) | |
3efdd860 | 777 | dev_t dev; |
7b8b5a01 | 778 | { |
634ebdbe RE |
779 | register struct buf *bp; |
780 | register struct bufhd *hp; | |
781 | #define dp ((struct buf *)hp) | |
7b8b5a01 | 782 | |
634ebdbe RE |
783 | for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++) |
784 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) | |
785 | if (bp->b_dev == dev) | |
786 | bp->b_flags |= B_INVAL; | |
7b8b5a01 | 787 | } |