|
|
1.1 root 1: /* bio.c 4.21 81/05/08 */
2:
3: #include "../h/param.h"
4: #include "../h/systm.h"
5: #include "../h/dir.h"
6: #include "../h/user.h"
7: #include "../h/buf.h"
8: #include "../h/conf.h"
9: #include "../h/proc.h"
10: #include "../h/seg.h"
11: #include "../h/pte.h"
12: #include "../h/vm.h"
13: #include "../h/trace.h"
14:
15: /*
16: * The following several routines allocate and free
17: * buffers with various side effects. In general the
18: * arguments to an allocate routine are a device and
19: * a block number, and the value is a pointer to
20: * to the buffer header; the buffer is marked "busy"
21: * so that no one else can touch it. If the block was
22: * already in core, no I/O need be done; if it is
23: * already busy, the process waits until it becomes free.
24: * The following routines allocate a buffer:
25: * getblk
26: * bread
27: * breada
28: * baddr (if it is incore)
29: * Eventually the buffer must be released, possibly with the
30: * side effect of writing it out, by using one of
31: * bwrite
32: * bdwrite
33: * bawrite
34: * brelse
35: */
36:
37: struct buf bfreelist[BQUEUES];
38: struct buf bswlist, *bclnlist;
39:
40: #define BUFHSZ 63
41: struct bufhd bufhash[BUFHSZ];
42: #define BUFHASH(dev, dblkno) \
43: ((struct buf *)&bufhash[((int)(dev)+(int)(dblkno)) % BUFHSZ])
44:
45: /*
46: * Initialize hash links for buffers.
47: */
48: bhinit()
49: {
50: register int i;
51: register struct bufhd *bp;
52:
53: for (bp = bufhash, i = 0; i < BUFHSZ; i++, bp++)
54: bp->b_forw = bp->b_back = (struct buf *)bp;
55: }
56:
57: /* #define DISKMON 1 */
58:
59: #ifdef DISKMON
60: struct {
61: int nbuf;
62: long nread;
63: long nreada;
64: long ncache;
65: long nwrite;
66: long bufcount[64];
67: } io_info;
68: #endif
69:
70: /*
71: * Swap IO headers -
72: * They contain the necessary information for the swap I/O.
73: * At any given time, a swap header can be in three
74: * different lists. When free it is in the free list,
75: * when allocated and the I/O queued, it is on the swap
76: * device list, and finally, if the operation was a dirty
77: * page push, when the I/O completes, it is inserted
78: * in a list of cleaned pages to be processed by the pageout daemon.
79: */
80: struct buf *swbuf;
81: short *swsize; /* CAN WE JUST USE B_BCOUNT? */
82: int *swpf;
83:
84:
85: #ifndef UNFAST
86: #define notavail(bp) \
87: { \
88: int s = spl6(); \
89: (bp)->av_back->av_forw = (bp)->av_forw; \
90: (bp)->av_forw->av_back = (bp)->av_back; \
91: (bp)->b_flags |= B_BUSY; \
92: splx(s); \
93: }
94: #endif
95:
96: /*
97: * Read in (if necessary) the block and return a buffer pointer.
98: */
99: struct buf *
100: bread(dev, blkno)
101: dev_t dev;
102: daddr_t blkno;
103: {
104: register struct buf *bp;
105:
106: bp = getblk(dev, blkno);
107: if (bp->b_flags&B_DONE) {
108: #ifdef DISKMON
109: io_info.ncache++;
110: #endif
111: return(bp);
112: }
113: bp->b_flags |= B_READ;
114: bp->b_bcount = BSIZE(dev);
115: (*bdevsw[major(dev)].d_strategy)(bp);
116: #ifdef DISKMON
117: io_info.nread++;
118: #endif
119: u.u_vm.vm_inblk++; /* pay for read */
120: iowait(bp);
121: return(bp);
122: }
123:
124: /*
125: * Read in the block, like bread, but also start I/O on the
126: * read-ahead block (which is not allocated to the caller)
127: */
128: struct buf *
129: breada(dev, blkno, rablkno)
130: dev_t dev;
131: daddr_t blkno, rablkno;
132: {
133: register struct buf *bp, *rabp;
134:
135: bp = NULL;
136: if (!incore(dev, blkno)) {
137: bp = getblk(dev, blkno);
138: if ((bp->b_flags&B_DONE) == 0) {
139: bp->b_flags |= B_READ;
140: bp->b_bcount = BSIZE(dev);
141: (*bdevsw[major(dev)].d_strategy)(bp);
142: #ifdef DISKMON
143: io_info.nread++;
144: #endif
145: u.u_vm.vm_inblk++; /* pay for read */
146: }
147: }
148: if (rablkno && !incore(dev, rablkno)) {
149: rabp = getblk(dev, rablkno);
150: if (rabp->b_flags & B_DONE) {
151: brelse(rabp);
152: } else {
153: rabp->b_flags |= B_READ|B_ASYNC;
154: rabp->b_bcount = BSIZE(dev);
155: (*bdevsw[major(dev)].d_strategy)(rabp);
156: #ifdef DISKMON
157: io_info.nreada++;
158: #endif
159: u.u_vm.vm_inblk++; /* pay in advance */
160: }
161: }
162: if(bp == NULL)
163: return(bread(dev, blkno));
164: iowait(bp);
165: return(bp);
166: }
167:
168: /*
169: * Write the buffer, waiting for completion.
170: * Then release the buffer.
171: */
172: bwrite(bp)
173: register struct buf *bp;
174: {
175: register flag;
176:
177: flag = bp->b_flags;
178: bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE);
179: bp->b_bcount = BSIZE(bp->b_dev);
180: #ifdef DISKMON
181: io_info.nwrite++;
182: #endif
183: if ((flag&B_DELWRI) == 0)
184: u.u_vm.vm_oublk++; /* noone paid yet */
185: (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
186: if ((flag&B_ASYNC) == 0) {
187: iowait(bp);
188: brelse(bp);
189: } else if (flag & B_DELWRI)
190: bp->b_flags |= B_AGE;
191: else
192: geterror(bp);
193: }
194:
195: /*
196: * Release the buffer, marking it so that if it is grabbed
197: * for another purpose it will be written out before being
198: * given up (e.g. when writing a partial block where it is
199: * assumed that another write for the same block will soon follow).
200: * This can't be done for magtape, since writes must be done
201: * in the same order as requested.
202: */
203: bdwrite(bp)
204: register struct buf *bp;
205: {
206: register int flags;
207:
208: if ((bp->b_flags&B_DELWRI) == 0)
209: u.u_vm.vm_oublk++; /* noone paid yet */
210: flags = bdevsw[major(bp->b_dev)].d_flags;
211: if(flags & B_TAPE)
212: bawrite(bp);
213: else {
214: bp->b_flags |= B_DELWRI | B_DONE;
215: brelse(bp);
216: }
217: }
218:
219: /*
220: * Release the buffer, start I/O on it, but don't wait for completion.
221: */
222: bawrite(bp)
223: register struct buf *bp;
224: {
225:
226: bp->b_flags |= B_ASYNC;
227: bwrite(bp);
228: }
229:
230: /*
231: * release the buffer, with no I/O implied.
232: */
233: brelse(bp)
234: register struct buf *bp;
235: {
236: register struct buf *flist;
237: register s;
238:
239: if (bp->b_flags&B_WANTED)
240: wakeup((caddr_t)bp);
241: if (bfreelist[0].b_flags&B_WANTED) {
242: bfreelist[0].b_flags &= ~B_WANTED;
243: wakeup((caddr_t)bfreelist);
244: }
245: if (bp->b_flags&B_ERROR)
246: if (bp->b_flags & B_LOCKED)
247: bp->b_flags &= ~B_ERROR; /* try again later */
248: else
249: bp->b_dev = NODEV; /* no assoc */
250: s = spl6();
251: if (bp->b_flags & (B_ERROR|B_INVAL)) {
252: /* block has no info ... put at front of most free list */
253: flist = &bfreelist[BQUEUES-1];
254: flist->av_forw->av_back = bp;
255: bp->av_forw = flist->av_forw;
256: flist->av_forw = bp;
257: bp->av_back = flist;
258: } else {
259: if (bp->b_flags & B_LOCKED)
260: flist = &bfreelist[BQ_LOCKED];
261: else if (bp->b_flags & B_AGE)
262: flist = &bfreelist[BQ_AGE];
263: else
264: flist = &bfreelist[BQ_LRU];
265: flist->av_back->av_forw = bp;
266: bp->av_back = flist->av_back;
267: flist->av_back = bp;
268: bp->av_forw = flist;
269: }
270: bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
271: splx(s);
272: }
273:
274: /*
275: * See if the block is associated with some buffer
276: * (mainly to avoid getting hung up on a wait in breada)
277: */
278: incore(dev, blkno)
279: dev_t dev;
280: daddr_t blkno;
281: {
282: register struct buf *bp;
283: register struct buf *dp;
284: register int dblkno = fsbtodb(dev, blkno);
285:
286: dp = BUFHASH(dev, dblkno);
287: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
288: if (bp->b_blkno == dblkno && bp->b_dev == dev &&
289: !(bp->b_flags & B_INVAL))
290: return (1);
291: return (0);
292: }
293:
294: struct buf *
295: baddr(dev, blkno)
296: dev_t dev;
297: daddr_t blkno;
298: {
299:
300: if (incore(dev, blkno))
301: return (bread(dev, blkno));
302: return (0);
303: }
304:
305: /*
306: * Assign a buffer for the given block. If the appropriate
307: * block is already associated, return it; otherwise search
308: * for the oldest non-busy buffer and reassign it.
309: */
310: struct buf *
311: getblk(dev, blkno)
312: dev_t dev;
313: daddr_t blkno;
314: {
315: register struct buf *bp, *dp, *ep;
316: register int dblkno = fsbtodb(dev, blkno);
317: #ifdef DISKMON
318: register int i;
319: #endif
320:
321: if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT))
322: blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1);
323: dblkno = fsbtodb(dev, blkno);
324: dp = BUFHASH(dev, dblkno);
325: loop:
326: (void) spl0();
327: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
328: if (bp->b_blkno != dblkno || bp->b_dev != dev ||
329: bp->b_flags&B_INVAL)
330: continue;
331: (void) spl6();
332: if (bp->b_flags&B_BUSY) {
333: bp->b_flags |= B_WANTED;
334: sleep((caddr_t)bp, PRIBIO+1);
335: goto loop;
336: }
337: (void) spl0();
338: #ifdef DISKMON
339: i = 0;
340: dp = bp->av_forw;
341: while ((dp->b_flags & B_HEAD) == 0) {
342: i++;
343: dp = dp->av_forw;
344: }
345: if (i<64)
346: io_info.bufcount[i]++;
347: #endif
348: notavail(bp);
349: bp->b_flags |= B_CACHE;
350: return(bp);
351: }
352: if (major(dev) >= nblkdev)
353: panic("blkdev");
354: (void) spl6();
355: for (ep = &bfreelist[BQUEUES-1]; ep > bfreelist; ep--)
356: if (ep->av_forw != ep)
357: break;
358: if (ep == bfreelist) { /* no free blocks at all */
359: ep->b_flags |= B_WANTED;
360: sleep((caddr_t)ep, PRIBIO+1);
361: goto loop;
362: }
363: (void) spl0();
364: bp = ep->av_forw;
365: notavail(bp);
366: if (bp->b_flags & B_DELWRI) {
367: bp->b_flags |= B_ASYNC;
368: bwrite(bp);
369: goto loop;
370: }
371: bp->b_flags = B_BUSY;
372: bp->b_back->b_forw = bp->b_forw;
373: bp->b_forw->b_back = bp->b_back;
374: bp->b_forw = dp->b_forw;
375: bp->b_back = dp;
376: dp->b_forw->b_back = bp;
377: dp->b_forw = bp;
378: bp->b_dev = dev;
379: bp->b_blkno = dblkno;
380: return(bp);
381: }
382:
383: /*
384: * get an empty block,
385: * not assigned to any particular device
386: */
387: struct buf *
388: geteblk()
389: {
390: register struct buf *bp, *dp;
391: register int s;
392:
393: loop:
394: s = spl6();
395: for (dp = &bfreelist[BQUEUES-1]; dp > bfreelist; dp--)
396: if (dp->av_forw != dp)
397: break;
398: if (dp == bfreelist) { /* no free blocks */
399: dp->b_flags |= B_WANTED;
400: sleep((caddr_t)dp, PRIBIO+1);
401: goto loop;
402: }
403: (void) splx(s);
404: bp = dp->av_forw;
405: notavail(bp);
406: if (bp->b_flags & B_DELWRI) {
407: bp->b_flags |= B_ASYNC;
408: bwrite(bp);
409: goto loop;
410: }
411: bp->b_flags = B_BUSY|B_INVAL;
412: bp->b_back->b_forw = bp->b_forw;
413: bp->b_forw->b_back = bp->b_back;
414: bp->b_forw = dp->b_forw;
415: bp->b_back = dp;
416: dp->b_forw->b_back = bp;
417: dp->b_forw = bp;
418: bp->b_dev = (dev_t)NODEV;
419: return(bp);
420: }
421:
422: /*
423: * Wait for I/O completion on the buffer; return errors
424: * to the user.
425: */
426: iowait(bp)
427: register struct buf *bp;
428: {
429:
430: (void) spl6();
431: while ((bp->b_flags&B_DONE)==0)
432: sleep((caddr_t)bp, PRIBIO);
433: (void) spl0();
434: geterror(bp);
435: }
436:
437: #ifdef UNFAST
438: /*
439: * Unlink a buffer from the available list and mark it busy.
440: * (internal interface)
441: */
442: notavail(bp)
443: register struct buf *bp;
444: {
445: register s;
446:
447: s = spl6();
448: bp->av_back->av_forw = bp->av_forw;
449: bp->av_forw->av_back = bp->av_back;
450: bp->b_flags |= B_BUSY;
451: splx(s);
452: }
453: #endif
454:
455: /*
456: * Mark I/O complete on a buffer. If the header
457: * indicates a dirty page push completion, the
458: * header is inserted into the ``cleaned'' list
459: * to be processed by the pageout daemon. Otherwise
460: * release it if I/O is asynchronous, and wake
461: * up anyone waiting for it.
462: */
463: iodone(bp)
464: register struct buf *bp;
465: {
466: register int s;
467:
468: if (bp->b_flags & B_DONE)
469: panic("dup iodone");
470: bp->b_flags |= B_DONE;
471: if (bp->b_flags & B_DIRTY) {
472: if (bp->b_flags & B_ERROR)
473: panic("IO err in push");
474: s = spl6();
475: bp->av_forw = bclnlist;
476: bp->b_bcount = swsize[bp - swbuf];
477: bp->b_pfcent = swpf[bp - swbuf];
478: cnt.v_pgout++;
479: cnt.v_pgpgout += bp->b_bcount / NBPG;
480: bclnlist = bp;
481: if (bswlist.b_flags & B_WANTED)
482: wakeup((caddr_t)&proc[2]);
483: splx(s);
484: return;
485: }
486: if (bp->b_flags&B_ASYNC)
487: brelse(bp);
488: else {
489: bp->b_flags &= ~B_WANTED;
490: wakeup((caddr_t)bp);
491: }
492: }
493:
494: /*
495: * Zero the core associated with a buffer.
496: */
497: clrbuf(bp)
498: struct buf *bp;
499: {
500: register *p;
501: register c;
502:
503: p = bp->b_un.b_words;
504: c = BUFSIZE/sizeof(int);
505: do
506: *p++ = 0;
507: while (--c);
508: bp->b_resid = 0;
509: }
510:
511: /*
512: * swap I/O -
513: *
514: * If the flag indicates a dirty page push initiated
515: * by the pageout daemon, we map the page into the i th
516: * virtual page of process 2 (the daemon itself) where i is
517: * the index of the swap header that has been allocated.
518: * We simply initialize the header and queue the I/O but
519: * do not wait for completion. When the I/O completes,
520: * iodone() will link the header to a list of cleaned
521: * pages to be processed by the pageout daemon.
522: */
523: swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
524: struct proc *p;
525: swblk_t dblkno;
526: caddr_t addr;
527: int flag, nbytes;
528: dev_t dev;
529: unsigned pfcent;
530: {
531: register struct buf *bp;
532: register int c;
533: int p2dp;
534: register struct pte *dpte, *vpte;
535:
536: (void) spl6();
537: while (bswlist.av_forw == NULL) {
538: bswlist.b_flags |= B_WANTED;
539: sleep((caddr_t)&bswlist, PSWP+1);
540: }
541: bp = bswlist.av_forw;
542: bswlist.av_forw = bp->av_forw;
543: (void) spl0();
544:
545: bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
546: if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
547: if (rdflg == B_READ)
548: sum.v_pswpin += btoc(nbytes);
549: else
550: sum.v_pswpout += btoc(nbytes);
551: bp->b_proc = p;
552: if (flag & B_DIRTY) {
553: p2dp = ((bp - swbuf) * CLSIZE) * KLMAX;
554: dpte = dptopte(&proc[2], p2dp);
555: vpte = vtopte(p, btop(addr));
556: for (c = 0; c < nbytes; c += NBPG) {
557: if (vpte->pg_pfnum == 0 || vpte->pg_fod)
558: panic("swap bad pte");
559: *dpte++ = *vpte++;
560: }
561: bp->b_un.b_addr = (caddr_t)ctob(p2dp);
562: } else
563: bp->b_un.b_addr = addr;
564: while (nbytes > 0) {
565: c = imin(ctob(120), nbytes);
566: bp->b_bcount = c;
567: bp->b_blkno = dblkno;
568: bp->b_dev = dev;
569: if (flag & B_DIRTY) {
570: swpf[bp - swbuf] = pfcent;
571: swsize[bp - swbuf] = nbytes;
572: }
573: (*bdevsw[major(dev)].d_strategy)(bp);
574: if (flag & B_DIRTY) {
575: if (c < nbytes)
576: panic("big push");
577: return;
578: }
579: (void) spl6();
580: while((bp->b_flags&B_DONE)==0)
581: sleep((caddr_t)bp, PSWP);
582: (void) spl0();
583: bp->b_un.b_addr += c;
584: bp->b_flags &= ~B_DONE;
585: if (bp->b_flags & B_ERROR) {
586: if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE)
587: panic("hard IO err in swap");
588: swkill(p, (char *)0);
589: }
590: nbytes -= c;
591: dblkno += btoc(c);
592: }
593: (void) spl6();
594: bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
595: bp->av_forw = bswlist.av_forw;
596: bswlist.av_forw = bp;
597: if (bswlist.b_flags & B_WANTED) {
598: bswlist.b_flags &= ~B_WANTED;
599: wakeup((caddr_t)&bswlist);
600: wakeup((caddr_t)&proc[2]);
601: }
602: (void) spl0();
603: }
604:
605: /*
606: * If rout == 0 then killed on swap error, else
607: * rout is the name of the routine where we ran out of
608: * swap space.
609: */
610: swkill(p, rout)
611: struct proc *p;
612: char *rout;
613: {
614: char *mesg;
615:
616: printf("pid %d: ", p->p_pid);
617: if (rout)
618: printf(mesg = "killed due to no swap space\n");
619: else
620: printf(mesg = "killed on swap error\n");
621: uprintf("sorry, pid %d was %s", p->p_pid, mesg);
622: /*
623: * To be sure no looping (e.g. in vmsched trying to
624: * swap out) mark process locked in core (as though
625: * done by user) after killing it so noone will try
626: * to swap it out.
627: */
628: psignal(p, SIGKILL);
629: p->p_flag |= SULOCK;
630: }
631:
632: /*
633: * make sure all write-behind blocks
634: * on dev (or NODEV for all)
635: * are flushed out.
636: * (from umount and update)
637: */
638: bflush(dev)
639: dev_t dev;
640: {
641: register struct buf *bp;
642: register struct buf *flist;
643: register int s;
644:
645: loop:
646: s = spl6();
647: trace(TR_BFIN, dev, 1);
648: for (flist = bfreelist; flist < &bfreelist[BQUEUES]; flist++)
649: for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
650: if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
651: bp->b_flags |= B_ASYNC;
652: notavail(bp);
653: bwrite(bp);
654: goto loop;
655: }
656: }
657: trace(TR_BFOUT, s, 1);
658: (void) spl0();
659: }
660:
661: /*
662: * Raw I/O. The arguments are
663: * The strategy routine for the device
664: * A buffer, which will always be a special buffer
665: * header owned exclusively by the device for this purpose
666: * The device number
667: * Read/write flag
668: * Essentially all the work is computing physical addresses and
669: * validating them.
670: * If the user has the proper access privilidges, the process is
671: * marked 'delayed unlock' and the pages involved in the I/O are
672: * faulted and locked. After the completion of the I/O, the above pages
673: * are unlocked.
674: */
675: physio(strat, bp, dev, rw, mincnt)
676: int (*strat)();
677: register struct buf *bp;
678: unsigned (*mincnt)();
679: {
680: register int c;
681: char *a;
682: register int s;
683:
684: if (useracc(u.u_base,u.u_count,rw==B_READ?B_WRITE:B_READ) == NULL) {
685: u.u_error = EFAULT;
686: return;
687: }
688: s = spl6();
689: while (bp->b_flags&B_BUSY) {
690: bp->b_flags |= B_WANTED;
691: /*sleep((caddr_t)bp, PRIBIO+1);*/
692: switch(tsleep((caddr_t)bp, PRIBIO+1, 20)) {
693: case TS_OK:
694: continue;
695: case TS_SIG: /* can't happen at PRIBIO+1*/
696: continue;
697: case TS_TIME:
698: u.u_error = EIO;
699: (void) splx(s);
700: return;
701: }
702: }
703: (void) splx(s);
704: bp->b_error = 0;
705: bp->b_proc = u.u_procp;
706: bp->b_un.b_addr = u.u_base;
707: while (u.u_count != 0) {
708: bp->b_flags = B_BUSY | B_PHYS | rw;
709: bp->b_dev = dev;
710: bp->b_blkno = u.u_offset >> PGSHIFT;
711: bp->b_bcount = u.u_count;
712: (*mincnt)(bp);
713: c = bp->b_bcount;
714: u.u_procp->p_flag |= SPHYSIO;
715: vslock(a = bp->b_un.b_addr, c);
716: (*strat)(bp);
717: s = spl6();
718: while ((bp->b_flags&B_DONE) == 0)
719: sleep((caddr_t)bp, PRIBIO);
720: vsunlock(a, c, rw);
721: u.u_procp->p_flag &= ~SPHYSIO;
722: if (bp->b_flags&B_WANTED)
723: wakeup((caddr_t)bp);
724: (void) splx(s);
725: bp->b_un.b_addr += c;
726: u.u_count -= c;
727: u.u_offset += c;
728: if (bp->b_flags&B_ERROR)
729: break;
730: }
731: bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
732: u.u_count = bp->b_resid;
733: geterror(bp);
734: }
735:
736: /*ARGSUSED*/
737: unsigned
738: minphys(bp)
739: struct buf *bp;
740: {
741:
742: if (bp->b_bcount > 60 * 1024)
743: bp->b_bcount = 60 * 1024;
744: }
745:
746: /*
747: * Pick up the device's error number and pass it to the user;
748: * if there is an error but the number is 0 set a generalized
749: * code. Actually the latter is always true because devices
750: * don't yet return specific errors.
751: */
752: geterror(bp)
753: register struct buf *bp;
754: {
755:
756: if (bp->b_flags&B_ERROR)
757: if ((u.u_error = bp->b_error)==0)
758: u.u_error = EIO;
759: }
760:
761: /*
762: * Invalidate in core blocks belonging to closed or umounted filesystem
763: *
764: * This is not nicely done at all - the buffer ought to be removed from the
765: * hash chains & have its dev/blkno fields clobbered, but unfortunately we
766: * can't do that here, as it is quite possible that the block is still
767: * being used for i/o. Eventually, all disc drivers should be forced to
768: * have a close routine, which ought ensure that the queue is empty, then
769: * properly flush the queues. Until that happy day, this suffices for
770: * correctness. ... kre
771: */
772: binval(dev)
773: dev_t dev;
774: {
775: register struct buf *bp;
776: register struct bufhd *hp;
777: #define dp ((struct buf *)hp)
778:
779: for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
780: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
781: if (bp->b_dev == dev)
782: bp->b_flags |= B_INVAL;
783: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.