routing messages do not come with attached addresses
[unix-history] / usr / src / sys / kern / vfs_cluster.c
CommitLineData
da7c5cc6 1/*
7188ac27
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
7188ac27
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
4e4b409c 17 * @(#)vfs_cluster.c 7.29 (Berkeley) %G%
da7c5cc6 18 */
961945a8 19
94368568 20#include "param.h"
94368568
JB
21#include "user.h"
22#include "buf.h"
7188ac27 23#include "vnode.h"
0f93ba7b 24#include "specdev.h"
edadbc2c 25#include "mount.h"
94368568 26#include "trace.h"
a937f856 27#include "ucred.h"
663dbc72 28
663dbc72
BJ
29/*
30 * Read in (if necessary) the block and return a buffer pointer.
31 */
a937f856 32bread(vp, blkno, size, cred, bpp)
7188ac27 33 struct vnode *vp;
ad30fb67
KM
34 daddr_t blkno;
35 int size;
a937f856 36 struct ucred *cred;
7188ac27 37 struct buf **bpp;
ec67a3ce
MK
38#ifdef SECSIZE
39 long secsize;
40#endif SECSIZE
663dbc72
BJ
41{
42 register struct buf *bp;
43
4f083fd7
SL
44 if (size == 0)
45 panic("bread: size 0");
ec67a3ce
MK
46#ifdef SECSIZE
47 bp = getblk(dev, blkno, size, secsize);
48#else SECSIZE
7188ac27 49 *bpp = bp = getblk(vp, blkno, size);
ec67a3ce 50#endif SECSIZE
32a56bda 51 if (bp->b_flags&(B_DONE|B_DELWRI)) {
c5a600cf 52 trace(TR_BREADHIT, pack(vp, size), blkno);
7188ac27 53 return (0);
663dbc72
BJ
54 }
55 bp->b_flags |= B_READ;
4f083fd7
SL
56 if (bp->b_bcount > bp->b_bufsize)
57 panic("bread");
a937f856
KM
58 if (bp->b_rcred == NOCRED && cred != NOCRED) {
59 crhold(cred);
60 bp->b_rcred = cred;
61 }
7188ac27 62 VOP_STRATEGY(bp);
c5a600cf 63 trace(TR_BREADMISS, pack(vp, size), blkno);
fb99a9a1 64 u.u_ru.ru_inblock++; /* pay for read */
7188ac27 65 return (biowait(bp));
663dbc72
BJ
66}
67
68/*
69 * Read in the block, like bread, but also start I/O on the
70 * read-ahead block (which is not allocated to the caller)
71 */
a937f856 72breada(vp, blkno, size, rablkno, rabsize, cred, bpp)
7188ac27 73 struct vnode *vp;
84baaab3 74 daddr_t blkno; int size;
ec67a3ce
MK
75#ifdef SECSIZE
76 long secsize;
77#endif SECSIZE
a8d3bf7f 78 daddr_t rablkno; int rabsize;
a937f856 79 struct ucred *cred;
7188ac27 80 struct buf **bpp;
663dbc72
BJ
81{
82 register struct buf *bp, *rabp;
83
84 bp = NULL;
3efdd860
KM
85 /*
86 * If the block isn't in core, then allocate
87 * a buffer and initiate i/o (getblk checks
88 * for a cache hit).
89 */
7188ac27
KM
90 if (!incore(vp, blkno)) {
91 *bpp = bp = getblk(vp, blkno, size);
ec67a3ce 92#endif SECSIZE
32a56bda 93 if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
663dbc72 94 bp->b_flags |= B_READ;
4f083fd7
SL
95 if (bp->b_bcount > bp->b_bufsize)
96 panic("breada");
a937f856
KM
97 if (bp->b_rcred == NOCRED && cred != NOCRED) {
98 crhold(cred);
99 bp->b_rcred = cred;
100 }
7188ac27 101 VOP_STRATEGY(bp);
c5a600cf 102 trace(TR_BREADMISS, pack(vp, size), blkno);
fb99a9a1 103 u.u_ru.ru_inblock++; /* pay for read */
3efdd860 104 } else
c5a600cf 105 trace(TR_BREADHIT, pack(vp, size), blkno);
663dbc72 106 }
3efdd860
KM
107
108 /*
109 * If there's a read-ahead block, start i/o
110 * on it also (as above).
111 */
ee19707c 112 if (!incore(vp, rablkno)) {
7188ac27 113 rabp = getblk(vp, rablkno, rabsize);
ec67a3ce 114#endif SECSIZE
32a56bda 115 if (rabp->b_flags & (B_DONE|B_DELWRI)) {
663dbc72 116 brelse(rabp);
c5a600cf 117 trace(TR_BREADHITRA, pack(vp, rabsize), rablkno);
973ecc4f 118 } else {
663dbc72 119 rabp->b_flags |= B_READ|B_ASYNC;
4f083fd7
SL
120 if (rabp->b_bcount > rabp->b_bufsize)
121 panic("breadrabp");
5062ac4a 122 if (rabp->b_rcred == NOCRED && cred != NOCRED) {
a937f856 123 crhold(cred);
5062ac4a 124 rabp->b_rcred = cred;
a937f856 125 }
7188ac27 126 VOP_STRATEGY(rabp);
c5a600cf 127 trace(TR_BREADMISSRA, pack(vp, rabsize), rablkno);
fb99a9a1 128 u.u_ru.ru_inblock++; /* pay in advance */
663dbc72
BJ
129 }
130 }
3efdd860
KM
131
132 /*
84baaab3
KM
133 * If block was in core, let bread get it.
134 * If block wasn't in core, then the read was started
135 * above, and just wait for it.
3efdd860 136 */
84baaab3 137 if (bp == NULL)
ec67a3ce
MK
138#ifdef SECSIZE
139 return (bread(dev, blkno, size, secsize));
140#else SECSIZE
a937f856 141 return (bread(vp, blkno, size, cred, bpp));
7188ac27 142 return (biowait(bp));
663dbc72
BJ
143}
144
145/*
146 * Write the buffer, waiting for completion.
147 * Then release the buffer.
148 */
149bwrite(bp)
3efdd860 150 register struct buf *bp;
663dbc72 151{
7188ac27 152 register int flag;
86e7dd3b 153 int s, error;
663dbc72
BJ
154
155 flag = bp->b_flags;
f844ee62 156 bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
663dbc72 157 if ((flag&B_DELWRI) == 0)
fb99a9a1 158 u.u_ru.ru_oublock++; /* noone paid yet */
c669f646
KM
159 else
160 reassignbuf(bp, bp->b_vp);
c5a600cf 161 trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno);
4f083fd7
SL
162 if (bp->b_bcount > bp->b_bufsize)
163 panic("bwrite");
86e7dd3b 164 s = splbio();
c669f646 165 bp->b_vp->v_numoutput++;
86e7dd3b 166 splx(s);
7188ac27 167 VOP_STRATEGY(bp);
3efdd860
KM
168
169 /*
170 * If the write was synchronous, then await i/o completion.
171 * If the write was "delayed", then we put the buffer on
172 * the q of blocks awaiting i/o completion status.
3efdd860 173 */
663dbc72 174 if ((flag&B_ASYNC) == 0) {
7188ac27 175 error = biowait(bp);
663dbc72 176 brelse(bp);
7188ac27 177 } else if (flag & B_DELWRI) {
663dbc72 178 bp->b_flags |= B_AGE;
7188ac27
KM
179 error = 0;
180 }
181 return (error);
663dbc72
BJ
182}
183
184/*
185 * Release the buffer, marking it so that if it is grabbed
186 * for another purpose it will be written out before being
187 * given up (e.g. when writing a partial block where it is
188 * assumed that another write for the same block will soon follow).
189 * This can't be done for magtape, since writes must be done
190 * in the same order as requested.
191 */
192bdwrite(bp)
3efdd860 193 register struct buf *bp;
663dbc72 194{
663dbc72 195
c669f646
KM
196 if ((bp->b_flags & B_DELWRI) == 0) {
197 bp->b_flags |= B_DELWRI;
198 reassignbuf(bp, bp->b_vp);
fb99a9a1 199 u.u_ru.ru_oublock++; /* noone paid yet */
c669f646 200 }
7188ac27 201 /*
edadbc2c 202 * If this is a tape drive, the write must be initiated.
7188ac27 203 */
ec67a3ce 204 if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
663dbc72 205 bawrite(bp);
edadbc2c 206 } else {
663dbc72
BJ
207 bp->b_flags |= B_DELWRI | B_DONE;
208 brelse(bp);
209 }
210}
211
212/*
213 * Release the buffer, start I/O on it, but don't wait for completion.
214 */
215bawrite(bp)
3efdd860 216 register struct buf *bp;
663dbc72
BJ
217{
218
219 bp->b_flags |= B_ASYNC;
7188ac27 220 (void) bwrite(bp);
663dbc72
BJ
221}
222
223/*
3efdd860 224 * Release the buffer, with no I/O implied.
663dbc72
BJ
225 */
226brelse(bp)
3efdd860 227 register struct buf *bp;
663dbc72 228{
46387ee3 229 register struct buf *flist;
663dbc72
BJ
230 register s;
231
c5a600cf 232 trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
3efdd860 233 /*
edadbc2c
KM
234 * If a process is waiting for the buffer, or
235 * is waiting for a free buffer, awaken it.
3efdd860 236 */
663dbc72
BJ
237 if (bp->b_flags&B_WANTED)
238 wakeup((caddr_t)bp);
46387ee3
BJ
239 if (bfreelist[0].b_flags&B_WANTED) {
240 bfreelist[0].b_flags &= ~B_WANTED;
241 wakeup((caddr_t)bfreelist);
663dbc72 242 }
edadbc2c
KM
243 /*
244 * Retry I/O for locked buffers rather than invalidating them.
245 */
246 if ((bp->b_flags & B_ERROR) && (bp->b_flags & B_LOCKED))
247 bp->b_flags &= ~B_ERROR;
248
249 /*
250 * Disassociate buffers that are no longer valid.
251 */
252 if (bp->b_flags & (B_NOCACHE|B_ERROR))
7188ac27 253 bp->b_flags |= B_INVAL;
edadbc2c
KM
254 if ((bp->b_bufsize <= 0) || (bp->b_flags & (B_ERROR|B_INVAL))) {
255 if (bp->b_vp)
256 brelvp(bp);
257 bp->b_flags &= ~B_DELWRI;
7188ac27 258 }
3efdd860
KM
259 /*
260 * Stick the buffer back on a free list.
261 */
a5e62f37 262 s = splbio();
4f083fd7
SL
263 if (bp->b_bufsize <= 0) {
264 /* block has no buffer ... put at front of unused buffer list */
265 flist = &bfreelist[BQ_EMPTY];
266 binsheadfree(bp, flist);
267 } else if (bp->b_flags & (B_ERROR|B_INVAL)) {
46387ee3 268 /* block has no info ... put at front of most free list */
4f083fd7 269 flist = &bfreelist[BQ_AGE];
3efdd860 270 binsheadfree(bp, flist);
663dbc72 271 } else {
46387ee3
BJ
272 if (bp->b_flags & B_LOCKED)
273 flist = &bfreelist[BQ_LOCKED];
274 else if (bp->b_flags & B_AGE)
275 flist = &bfreelist[BQ_AGE];
276 else
277 flist = &bfreelist[BQ_LRU];
3efdd860 278 binstailfree(bp, flist);
663dbc72 279 }
7188ac27 280 bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE|B_NOCACHE);
663dbc72
BJ
281 splx(s);
282}
283
284/*
285 * See if the block is associated with some buffer
286 * (mainly to avoid getting hung up on a wait in breada)
287 */
7188ac27
KM
288incore(vp, blkno)
289 struct vnode *vp;
3efdd860 290 daddr_t blkno;
663dbc72
BJ
291{
292 register struct buf *bp;
46387ee3 293 register struct buf *dp;
663dbc72 294
243d4743 295 dp = BUFHASH(vp, blkno);
46387ee3 296 for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
edadbc2c 297 if (bp->b_lblkno == blkno && bp->b_vp == vp &&
3efdd860 298 (bp->b_flags & B_INVAL) == 0)
5603d07d 299 return (1);
5603d07d 300 return (0);
663dbc72
BJ
301}
302
edadbc2c
KM
303/*
304 * Return a block if it is in memory.
305 */
a937f856 306baddr(vp, blkno, size, cred, bpp)
7188ac27 307 struct vnode *vp;
ad30fb67
KM
308 daddr_t blkno;
309 int size;
a937f856 310 struct ucred *cred;
7188ac27 311 struct buf **bpp;
ec67a3ce
MK
312#ifdef SECSIZE
313 long secsize;
314#endif SECSIZE
663dbc72
BJ
315{
316
7188ac27 317 if (incore(vp, blkno))
a937f856 318 return (bread(vp, blkno, size, cred, bpp));
7188ac27 319 *bpp = 0;
ec67a3ce 320#endif SECSIZE
663dbc72
BJ
321 return (0);
322}
323
324/*
325 * Assign a buffer for the given block. If the appropriate
326 * block is already associated, return it; otherwise search
327 * for the oldest non-busy buffer and reassign it.
23900030
BJ
328 *
329 * We use splx here because this routine may be called
330 * on the interrupt stack during a dump, and we don't
331 * want to lower the ipl back to 0.
663dbc72
BJ
332 */
333struct buf *
ec67a3ce
MK
334#ifdef SECSIZE
335getblk(dev, blkno, size, secsize)
336#else SECSIZE
7188ac27
KM
337getblk(vp, blkno, size)
338 register struct vnode *vp;
ad30fb67
KM
339 daddr_t blkno;
340 int size;
ec67a3ce
MK
341#ifdef SECSIZE
342 long secsize;
343#endif SECSIZE
663dbc72 344{
4f083fd7 345 register struct buf *bp, *dp;
23900030 346 int s;
663dbc72 347
00a6a148
KM
348 if (size > MAXBSIZE)
349 panic("getblk: size too big");
3efdd860
KM
350 /*
351 * Search the cache for the block. If we hit, but
352 * the buffer is in use for i/o, then we wait until
353 * the i/o has completed.
354 */
7188ac27 355 dp = BUFHASH(vp, blkno);
3efdd860 356loop:
46387ee3 357 for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
edadbc2c 358 if (bp->b_lblkno != blkno || bp->b_vp != vp ||
46387ee3 359 bp->b_flags&B_INVAL)
663dbc72 360 continue;
a5e62f37 361 s = splbio();
663dbc72
BJ
362 if (bp->b_flags&B_BUSY) {
363 bp->b_flags |= B_WANTED;
364 sleep((caddr_t)bp, PRIBIO+1);
23900030 365 splx(s);
663dbc72
BJ
366 goto loop;
367 }
c669f646
KM
368 bremfree(bp);
369 bp->b_flags |= B_BUSY;
23900030 370 splx(s);
32a56bda 371 if (bp->b_bcount != size) {
edadbc2c
KM
372 printf("getblk: stray size");
373 bp->b_flags |= B_INVAL;
374 bwrite(bp);
9d6d37ce 375 goto loop;
edadbc2c 376 }
663dbc72 377 bp->b_flags |= B_CACHE;
a5e62f37 378 return (bp);
663dbc72 379 }
4f083fd7 380 bp = getnewbuf();
ad30fb67 381 bfree(bp);
3efdd860 382 bremhash(bp);
edadbc2c
KM
383 bgetvp(vp, bp);
384 bp->b_lblkno = blkno;
ec67a3ce
MK
385#ifdef SECSIZE
386 bp->b_blksize = secsize;
387#endif SECSIZE
ad30fb67 388 bp->b_blkno = blkno;
4f083fd7 389 bp->b_error = 0;
7188ac27
KM
390 bp->b_resid = 0;
391 binshash(bp, dp);
edadbc2c 392 brealloc(bp, size);
a5e62f37 393 return (bp);
663dbc72
BJ
394}
395
396/*
397 * get an empty block,
398 * not assigned to any particular device
399 */
400struct buf *
ad30fb67
KM
401geteblk(size)
402 int size;
663dbc72 403{
4f083fd7 404 register struct buf *bp, *flist;
663dbc72 405
00a6a148
KM
406 if (size > MAXBSIZE)
407 panic("geteblk: size too big");
4f083fd7
SL
408 bp = getnewbuf();
409 bp->b_flags |= B_INVAL;
3efdd860
KM
410 bfree(bp);
411 bremhash(bp);
4f083fd7 412 flist = &bfreelist[BQ_AGE];
ec67a3ce
MK
413#ifdef SECSIZE
414 bp->b_blksize = DEV_BSIZE;
415#endif SECSIZE
4f083fd7 416 bp->b_error = 0;
7188ac27
KM
417 bp->b_resid = 0;
418 binshash(bp, flist);
edadbc2c 419 brealloc(bp, size);
a5e62f37 420 return (bp);
663dbc72
BJ
421}
422
ad30fb67
KM
423/*
424 * Allocate space associated with a buffer.
425 */
426brealloc(bp, size)
427 register struct buf *bp;
428 int size;
429{
430 daddr_t start, last;
431 register struct buf *ep;
432 struct buf *dp;
433 int s;
434
ad30fb67 435 if (size == bp->b_bcount)
edadbc2c
KM
436 return;
437 allocbuf(bp, size);
4f083fd7
SL
438}
439
4f083fd7
SL
440/*
441 * Find a buffer which is available for use.
442 * Select something from a free list.
443 * Preference is to AGE list, then LRU list.
444 */
445struct buf *
446getnewbuf()
447{
448 register struct buf *bp, *dp;
a937f856 449 register struct ucred *cred;
4f083fd7
SL
450 int s;
451
452loop:
a5e62f37 453 s = splbio();
4f083fd7
SL
454 for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--)
455 if (dp->av_forw != dp)
456 break;
457 if (dp == bfreelist) { /* no free blocks */
458 dp->b_flags |= B_WANTED;
459 sleep((caddr_t)dp, PRIBIO+1);
4b7d506c 460 splx(s);
4f083fd7
SL
461 goto loop;
462 }
4f083fd7 463 bp = dp->av_forw;
c669f646
KM
464 bremfree(bp);
465 bp->b_flags |= B_BUSY;
466 splx(s);
4f083fd7 467 if (bp->b_flags & B_DELWRI) {
033a786e 468 (void) bawrite(bp);
4f083fd7
SL
469 goto loop;
470 }
c5a600cf 471 trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
edadbc2c
KM
472 if (bp->b_vp)
473 brelvp(bp);
a937f856
KM
474 if (bp->b_rcred != NOCRED) {
475 cred = bp->b_rcred;
476 bp->b_rcred = NOCRED;
477 crfree(cred);
478 }
479 if (bp->b_wcred != NOCRED) {
480 cred = bp->b_wcred;
481 bp->b_wcred = NOCRED;
482 crfree(cred);
483 }
4f083fd7
SL
484 bp->b_flags = B_BUSY;
485 return (bp);
486}
487
663dbc72
BJ
488/*
489 * Wait for I/O completion on the buffer; return errors
490 * to the user.
491 */
3efdd860 492biowait(bp)
ad30fb67 493 register struct buf *bp;
663dbc72 494{
530d0032 495 int s;
663dbc72 496
a5e62f37 497 s = splbio();
a937f856 498 while ((bp->b_flags & B_DONE) == 0)
663dbc72 499 sleep((caddr_t)bp, PRIBIO);
530d0032 500 splx(s);
7188ac27
KM
501 /*
502 * Pick up the device's error number and pass it to the user;
503 * if there is an error but the number is 0 set a generalized code.
504 */
505 if ((bp->b_flags & B_ERROR) == 0)
506 return (0);
507 if (bp->b_error)
508 return (bp->b_error);
509 return (EIO);
663dbc72
BJ
510}
511
663dbc72 512/*
af04ce66
SL
513 * Mark I/O complete on a buffer.
514 * If someone should be called, e.g. the pageout
515 * daemon, do so. Otherwise, wake up anyone
516 * waiting for it.
663dbc72 517 */
3efdd860
KM
518biodone(bp)
519 register struct buf *bp;
663dbc72 520{
c669f646 521 register struct vnode *vp;
663dbc72 522
80e7c811 523 if (bp->b_flags & B_DONE)
3efdd860 524 panic("dup biodone");
663dbc72 525 bp->b_flags |= B_DONE;
c669f646 526 if ((bp->b_flags & B_READ) == 0) {
a937f856 527 bp->b_dirtyoff = bp->b_dirtyend = 0;
c669f646
KM
528 if (vp = bp->b_vp) {
529 vp->v_numoutput--;
530 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
531 if (vp->v_numoutput < 0)
532 panic("biodone: neg numoutput");
533 vp->v_flag &= ~VBWAIT;
534 wakeup((caddr_t)&vp->v_numoutput);
535 }
536 }
537 }
961945a8
SL
538 if (bp->b_flags & B_CALL) {
539 bp->b_flags &= ~B_CALL;
540 (*bp->b_iodone)(bp);
541 return;
542 }
663dbc72
BJ
543 if (bp->b_flags&B_ASYNC)
544 brelse(bp);
545 else {
546 bp->b_flags &= ~B_WANTED;
547 wakeup((caddr_t)bp);
548 }
549}
550
663dbc72 551/*
7188ac27 552 * Make sure all write-behind blocks associated
a937f856 553 * with mount point are flushed out (from sync).
663dbc72 554 */
edadbc2c 555mntflushbuf(mountp, flags)
a937f856 556 struct mount *mountp;
edadbc2c 557 int flags;
663dbc72 558{
099798da 559 register struct vnode *vp;
edadbc2c 560
54fb9dc2 561 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
17c2edaa 562 panic("mntflushbuf: not busy");
edadbc2c 563loop:
4597dd33 564 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
edadbc2c
KM
565 if (vget(vp))
566 goto loop;
567 vflushbuf(vp, flags);
568 vput(vp);
4597dd33
KM
569 if (vp->v_mount != mountp)
570 goto loop;
edadbc2c
KM
571 }
572}
573
574/*
575 * Flush all dirty buffers associated with a vnode.
576 */
577vflushbuf(vp, flags)
578 register struct vnode *vp;
579 int flags;
580{
581 register struct buf *bp;
582 struct buf *nbp;
530d0032 583 int s;
663dbc72
BJ
584
585loop:
a5e62f37 586 s = splbio();
c669f646 587 for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
edadbc2c
KM
588 nbp = bp->b_blockf;
589 if ((bp->b_flags & B_BUSY))
590 continue;
591 if ((bp->b_flags & B_DELWRI) == 0)
c669f646
KM
592 panic("vflushbuf: not dirty");
593 bremfree(bp);
594 bp->b_flags |= B_BUSY;
edadbc2c 595 splx(s);
c669f646
KM
596 /*
597 * Wait for I/O associated with indirect blocks to complete,
598 * since there is no way to quickly wait for them below.
599 * NB - This is really specific to ufs, but is done here
600 * as it is easier and quicker.
601 */
602 if (bp->b_vp == vp || (flags & B_SYNC) == 0) {
603 (void) bawrite(bp);
93d6e9b8 604 s = splbio();
c669f646
KM
605 } else {
606 (void) bwrite(bp);
607 goto loop;
608 }
edadbc2c 609 }
9c1dffd6 610 splx(s);
edadbc2c
KM
611 if ((flags & B_SYNC) == 0)
612 return;
edadbc2c 613 s = splbio();
c669f646
KM
614 while (vp->v_numoutput) {
615 vp->v_flag |= VBWAIT;
616 sleep((caddr_t)&vp->v_numoutput, PRIBIO+1);
7188ac27 617 }
9c1dffd6 618 splx(s);
c669f646
KM
619 if (vp->v_dirtyblkhd) {
620 vprint("vflushbuf: dirty", vp);
621 goto loop;
622 }
663dbc72 623}
7b8b5a01
RE
624
625/*
626 * Invalidate in core blocks belonging to closed or umounted filesystem
627 *
edadbc2c
KM
628 * Go through the list of vnodes associated with the file system;
629 * for each vnode invalidate any buffers that it holds. Normally
630 * this routine is preceeded by a bflush call, so that on a quiescent
631 * filesystem there will be no dirty buffers when we are done. Binval
632 * returns the count of dirty buffers when it is finished.
7b8b5a01 633 */
edadbc2c 634mntinvalbuf(mountp)
a937f856 635 struct mount *mountp;
7b8b5a01 636{
099798da 637 register struct vnode *vp;
edadbc2c
KM
638 int dirty = 0;
639
54fb9dc2 640 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
17c2edaa 641 panic("mntinvalbuf: not busy");
edadbc2c 642loop:
4597dd33 643 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
edadbc2c
KM
644 if (vget(vp))
645 goto loop;
646 dirty += vinvalbuf(vp, 1);
647 vput(vp);
4597dd33
KM
648 if (vp->v_mount != mountp)
649 goto loop;
edadbc2c
KM
650 }
651 return (dirty);
652}
653
654/*
655 * Flush out and invalidate all buffers associated with a vnode.
656 * Called with the underlying object locked.
657 */
658vinvalbuf(vp, save)
659 register struct vnode *vp;
660 int save;
661{
662 register struct buf *bp;
c669f646 663 struct buf *nbp, *blist;
1a24c701 664 int s, dirty = 0;
7b8b5a01 665
c669f646
KM
666 for (;;) {
667 if (blist = vp->v_dirtyblkhd)
668 /* void */;
669 else if (blist = vp->v_cleanblkhd)
670 /* void */;
671 else
672 break;
673 for (bp = blist; bp; bp = nbp) {
674 nbp = bp->b_blockf;
675 s = splbio();
676 if (bp->b_flags & B_BUSY) {
677 bp->b_flags |= B_WANTED;
678 sleep((caddr_t)bp, PRIBIO+1);
679 splx(s);
680 break;
681 }
682 bremfree(bp);
683 bp->b_flags |= B_BUSY;
5a3e32e2 684 splx(s);
c669f646 685 if (save && (bp->b_flags & B_DELWRI)) {
033a786e 686 dirty++;
edadbc2c 687 (void) bwrite(bp);
c669f646 688 break;
7188ac27 689 }
05a0ddc9
KM
690 if (bp->b_vp != vp)
691 reassignbuf(bp, bp->b_vp);
692 else
693 bp->b_flags |= B_INVAL;
c669f646 694 brelse(bp);
033a786e
KM
695 }
696 }
c669f646 697 if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
edadbc2c 698 panic("vinvalbuf: flush failed");
033a786e 699 return (dirty);
7188ac27
KM
700}
701
edadbc2c
KM
702/*
703 * Associate a buffer with a vnode.
704 */
705bgetvp(vp, bp)
706 register struct vnode *vp;
707 register struct buf *bp;
708{
709
710 if (bp->b_vp)
711 panic("bgetvp: not free");
79b10da1 712 VHOLD(vp);
edadbc2c
KM
713 bp->b_vp = vp;
714 if (vp->v_type == VBLK || vp->v_type == VCHR)
715 bp->b_dev = vp->v_rdev;
716 else
717 bp->b_dev = NODEV;
718 /*
719 * Insert onto list for new vnode.
720 */
c669f646
KM
721 if (vp->v_cleanblkhd) {
722 bp->b_blockf = vp->v_cleanblkhd;
723 bp->b_blockb = &vp->v_cleanblkhd;
724 vp->v_cleanblkhd->b_blockb = &bp->b_blockf;
725 vp->v_cleanblkhd = bp;
edadbc2c 726 } else {
c669f646
KM
727 vp->v_cleanblkhd = bp;
728 bp->b_blockb = &vp->v_cleanblkhd;
edadbc2c
KM
729 bp->b_blockf = NULL;
730 }
731}
732
733/*
734 * Disassociate a buffer from a vnode.
735 */
7188ac27 736brelvp(bp)
edadbc2c 737 register struct buf *bp;
7188ac27 738{
edadbc2c 739 struct buf *bq;
7188ac27
KM
740 struct vnode *vp;
741
742 if (bp->b_vp == (struct vnode *) 0)
edadbc2c
KM
743 panic("brelvp: NULL");
744 /*
745 * Delete from old vnode list, if on one.
746 */
747 if (bp->b_blockb) {
748 if (bq = bp->b_blockf)
749 bq->b_blockb = bp->b_blockb;
750 *bp->b_blockb = bq;
751 bp->b_blockf = NULL;
752 bp->b_blockb = NULL;
753 }
7188ac27
KM
754 vp = bp->b_vp;
755 bp->b_vp = (struct vnode *) 0;
79b10da1 756 HOLDRELE(vp);
7b8b5a01 757}
edadbc2c
KM
758
759/*
760 * Reassign a buffer from one vnode to another.
761 * Used to assign file specific control information
762 * (indirect blocks) to the vnode to which they belong.
763 */
764reassignbuf(bp, newvp)
765 register struct buf *bp;
766 register struct vnode *newvp;
767{
c669f646 768 register struct buf *bq, **listheadp;
edadbc2c 769
c669f646
KM
770 if (newvp == NULL)
771 panic("reassignbuf: NULL");
edadbc2c
KM
772 /*
773 * Delete from old vnode list, if on one.
774 */
775 if (bp->b_blockb) {
776 if (bq = bp->b_blockf)
777 bq->b_blockb = bp->b_blockb;
778 *bp->b_blockb = bq;
779 }
780 /*
c669f646
KM
781 * If dirty, put on list of dirty buffers;
782 * otherwise insert onto list of clean buffers.
edadbc2c 783 */
c669f646
KM
784 if (bp->b_flags & B_DELWRI)
785 listheadp = &newvp->v_dirtyblkhd;
786 else
787 listheadp = &newvp->v_cleanblkhd;
788 if (*listheadp) {
789 bp->b_blockf = *listheadp;
790 bp->b_blockb = listheadp;
791 bp->b_blockf->b_blockb = &bp->b_blockf;
792 *listheadp = bp;
edadbc2c 793 } else {
c669f646
KM
794 *listheadp = bp;
795 bp->b_blockb = listheadp;
edadbc2c
KM
796 bp->b_blockf = NULL;
797 }
798}