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