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