Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

299 lines
7.0 KiB
C

#ident "@(#)vm_subr.c 1.1 92/07/30 SMI"
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/mman.h>
#include <sys/vnode.h>
#include <sys/vm.h>
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/seg.h>
#include <vm/page.h>
#include <machine/pte.h>
#include <machine/seg_kmem.h>
/*
* rout is the name of the routine where we ran into problems.
*/
swkill(p, rout)
struct proc *p;
char *rout;
{
printf("pid %d: killed due to swap problems in %s\n", p->p_pid, rout);
uprintf("sorry, pid %d was killed due to swap problems in %s\n",
p->p_pid, rout);
/*
* To be sure no looping (e.g. in vmsched trying to
* swap out) mark process locked in core (as though
* done by user) after killing it so noone will try
* to swap it out.
*/
psignal(p, SIGKILL);
p->p_flag |= SULOCK;
}
/*
* Don't increase beyond NDMAXIO (this)
* for machines that cannot guarantee the
* integrity of dma xfers this size.
*
* Also- check <machine/machdep.c> to
* keep MBMAXPHYS in sync w/this.
*
*/
#define MAXPHYS (63 * 1024)
int maxphys = MAXPHYS;
void
minphys(bp)
struct buf *bp;
{
if (bp->b_bcount > maxphys)
bp->b_bcount = maxphys;
}
static caddr_t physio_bufs;
/*
* Raw I/O. The arguments are
* The strategy routine for the device
* A buffer, which will always be a special buffer
* header owned exclusively by the device for this purpose
* The device number
* Read/write flag
* Essentially all the work is computing physical addresses and
* validating them.
* If the user has the proper access privileges, the process is
* marked 'delayed unlock' and the pages involved in the I/O are
* faulted and locked. After the completion of the I/O, the above pages
* are unlocked.
*/
/*ARGSUSED*/
physio(strat, bp, dev, rw, mincnt, uio)
int (*strat)();
struct buf *bp;
dev_t dev;
int rw;
void (*mincnt)();
struct uio *uio;
{
register struct iovec *iov;
register int c;
faultcode_t fault_err;
char *a;
int s, error = 0;
int allocbuf = 0;
if (bp == NULL) {
/*
* Allocate buffer header.
* XXX Should use common function (getvbuf?) here and
* for swap buf headers.
*/
bp = (struct buf *)new_kmem_fast_zalloc(
&physio_bufs, sizeof (struct buf), 1, KMEM_SLEEP);
bp->b_flags = 0;
allocbuf = 1;
}
nextiov:
if (uio->uio_iovcnt == 0)
goto out;
iov = uio->uio_iov;
if (useracc(iov->iov_base, (u_int)iov->iov_len,
rw == B_READ ? B_WRITE : B_READ) == NULL) {
error = EFAULT;
goto out;
}
s = spl6();
while (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
(void) sleep((caddr_t)bp, PRIBIO+1);
}
(void) splx(s);
bp->b_error = 0;
bp->b_proc = u.u_procp;
bp->b_un.b_addr = iov->iov_base;
while (iov->iov_len > 0) {
bp->b_flags = B_BUSY | B_PHYS | rw;
bp->b_dev = dev;
bp->b_blkno = (uio->uio_fmode & FSETBLK) ?
uio->uio_offset : btodb(uio->uio_offset);
/*
* Don't count on b_addr remaining untouched by the
* code below (it may be reset because someone does
* a bp_mapin on the buffer) -- reset from the iov
* each time through, updating the iov's base address
* instead.
*/
bp->b_un.b_addr = iov->iov_base;
bp->b_bcount = iov->iov_len;
(*mincnt)(bp);
c = bp->b_bcount;
u.u_procp->p_flag |= SPHYSIO;
a = bp->b_un.b_addr;
fault_err = as_fault(u.u_procp->p_as, a, (u_int)c, F_SOFTLOCK,
rw == B_READ? S_WRITE : S_READ);
if (fault_err != 0) {
/*
* Even though the range of addresses were valid
* and had the correct permissions, we couldn't
* lock down all the pages for the access we needed.
* (e.g. we needed to allocate filesystem blocks
* for rw == B_READ but the file system was full).
*/
if (FC_CODE(fault_err) == FC_OBJERR)
error = FC_ERRNO(fault_err);
else
error = EFAULT;
bp->b_flags |= B_ERROR;
bp->b_error = error;
(void) spl6();
if (u.u_procp->p_threadcnt <= 1)
u.u_procp->p_flag &= ~SPHYSIO;
if (bp->b_flags & B_WANTED)
wakeup((caddr_t)bp);
(void) splx(s);
bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
goto out;
}
if (buscheck(bp) < 0) {
/*
* The io was not requested across legal pages.
*/
bp->b_flags |= B_ERROR;
bp->b_error = error = EFAULT;
} else {
(void) (*strat)(bp);
error = biowait(bp);
}
if (as_fault(u.u_procp->p_as, a, (u_int)c, F_SOFTUNLOCK,
rw == B_READ? S_WRITE : S_READ) != 0)
panic("physio unlock");
(void) spl6();
if (u.u_procp->p_threadcnt <= 1)
u.u_procp->p_flag &= ~SPHYSIO;
if (bp->b_flags & B_WANTED)
wakeup((caddr_t)bp);
(void) splx(s);
c -= bp->b_resid;
iov->iov_base += c;
iov->iov_len -= c;
uio->uio_resid -= c;
uio->uio_offset += (uio->uio_fmode & FSETBLK) ? btodb(c) : c;
/* temp kludge for tape drives */
if (bp->b_resid || error)
break;
}
bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
/* temp kludge for tape drives */
if (bp->b_resid || error)
goto out;
uio->uio_iov++;
uio->uio_iovcnt--;
goto nextiov;
out:
if (allocbuf)
kmem_fast_free(&physio_bufs, (caddr_t)bp);
return (error);
}
int
useracc(addr, count, access)
caddr_t addr;
u_int count;
int access;
{
u_int prot;
prot = PROT_USER | ((access == B_READ) ? PROT_READ : PROT_WRITE);
if (as_checkprot(u.u_procp->p_as, (addr_t)addr, count, prot) ==
A_SUCCESS)
return (1);
/*
* We may have failed above due to accessing a part of the stack
* that has not been expanded yet. This may happen when doing
* a physio() to a buffer on the stack for instance.
*/
if (grow((int)addr) == 0)
return (0); /* addr not part of stack expansion */
return (as_checkprot(u.u_procp->p_as, (addr_t)addr, count, prot) ==
A_SUCCESS);
}
int
kernacc(addr, count, access)
caddr_t addr;
u_int count;
int access;
{
u_int prot;
prot = ((access == B_READ) ? PROT_READ : PROT_WRITE);
return (as_checkprot(&kas, (addr_t)addr, count, prot) == A_SUCCESS);
}
/*
* Add pages [first, last) to page free list.
* Assumes that memory is allocated with no
* overlapping allocation ranges, and that increasing physical addresses
* imply increasing page struct addresses.
*/
memialloc(first, last)
register u_int first, last;
{
register struct page *p, *q;
p = page_numtopp(first);
q = page_numtopp(last - 1);
if (first >= last ||
p == (struct page *)NULL ||
q == (struct page *)NULL)
panic("memialloc");
for (; p <= q; p++)
page_free(p, 1);
}
/*
* Common code to core dump the UNIX data or stack segment.
*/
int
core_seg(vp, offset, addr, size, cred)
struct vnode *vp;
int offset;
register caddr_t addr;
int size;
struct ucred *cred;
{
register addr_t eaddr;
addr_t base;
u_int len;
register int err;
eaddr = (addr_t)(addr + size);
for (base = addr; base < eaddr; base += len) {
len = eaddr - base;
if (as_memory(u.u_procp->p_as, &base, &len) != A_SUCCESS)
return (0);
err = corefile_rdwr(UIO_WRITE, vp, base, (int)len,
offset + (base - (addr_t)addr),
UIO_USERSPACE, IO_UNIT, (int *)0, cred);
if (err)
return (err);
}
return (0);
}