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