176 lines
5.4 KiB
C
176 lines
5.4 KiB
C
/*
|
|
* Copyright (c) 1986 Regents of the University of California.
|
|
* All rights reserved. The Berkeley software License Agreement
|
|
* specifies the terms and conditions for redistribution.
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/user.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/vm.h>
|
|
#include <sys/uio.h>
|
|
|
|
/*
|
|
* swap I/O
|
|
*/
|
|
void
|
|
swap (blkno, coreaddr, count, rdflg)
|
|
size_t blkno, coreaddr;
|
|
register int count;
|
|
int rdflg;
|
|
{
|
|
register struct buf *bp;
|
|
int s;
|
|
|
|
//printf ("swap (%u, %08x, %d, %s)\n", blkno, coreaddr, count, rdflg ? "R" : "W");
|
|
#ifdef UCB_METER
|
|
if (rdflg) {
|
|
cnt.v_kbin += (count + 1023) / 1024;
|
|
} else {
|
|
cnt.v_kbout += (count + 1023) / 1024;
|
|
}
|
|
#endif
|
|
bp = geteblk(); /* allocate a buffer header */
|
|
|
|
while (count) {
|
|
bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rdflg;
|
|
bp->b_dev = swapdev;
|
|
bp->b_bcount = count;
|
|
bp->b_blkno = blkno;
|
|
bp->b_addr = (caddr_t) coreaddr;
|
|
(*bdevsw[major(swapdev)].d_strategy) (bp);
|
|
s = splbio();
|
|
while ((bp->b_flags & B_DONE) == 0)
|
|
sleep ((caddr_t)bp, PSWP);
|
|
splx (s);
|
|
if ((bp->b_flags & B_ERROR) || bp->b_resid)
|
|
panic ("hard err: swap");
|
|
count -= count;
|
|
coreaddr += count;
|
|
blkno += btod (count);
|
|
}
|
|
brelse(bp);
|
|
}
|
|
|
|
/*
|
|
* Raw I/O. The arguments are
|
|
* The strategy routine for the device
|
|
* A buffer, which may be a special buffer header
|
|
* owned exclusively by the device for this purpose or
|
|
* NULL if one is to be allocated.
|
|
* The device number
|
|
* Read/write flag
|
|
* Essentially all the work is computing physical addresses and
|
|
* validating them.
|
|
*
|
|
* rewritten to use the iov/uio mechanism from 4.3bsd. the physbuf routine
|
|
* was inlined. essentially the chkphys routine performs the same task
|
|
* as the useracc routine on a 4.3 system. 3/90 sms
|
|
*
|
|
* If the buffer pointer is NULL then one is allocated "dynamically" from
|
|
* the system cache. the 'invalid' flag is turned on so that the brelse()
|
|
* done later doesn't place the buffer back in the cache. the 'phys' flag
|
|
* is left on so that the address of the buffer is recalcuated in getnewbuf().
|
|
* The BYTE/WORD stuff began to be removed after testing proved that either
|
|
* 1) the underlying hardware gives an error or 2) nothing bad happens.
|
|
* besides, 4.3BSD doesn't do the byte/word check and noone could remember
|
|
* why the byte/word check was added in the first place - likely historical
|
|
* paranoia. chkphys() inlined. 5/91 sms
|
|
*
|
|
* Refined (and streamlined) the flow by using a 'for' construct
|
|
* (a la 4.3Reno). Avoid allocating/freeing the buffer for each iovec
|
|
* element (i must have been confused at the time). 6/91-sms
|
|
*
|
|
* Finished removing the BYTE/WORD code as part of implementing the common
|
|
* raw read&write routines , systems had been running fine for several
|
|
* months with it ifdef'd out. 9/91-sms
|
|
*/
|
|
int
|
|
physio(strat, bp, dev, rw, uio)
|
|
void (*strat) (struct buf*);
|
|
register struct buf *bp;
|
|
dev_t dev;
|
|
int rw;
|
|
register struct uio *uio;
|
|
{
|
|
int error = 0, s, c, allocbuf = 0;
|
|
register struct iovec *iov;
|
|
|
|
if (! bp) {
|
|
allocbuf++;
|
|
bp = geteblk();
|
|
}
|
|
u.u_procp->p_flag |= SLOCK;
|
|
for ( ; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) {
|
|
iov = uio->uio_iov;
|
|
if (iov->iov_base >= iov->iov_base + iov->iov_len) {
|
|
error = EFAULT;
|
|
break;
|
|
}
|
|
/*
|
|
* Check that transfer is either entirely in the
|
|
* data or in the stack: that is, either
|
|
* the end is in the data or the start is in the stack
|
|
* (remember wraparound was already checked).
|
|
*/
|
|
if (baduaddr (iov->iov_base) ||
|
|
baduaddr (iov->iov_base + iov->iov_len - 1)) {
|
|
error = EFAULT;
|
|
break;
|
|
}
|
|
if (! allocbuf) {
|
|
s = splbio();
|
|
while (bp->b_flags & B_BUSY) {
|
|
bp->b_flags |= B_WANTED;
|
|
sleep((caddr_t)bp, PRIBIO+1);
|
|
}
|
|
splx(s);
|
|
}
|
|
bp->b_error = 0;
|
|
while (iov->iov_len) {
|
|
bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rw;
|
|
bp->b_dev = dev;
|
|
bp->b_addr = iov->iov_base;
|
|
bp->b_blkno = (unsigned) uio->uio_offset >> DEV_BSHIFT;
|
|
bp->b_bcount = iov->iov_len;
|
|
c = bp->b_bcount;
|
|
(*strat)(bp);
|
|
s = splbio();
|
|
while ((bp->b_flags & B_DONE) == 0)
|
|
sleep((caddr_t)bp, PRIBIO);
|
|
if (bp->b_flags & B_WANTED) /* rare */
|
|
wakeup((caddr_t)bp);
|
|
splx(s);
|
|
c -= bp->b_resid;
|
|
iov->iov_base += c;
|
|
iov->iov_len -= c;
|
|
uio->uio_resid -= c;
|
|
uio->uio_offset += c;
|
|
/* temp kludge for tape drives */
|
|
if (bp->b_resid || (bp->b_flags & B_ERROR))
|
|
break;
|
|
}
|
|
bp->b_flags &= ~(B_BUSY | B_WANTED);
|
|
error = geterror(bp);
|
|
/* temp kludge for tape drives */
|
|
if (bp->b_resid || error)
|
|
break;
|
|
}
|
|
if (allocbuf)
|
|
brelse(bp);
|
|
u.u_procp->p_flag &= ~SLOCK;
|
|
return(error);
|
|
}
|
|
|
|
int
|
|
rawrw (dev, uio, flag)
|
|
dev_t dev;
|
|
register struct uio *uio;
|
|
int flag;
|
|
{
|
|
return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, dev,
|
|
uio->uio_rw == UIO_READ ? B_READ : B_WRITE, uio));
|
|
}
|