Commit | Line | Data |
---|---|---|
5dc2581e KB |
1 | /*- |
2 | * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. | |
7188ac27 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
217c3be4 KM |
5 | * This module is believed to contain source code proprietary to AT&T. |
6 | * Use and redistribution is subject to the Berkeley Software License | |
7 | * Agreement and your Software Agreement with AT&T (Western Electric). | |
7188ac27 | 8 | * |
ea67b335 | 9 | * @(#)vfs_cluster.c 7.47 (Berkeley) %G% |
da7c5cc6 | 10 | */ |
961945a8 | 11 | |
251f56ba KB |
12 | #include <sys/param.h> |
13 | #include <sys/proc.h> | |
14 | #include <sys/buf.h> | |
15 | #include <sys/vnode.h> | |
16 | #include <sys/specdev.h> | |
17 | #include <sys/mount.h> | |
18 | #include <sys/trace.h> | |
19 | #include <sys/resourcevar.h> | |
663dbc72 | 20 | |
e7db227e MK |
21 | /* |
22 | * Initialize buffers and hash links for buffers. | |
23 | */ | |
251f56ba | 24 | void |
e7db227e MK |
25 | bufinit() |
26 | { | |
27 | register int i; | |
28 | register struct buf *bp, *dp; | |
29 | register struct bufhd *hp; | |
30 | int base, residual; | |
31 | ||
32 | for (hp = bufhash, i = 0; i < BUFHSZ; i++, hp++) | |
33 | hp->b_forw = hp->b_back = (struct buf *)hp; | |
34 | ||
35 | for (dp = bfreelist; dp < &bfreelist[BQUEUES]; dp++) { | |
36 | dp->b_forw = dp->b_back = dp->av_forw = dp->av_back = dp; | |
37 | dp->b_flags = B_HEAD; | |
38 | } | |
39 | base = bufpages / nbuf; | |
40 | residual = bufpages % nbuf; | |
41 | for (i = 0; i < nbuf; i++) { | |
42 | bp = &buf[i]; | |
43 | bp->b_dev = NODEV; | |
44 | bp->b_bcount = 0; | |
45 | bp->b_rcred = NOCRED; | |
46 | bp->b_wcred = NOCRED; | |
47 | bp->b_dirtyoff = 0; | |
48 | bp->b_dirtyend = 0; | |
bb1626f7 KM |
49 | bp->b_validoff = 0; |
50 | bp->b_validend = 0; | |
e7db227e MK |
51 | bp->b_un.b_addr = buffers + i * MAXBSIZE; |
52 | if (i < residual) | |
53 | bp->b_bufsize = (base + 1) * CLBYTES; | |
54 | else | |
55 | bp->b_bufsize = base * CLBYTES; | |
56 | binshash(bp, &bfreelist[BQ_AGE]); | |
31222d0d CT |
57 | bp->b_flags = B_INVAL; |
58 | dp = bp->b_bufsize ? &bfreelist[BQ_AGE] : &bfreelist[BQ_EMPTY]; | |
59 | binsheadfree(bp, dp); | |
e7db227e MK |
60 | } |
61 | } | |
62 | ||
663dbc72 | 63 | /* |
d42a4811 KM |
64 | * Find the block in the buffer pool. |
65 | * If the buffer is not present, allocate a new buffer and load | |
66 | * its contents according to the filesystem fill routine. | |
663dbc72 | 67 | */ |
a937f856 | 68 | bread(vp, blkno, size, cred, bpp) |
7188ac27 | 69 | struct vnode *vp; |
ad30fb67 KM |
70 | daddr_t blkno; |
71 | int size; | |
a937f856 | 72 | struct ucred *cred; |
7188ac27 | 73 | struct buf **bpp; |
ec67a3ce MK |
74 | #ifdef SECSIZE |
75 | long secsize; | |
76 | #endif SECSIZE | |
663dbc72 | 77 | { |
9342689a | 78 | USES_VOP_STRATEGY; |
3789a403 | 79 | struct proc *p = curproc; /* XXX */ |
663dbc72 BJ |
80 | register struct buf *bp; |
81 | ||
4f083fd7 SL |
82 | if (size == 0) |
83 | panic("bread: size 0"); | |
ec67a3ce MK |
84 | #ifdef SECSIZE |
85 | bp = getblk(dev, blkno, size, secsize); | |
86 | #else SECSIZE | |
7188ac27 | 87 | *bpp = bp = getblk(vp, blkno, size); |
ec67a3ce | 88 | #endif SECSIZE |
d42a4811 | 89 | if (bp->b_flags & (B_DONE | B_DELWRI)) { |
c5a600cf | 90 | trace(TR_BREADHIT, pack(vp, size), blkno); |
7188ac27 | 91 | return (0); |
663dbc72 BJ |
92 | } |
93 | bp->b_flags |= B_READ; | |
4f083fd7 SL |
94 | if (bp->b_bcount > bp->b_bufsize) |
95 | panic("bread"); | |
a937f856 KM |
96 | if (bp->b_rcred == NOCRED && cred != NOCRED) { |
97 | crhold(cred); | |
98 | bp->b_rcred = cred; | |
99 | } | |
7188ac27 | 100 | VOP_STRATEGY(bp); |
c5a600cf | 101 | trace(TR_BREADMISS, pack(vp, size), blkno); |
3789a403 | 102 | p->p_stats->p_ru.ru_inblock++; /* pay for read */ |
7188ac27 | 103 | return (biowait(bp)); |
663dbc72 BJ |
104 | } |
105 | ||
106 | /* | |
bb1626f7 KM |
107 | * Operates like bread, but also starts I/O on the N specified |
108 | * read-ahead blocks. | |
663dbc72 | 109 | */ |
bb1626f7 | 110 | breadn(vp, blkno, size, rablkno, rabsize, num, cred, bpp) |
7188ac27 | 111 | struct vnode *vp; |
84baaab3 | 112 | daddr_t blkno; int size; |
ec67a3ce MK |
113 | #ifdef SECSIZE |
114 | long secsize; | |
115 | #endif SECSIZE | |
bb1626f7 KM |
116 | daddr_t rablkno[]; int rabsize[]; |
117 | int num; | |
a937f856 | 118 | struct ucred *cred; |
7188ac27 | 119 | struct buf **bpp; |
663dbc72 | 120 | { |
9342689a | 121 | USES_VOP_STRATEGY; |
3789a403 | 122 | struct proc *p = curproc; /* XXX */ |
663dbc72 | 123 | register struct buf *bp, *rabp; |
bb1626f7 | 124 | register int i; |
663dbc72 BJ |
125 | |
126 | bp = NULL; | |
3efdd860 | 127 | /* |
d42a4811 KM |
128 | * If the block is not memory resident, |
129 | * allocate a buffer and start I/O. | |
3efdd860 | 130 | */ |
7188ac27 KM |
131 | if (!incore(vp, blkno)) { |
132 | *bpp = bp = getblk(vp, blkno, size); | |
ec67a3ce | 133 | #endif SECSIZE |
d42a4811 | 134 | if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) { |
663dbc72 | 135 | bp->b_flags |= B_READ; |
4f083fd7 | 136 | if (bp->b_bcount > bp->b_bufsize) |
bb1626f7 | 137 | panic("breadn"); |
a937f856 KM |
138 | if (bp->b_rcred == NOCRED && cred != NOCRED) { |
139 | crhold(cred); | |
140 | bp->b_rcred = cred; | |
141 | } | |
7188ac27 | 142 | VOP_STRATEGY(bp); |
c5a600cf | 143 | trace(TR_BREADMISS, pack(vp, size), blkno); |
3789a403 | 144 | p->p_stats->p_ru.ru_inblock++; /* pay for read */ |
3efdd860 | 145 | } else |
c5a600cf | 146 | trace(TR_BREADHIT, pack(vp, size), blkno); |
663dbc72 | 147 | } |
3efdd860 KM |
148 | |
149 | /* | |
bb1626f7 KM |
150 | * If there's read-ahead block(s), start I/O |
151 | * on them also (as above). | |
3efdd860 | 152 | */ |
bb1626f7 KM |
153 | for (i = 0; i < num; i++) { |
154 | if (incore(vp, rablkno[i])) | |
155 | continue; | |
156 | rabp = getblk(vp, rablkno[i], rabsize[i]); | |
ec67a3ce | 157 | #endif SECSIZE |
d42a4811 | 158 | if (rabp->b_flags & (B_DONE | B_DELWRI)) { |
663dbc72 | 159 | brelse(rabp); |
bb1626f7 | 160 | trace(TR_BREADHITRA, pack(vp, rabsize[i]), rablkno[i]); |
973ecc4f | 161 | } else { |
d42a4811 | 162 | rabp->b_flags |= B_ASYNC | B_READ; |
4f083fd7 SL |
163 | if (rabp->b_bcount > rabp->b_bufsize) |
164 | panic("breadrabp"); | |
5062ac4a | 165 | if (rabp->b_rcred == NOCRED && cred != NOCRED) { |
a937f856 | 166 | crhold(cred); |
5062ac4a | 167 | rabp->b_rcred = cred; |
a937f856 | 168 | } |
7188ac27 | 169 | VOP_STRATEGY(rabp); |
bb1626f7 | 170 | trace(TR_BREADMISSRA, pack(vp, rabsize[i]), rablkno[i]); |
3789a403 | 171 | p->p_stats->p_ru.ru_inblock++; /* pay in advance */ |
663dbc72 BJ |
172 | } |
173 | } | |
3efdd860 KM |
174 | |
175 | /* | |
d42a4811 KM |
176 | * If block was memory resident, let bread get it. |
177 | * If block was not memory resident, the read was | |
178 | * started above, so just wait for the read to complete. | |
3efdd860 | 179 | */ |
84baaab3 | 180 | if (bp == NULL) |
ec67a3ce MK |
181 | #ifdef SECSIZE |
182 | return (bread(dev, blkno, size, secsize)); | |
183 | #else SECSIZE | |
a937f856 | 184 | return (bread(vp, blkno, size, cred, bpp)); |
7188ac27 | 185 | return (biowait(bp)); |
663dbc72 BJ |
186 | } |
187 | ||
188 | /* | |
d42a4811 KM |
189 | * Synchronous write. |
190 | * Release buffer on completion. | |
663dbc72 BJ |
191 | */ |
192 | bwrite(bp) | |
3efdd860 | 193 | register struct buf *bp; |
663dbc72 | 194 | { |
9342689a | 195 | USES_VOP_STRATEGY; |
3789a403 | 196 | struct proc *p = curproc; /* XXX */ |
7188ac27 | 197 | register int flag; |
31222d0d | 198 | int s, error = 0; |
663dbc72 BJ |
199 | |
200 | flag = bp->b_flags; | |
f844ee62 | 201 | bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); |
77dc8a8c KM |
202 | if (flag & B_ASYNC) { |
203 | if ((flag & B_DELWRI) == 0) | |
204 | p->p_stats->p_ru.ru_oublock++; /* no one paid yet */ | |
205 | else | |
206 | reassignbuf(bp, bp->b_vp); | |
207 | } | |
c5a600cf | 208 | trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno); |
4f083fd7 SL |
209 | if (bp->b_bcount > bp->b_bufsize) |
210 | panic("bwrite"); | |
86e7dd3b | 211 | s = splbio(); |
c669f646 | 212 | bp->b_vp->v_numoutput++; |
86e7dd3b | 213 | splx(s); |
7188ac27 | 214 | VOP_STRATEGY(bp); |
3efdd860 KM |
215 | |
216 | /* | |
d42a4811 | 217 | * If the write was synchronous, then await I/O completion. |
3efdd860 | 218 | * If the write was "delayed", then we put the buffer on |
d42a4811 | 219 | * the queue of blocks awaiting I/O completion status. |
3efdd860 | 220 | */ |
d42a4811 | 221 | if ((flag & B_ASYNC) == 0) { |
7188ac27 | 222 | error = biowait(bp); |
77dc8a8c KM |
223 | if ((flag&B_DELWRI) == 0) |
224 | p->p_stats->p_ru.ru_oublock++; /* no one paid yet */ | |
225 | else | |
226 | reassignbuf(bp, bp->b_vp); | |
663dbc72 | 227 | brelse(bp); |
7188ac27 | 228 | } else if (flag & B_DELWRI) { |
31222d0d | 229 | s = splbio(); |
663dbc72 | 230 | bp->b_flags |= B_AGE; |
31222d0d | 231 | splx(s); |
7188ac27 KM |
232 | } |
233 | return (error); | |
663dbc72 BJ |
234 | } |
235 | ||
236 | /* | |
d42a4811 KM |
237 | * Delayed write. |
238 | * | |
239 | * The buffer is marked dirty, but is not queued for I/O. | |
240 | * This routine should be used when the buffer is expected | |
241 | * to be modified again soon, typically a small write that | |
242 | * partially fills a buffer. | |
243 | * | |
244 | * NB: magnetic tapes cannot be delayed; they must be | |
245 | * written in the order that the writes are requested. | |
663dbc72 BJ |
246 | */ |
247 | bdwrite(bp) | |
3efdd860 | 248 | register struct buf *bp; |
663dbc72 | 249 | { |
9342689a | 250 | USES_VOP_IOCTL; |
3789a403 | 251 | struct proc *p = curproc; /* XXX */ |
663dbc72 | 252 | |
c669f646 KM |
253 | if ((bp->b_flags & B_DELWRI) == 0) { |
254 | bp->b_flags |= B_DELWRI; | |
255 | reassignbuf(bp, bp->b_vp); | |
3789a403 | 256 | p->p_stats->p_ru.ru_oublock++; /* no one paid yet */ |
c669f646 | 257 | } |
7188ac27 | 258 | /* |
edadbc2c | 259 | * If this is a tape drive, the write must be initiated. |
7188ac27 | 260 | */ |
ec67a3ce | 261 | if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE) |
663dbc72 | 262 | bawrite(bp); |
edadbc2c | 263 | } else { |
d42a4811 | 264 | bp->b_flags |= (B_DONE | B_DELWRI); |
663dbc72 BJ |
265 | brelse(bp); |
266 | } | |
267 | } | |
268 | ||
269 | /* | |
d42a4811 KM |
270 | * Asynchronous write. |
271 | * Start I/O on a buffer, but do not wait for it to complete. | |
272 | * The buffer is released when the I/O completes. | |
663dbc72 BJ |
273 | */ |
274 | bawrite(bp) | |
3efdd860 | 275 | register struct buf *bp; |
663dbc72 BJ |
276 | { |
277 | ||
d42a4811 KM |
278 | /* |
279 | * Setting the ASYNC flag causes bwrite to return | |
280 | * after starting the I/O. | |
281 | */ | |
663dbc72 | 282 | bp->b_flags |= B_ASYNC; |
7188ac27 | 283 | (void) bwrite(bp); |
663dbc72 BJ |
284 | } |
285 | ||
286 | /* | |
d42a4811 KM |
287 | * Release a buffer. |
288 | * Even if the buffer is dirty, no I/O is started. | |
663dbc72 BJ |
289 | */ |
290 | brelse(bp) | |
3efdd860 | 291 | register struct buf *bp; |
663dbc72 | 292 | { |
46387ee3 | 293 | register struct buf *flist; |
d42a4811 | 294 | int s; |
663dbc72 | 295 | |
c5a600cf | 296 | trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); |
3efdd860 | 297 | /* |
edadbc2c KM |
298 | * If a process is waiting for the buffer, or |
299 | * is waiting for a free buffer, awaken it. | |
3efdd860 | 300 | */ |
d42a4811 | 301 | if (bp->b_flags & B_WANTED) |
663dbc72 | 302 | wakeup((caddr_t)bp); |
d42a4811 | 303 | if (bfreelist[0].b_flags & B_WANTED) { |
46387ee3 BJ |
304 | bfreelist[0].b_flags &= ~B_WANTED; |
305 | wakeup((caddr_t)bfreelist); | |
663dbc72 | 306 | } |
edadbc2c KM |
307 | /* |
308 | * Retry I/O for locked buffers rather than invalidating them. | |
309 | */ | |
31222d0d | 310 | s = splbio(); |
edadbc2c KM |
311 | if ((bp->b_flags & B_ERROR) && (bp->b_flags & B_LOCKED)) |
312 | bp->b_flags &= ~B_ERROR; | |
edadbc2c KM |
313 | /* |
314 | * Disassociate buffers that are no longer valid. | |
315 | */ | |
d42a4811 | 316 | if (bp->b_flags & (B_NOCACHE | B_ERROR)) |
7188ac27 | 317 | bp->b_flags |= B_INVAL; |
d42a4811 | 318 | if ((bp->b_bufsize <= 0) || (bp->b_flags & (B_ERROR | B_INVAL))) { |
edadbc2c KM |
319 | if (bp->b_vp) |
320 | brelvp(bp); | |
321 | bp->b_flags &= ~B_DELWRI; | |
7188ac27 | 322 | } |
3efdd860 KM |
323 | /* |
324 | * Stick the buffer back on a free list. | |
325 | */ | |
4f083fd7 SL |
326 | if (bp->b_bufsize <= 0) { |
327 | /* block has no buffer ... put at front of unused buffer list */ | |
328 | flist = &bfreelist[BQ_EMPTY]; | |
329 | binsheadfree(bp, flist); | |
d42a4811 | 330 | } else if (bp->b_flags & (B_ERROR | B_INVAL)) { |
46387ee3 | 331 | /* block has no info ... put at front of most free list */ |
4f083fd7 | 332 | flist = &bfreelist[BQ_AGE]; |
3efdd860 | 333 | binsheadfree(bp, flist); |
663dbc72 | 334 | } else { |
46387ee3 BJ |
335 | if (bp->b_flags & B_LOCKED) |
336 | flist = &bfreelist[BQ_LOCKED]; | |
337 | else if (bp->b_flags & B_AGE) | |
338 | flist = &bfreelist[BQ_AGE]; | |
339 | else | |
340 | flist = &bfreelist[BQ_LRU]; | |
3efdd860 | 341 | binstailfree(bp, flist); |
663dbc72 | 342 | } |
d42a4811 | 343 | bp->b_flags &= ~(B_WANTED | B_BUSY | B_ASYNC | B_AGE | B_NOCACHE); |
663dbc72 BJ |
344 | splx(s); |
345 | } | |
346 | ||
347 | /* | |
d42a4811 | 348 | * Check to see if a block is currently memory resident. |
663dbc72 | 349 | */ |
7188ac27 KM |
350 | incore(vp, blkno) |
351 | struct vnode *vp; | |
3efdd860 | 352 | daddr_t blkno; |
663dbc72 BJ |
353 | { |
354 | register struct buf *bp; | |
46387ee3 | 355 | register struct buf *dp; |
663dbc72 | 356 | |
243d4743 | 357 | dp = BUFHASH(vp, blkno); |
46387ee3 | 358 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) |
edadbc2c | 359 | if (bp->b_lblkno == blkno && bp->b_vp == vp && |
3efdd860 | 360 | (bp->b_flags & B_INVAL) == 0) |
5603d07d | 361 | return (1); |
5603d07d | 362 | return (0); |
663dbc72 BJ |
363 | } |
364 | ||
edadbc2c | 365 | /* |
d42a4811 KM |
366 | * Check to see if a block is currently memory resident. |
367 | * If it is resident, return it. If it is not resident, | |
368 | * allocate a new buffer and assign it to the block. | |
663dbc72 BJ |
369 | */ |
370 | struct buf * | |
ec67a3ce MK |
371 | #ifdef SECSIZE |
372 | getblk(dev, blkno, size, secsize) | |
373 | #else SECSIZE | |
7188ac27 KM |
374 | getblk(vp, blkno, size) |
375 | register struct vnode *vp; | |
ad30fb67 KM |
376 | daddr_t blkno; |
377 | int size; | |
ec67a3ce MK |
378 | #ifdef SECSIZE |
379 | long secsize; | |
380 | #endif SECSIZE | |
663dbc72 | 381 | { |
4f083fd7 | 382 | register struct buf *bp, *dp; |
23900030 | 383 | int s; |
663dbc72 | 384 | |
00a6a148 KM |
385 | if (size > MAXBSIZE) |
386 | panic("getblk: size too big"); | |
3efdd860 | 387 | /* |
d42a4811 KM |
388 | * Search the cache for the block. If the buffer is found, |
389 | * but it is currently locked, the we must wait for it to | |
390 | * become available. | |
3efdd860 | 391 | */ |
7188ac27 | 392 | dp = BUFHASH(vp, blkno); |
3efdd860 | 393 | loop: |
46387ee3 | 394 | for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { |
edadbc2c | 395 | if (bp->b_lblkno != blkno || bp->b_vp != vp || |
d42a4811 | 396 | (bp->b_flags & B_INVAL)) |
663dbc72 | 397 | continue; |
a5e62f37 | 398 | s = splbio(); |
d42a4811 | 399 | if (bp->b_flags & B_BUSY) { |
663dbc72 | 400 | bp->b_flags |= B_WANTED; |
d42a4811 | 401 | sleep((caddr_t)bp, PRIBIO + 1); |
23900030 | 402 | splx(s); |
663dbc72 BJ |
403 | goto loop; |
404 | } | |
c669f646 KM |
405 | bremfree(bp); |
406 | bp->b_flags |= B_BUSY; | |
23900030 | 407 | splx(s); |
32a56bda | 408 | if (bp->b_bcount != size) { |
edadbc2c KM |
409 | printf("getblk: stray size"); |
410 | bp->b_flags |= B_INVAL; | |
411 | bwrite(bp); | |
9d6d37ce | 412 | goto loop; |
edadbc2c | 413 | } |
663dbc72 | 414 | bp->b_flags |= B_CACHE; |
a5e62f37 | 415 | return (bp); |
663dbc72 | 416 | } |
4f083fd7 | 417 | bp = getnewbuf(); |
3efdd860 | 418 | bremhash(bp); |
edadbc2c | 419 | bgetvp(vp, bp); |
521a4688 | 420 | bp->b_bcount = 0; |
edadbc2c | 421 | bp->b_lblkno = blkno; |
ec67a3ce MK |
422 | #ifdef SECSIZE |
423 | bp->b_blksize = secsize; | |
424 | #endif SECSIZE | |
ad30fb67 | 425 | bp->b_blkno = blkno; |
4f083fd7 | 426 | bp->b_error = 0; |
7188ac27 KM |
427 | bp->b_resid = 0; |
428 | binshash(bp, dp); | |
521a4688 | 429 | allocbuf(bp, size); |
a5e62f37 | 430 | return (bp); |
663dbc72 BJ |
431 | } |
432 | ||
433 | /* | |
d42a4811 KM |
434 | * Allocate a buffer. |
435 | * The caller will assign it to a block. | |
663dbc72 BJ |
436 | */ |
437 | struct buf * | |
ad30fb67 KM |
438 | geteblk(size) |
439 | int size; | |
663dbc72 | 440 | { |
4f083fd7 | 441 | register struct buf *bp, *flist; |
663dbc72 | 442 | |
00a6a148 KM |
443 | if (size > MAXBSIZE) |
444 | panic("geteblk: size too big"); | |
4f083fd7 SL |
445 | bp = getnewbuf(); |
446 | bp->b_flags |= B_INVAL; | |
3efdd860 | 447 | bremhash(bp); |
4f083fd7 | 448 | flist = &bfreelist[BQ_AGE]; |
521a4688 | 449 | bp->b_bcount = 0; |
ec67a3ce MK |
450 | #ifdef SECSIZE |
451 | bp->b_blksize = DEV_BSIZE; | |
452 | #endif SECSIZE | |
4f083fd7 | 453 | bp->b_error = 0; |
7188ac27 KM |
454 | bp->b_resid = 0; |
455 | binshash(bp, flist); | |
521a4688 | 456 | allocbuf(bp, size); |
a5e62f37 | 457 | return (bp); |
663dbc72 BJ |
458 | } |
459 | ||
ad30fb67 | 460 | /* |
521a4688 | 461 | * Expand or contract the actual memory allocated to a buffer. |
d42a4811 | 462 | * If no memory is available, release buffer and take error exit. |
ad30fb67 | 463 | */ |
521a4688 KM |
464 | allocbuf(tp, size) |
465 | register struct buf *tp; | |
ad30fb67 KM |
466 | int size; |
467 | { | |
521a4688 KM |
468 | register struct buf *bp, *ep; |
469 | int sizealloc, take, s; | |
ad30fb67 | 470 | |
521a4688 KM |
471 | sizealloc = roundup(size, CLBYTES); |
472 | /* | |
473 | * Buffer size does not change | |
474 | */ | |
475 | if (sizealloc == tp->b_bufsize) | |
476 | goto out; | |
477 | /* | |
478 | * Buffer size is shrinking. | |
479 | * Place excess space in a buffer header taken from the | |
480 | * BQ_EMPTY buffer list and placed on the "most free" list. | |
481 | * If no extra buffer headers are available, leave the | |
482 | * extra space in the present buffer. | |
483 | */ | |
484 | if (sizealloc < tp->b_bufsize) { | |
485 | ep = bfreelist[BQ_EMPTY].av_forw; | |
486 | if (ep == &bfreelist[BQ_EMPTY]) | |
487 | goto out; | |
488 | s = splbio(); | |
489 | bremfree(ep); | |
490 | ep->b_flags |= B_BUSY; | |
491 | splx(s); | |
492 | pagemove(tp->b_un.b_addr + sizealloc, ep->b_un.b_addr, | |
493 | (int)tp->b_bufsize - sizealloc); | |
494 | ep->b_bufsize = tp->b_bufsize - sizealloc; | |
495 | tp->b_bufsize = sizealloc; | |
496 | ep->b_flags |= B_INVAL; | |
497 | ep->b_bcount = 0; | |
498 | brelse(ep); | |
499 | goto out; | |
500 | } | |
501 | /* | |
502 | * More buffer space is needed. Get it out of buffers on | |
503 | * the "most free" list, placing the empty headers on the | |
504 | * BQ_EMPTY buffer header list. | |
505 | */ | |
506 | while (tp->b_bufsize < sizealloc) { | |
507 | take = sizealloc - tp->b_bufsize; | |
508 | bp = getnewbuf(); | |
509 | if (take >= bp->b_bufsize) | |
510 | take = bp->b_bufsize; | |
511 | pagemove(&bp->b_un.b_addr[bp->b_bufsize - take], | |
512 | &tp->b_un.b_addr[tp->b_bufsize], take); | |
513 | tp->b_bufsize += take; | |
514 | bp->b_bufsize = bp->b_bufsize - take; | |
515 | if (bp->b_bcount > bp->b_bufsize) | |
516 | bp->b_bcount = bp->b_bufsize; | |
517 | if (bp->b_bufsize <= 0) { | |
518 | bremhash(bp); | |
519 | binshash(bp, &bfreelist[BQ_EMPTY]); | |
d42a4811 | 520 | bp->b_dev = NODEV; |
521a4688 KM |
521 | bp->b_error = 0; |
522 | bp->b_flags |= B_INVAL; | |
523 | } | |
524 | brelse(bp); | |
525 | } | |
526 | out: | |
527 | tp->b_bcount = size; | |
528 | return (1); | |
4f083fd7 SL |
529 | } |
530 | ||
4f083fd7 SL |
531 | /* |
532 | * Find a buffer which is available for use. | |
533 | * Select something from a free list. | |
534 | * Preference is to AGE list, then LRU list. | |
535 | */ | |
536 | struct buf * | |
537 | getnewbuf() | |
538 | { | |
539 | register struct buf *bp, *dp; | |
a937f856 | 540 | register struct ucred *cred; |
4f083fd7 SL |
541 | int s; |
542 | ||
5777440f KB |
543 | #ifdef LFS |
544 | lfs_flush(); | |
545 | #endif | |
4f083fd7 | 546 | loop: |
a5e62f37 | 547 | s = splbio(); |
4f083fd7 SL |
548 | for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) |
549 | if (dp->av_forw != dp) | |
550 | break; | |
551 | if (dp == bfreelist) { /* no free blocks */ | |
552 | dp->b_flags |= B_WANTED; | |
d42a4811 | 553 | sleep((caddr_t)dp, PRIBIO + 1); |
4b7d506c | 554 | splx(s); |
4f083fd7 SL |
555 | goto loop; |
556 | } | |
4f083fd7 | 557 | bp = dp->av_forw; |
c669f646 KM |
558 | bremfree(bp); |
559 | bp->b_flags |= B_BUSY; | |
560 | splx(s); | |
4f083fd7 | 561 | if (bp->b_flags & B_DELWRI) { |
033a786e | 562 | (void) bawrite(bp); |
4f083fd7 SL |
563 | goto loop; |
564 | } | |
c5a600cf | 565 | trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); |
edadbc2c KM |
566 | if (bp->b_vp) |
567 | brelvp(bp); | |
a937f856 KM |
568 | if (bp->b_rcred != NOCRED) { |
569 | cred = bp->b_rcred; | |
570 | bp->b_rcred = NOCRED; | |
571 | crfree(cred); | |
572 | } | |
573 | if (bp->b_wcred != NOCRED) { | |
574 | cred = bp->b_wcred; | |
575 | bp->b_wcred = NOCRED; | |
576 | crfree(cred); | |
577 | } | |
4f083fd7 | 578 | bp->b_flags = B_BUSY; |
1c89915d | 579 | bp->b_dirtyoff = bp->b_dirtyend = 0; |
bb1626f7 | 580 | bp->b_validoff = bp->b_validend = 0; |
4f083fd7 SL |
581 | return (bp); |
582 | } | |
583 | ||
663dbc72 | 584 | /* |
d42a4811 KM |
585 | * Wait for I/O to complete. |
586 | * | |
587 | * Extract and return any errors associated with the I/O. | |
588 | * If the error flag is set, but no specific error is | |
589 | * given, return EIO. | |
663dbc72 | 590 | */ |
3efdd860 | 591 | biowait(bp) |
ad30fb67 | 592 | register struct buf *bp; |
663dbc72 | 593 | { |
530d0032 | 594 | int s; |
663dbc72 | 595 | |
a5e62f37 | 596 | s = splbio(); |
a937f856 | 597 | while ((bp->b_flags & B_DONE) == 0) |
663dbc72 | 598 | sleep((caddr_t)bp, PRIBIO); |
530d0032 | 599 | splx(s); |
7188ac27 KM |
600 | if ((bp->b_flags & B_ERROR) == 0) |
601 | return (0); | |
602 | if (bp->b_error) | |
603 | return (bp->b_error); | |
604 | return (EIO); | |
663dbc72 BJ |
605 | } |
606 | ||
663dbc72 | 607 | /* |
af04ce66 | 608 | * Mark I/O complete on a buffer. |
d42a4811 KM |
609 | * |
610 | * If a callback has been requested, e.g. the pageout | |
611 | * daemon, do so. Otherwise, awaken waiting processes. | |
663dbc72 | 612 | */ |
251f56ba | 613 | void |
3efdd860 KM |
614 | biodone(bp) |
615 | register struct buf *bp; | |
663dbc72 | 616 | { |
663dbc72 | 617 | |
80e7c811 | 618 | if (bp->b_flags & B_DONE) |
3efdd860 | 619 | panic("dup biodone"); |
663dbc72 | 620 | bp->b_flags |= B_DONE; |
76429560 KM |
621 | if ((bp->b_flags & B_READ) == 0) |
622 | vwakeup(bp); | |
961945a8 SL |
623 | if (bp->b_flags & B_CALL) { |
624 | bp->b_flags &= ~B_CALL; | |
625 | (*bp->b_iodone)(bp); | |
626 | return; | |
627 | } | |
d42a4811 | 628 | if (bp->b_flags & B_ASYNC) |
663dbc72 BJ |
629 | brelse(bp); |
630 | else { | |
631 | bp->b_flags &= ~B_WANTED; | |
632 | wakeup((caddr_t)bp); | |
633 | } | |
634 | } |