V9/sys/sys/vmsubr.c

Compare this file to the similar file:
Show the results in this format:

/*	vmsubr.c	4.6	81/05/28	*/

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/vm.h"
#include "../h/proc.h"
#include "../machine/pte.h"
#include "../h/cmap.h"
#include "../h/inode.h"
#include "../h/buf.h"
#include "../h/text.h"

/*
 * Make uarea of process p addressible at kernel virtual
 * address uarea through sysmap locations starting at map.
 */
uaccess(p, map, uarea)
	register struct proc *p;
	struct pte *map;
	register struct user *uarea;
{
	register int i;
	register struct pte *mp = map;

	for (i = 0; i < UPAGES; i++) {
		*(int *)mp = 0;
		mp->pg_pfnum = p->p_addr[i].pg_pfnum;
		mp++;
	}
	vmaccess(map, (caddr_t)uarea, UPAGES);
}

/*
 * Validate the kernel map for size ptes which
 * start at ppte in the sysmap, and which map
 * kernel virtual addresses starting with vaddr.
 */
vmaccess(ppte, vaddr, size)
	register struct pte *ppte;
	register caddr_t vaddr;
	register int size;
{

	while (size != 0) {
		mapin(ppte, btop(vaddr), (unsigned)(*(int *)ppte & PG_PFNUM), 1,
			(int)(PG_V|PG_KW));
		ppte++;
		vaddr += NBPG;
		--size;
	}
}

/* 
 * Convert a pte pointer to
 * a virtual page number.
 */
ptetov(p, pte)
	register struct proc *p;
	register struct pte *pte;
{

	if (isatpte(p, pte))
		return (tptov(p, ptetotp(p, pte)));
	else if (isadpte(p, pte))
		return (dptov(p, ptetodp(p, pte)));
	else
		return (sptov(p, ptetosp(p, pte)));
}

/*
 * Convert a virtual page 
 * number to a pte address.
 */
struct pte *
vtopte(p, v)
	register struct proc *p;
	register unsigned v;
{

	if (isatsv(p, v))
		return (tptopte(p, vtotp(p, v)));
	else if (isadsv(p, v))
		return (dptopte(p, vtodp(p, v)));
	else 
		return (sptopte(p, vtosp(p, v)));
}

struct	buf *vbmap();
/*
 * Initialize the page tables for paging from an inode,
 * by scouring up the indirect blocks in order.
 * Corresponding area of memory should have been vmemfree()d
 * first or just created.
 */
vinifod(pte, fileno, ip, bstart, count)
	register struct fpte *pte;
	int fileno;
	register struct inode *ip;
	daddr_t bstart;
	size_t count;
{
	register int i, j;
	struct buf *bp;
	int indx;
	register daddr_t *pp;

	if(ip->i_fstyp)
		panic("vinifod, fstyp");
	if(fileno < PG_FMIN)
		panic("vinifod, fileno");
	while (count > 0) {
		if (bstart < NADDR - 3) {
			pte->pg_fod = 1;
			pte->pg_source = fileno - PG_FMIN;
			pte->pg_blkno = ip ?
				fsbtodb(ip->i_dev,ip->i_un.i_addr[bstart]) : 0;
			if (pte->pg_blkno == 0) {
				pte->pg_source = PG_FZERO - PG_FMIN;
				pte->pg_blkno = 0;
				cnt.v_nzfod += CLSIZE;
			} else if (fileno == PG_FTEXT)
				cnt.v_nexfod += CLSIZE;
			else
				panic("vinifod, vrpages set");
			for (j = 1; j < CLSIZE; j++)
				pte[j] = pte[0];
			pte += CLSIZE;
			bstart++;
			count -= CLSIZE;
		} else {
			bp = vbmap(ip, bstart);
			indx = (bstart - (NADDR - 3)) % NINDIR(ip->i_dev);
			i = imin((NINDIR(ip->i_dev) - indx) * CLSIZE, count);
			bstart += i / CLSIZE;
			count -= i;
			if (bp) {
				pp = &bp->b_un.b_daddr[indx];
				do {
					pte->pg_fod = 1;
					pte->pg_blkno = fsbtodb(ip->i_dev,*pp);
					pp++;
					if (pte->pg_blkno) {
						pte->pg_source = fileno - PG_FMIN;
						if (fileno == PG_FTEXT)
							cnt.v_nexfod += CLSIZE;
						else
							panic("vinifod, vrpages set");
					} else {
						pte->pg_source = PG_FZERO - PG_FMIN;
						pte->pg_blkno = 0;
						cnt.v_nzfod += CLSIZE;
					}
					for (j = 1; j < CLSIZE; j++)
						pte[j] = pte[0];
					pte += CLSIZE;
				} while ((i -= CLSIZE) > 0);
				brelse(bp);
			} else {
				cnt.v_nzfod += i;
				do {
					pte->pg_fod = 1;
					pte->pg_source = PG_FZERO - PG_FMIN;
					distcl(pte);
					pte += CLSIZE;
				} while ((i -= CLSIZE) > 0);
			}
		}
	}
}

/*
 * Vbmap returns a block full of indirect pointers for a given block offset
 * in a file.  It returns 0 if a missing address block was encountered,
 * in which case the pages can be normal zfod pages.
 */
struct buf *
vbmap(ip, bn)
register struct inode *ip;
daddr_t bn;
{
	register i;
	struct buf *bp;
	int j, sh;
	daddr_t nb;
	dev_t dev = ip->i_dev;

	if (bn < NADDR-3)
		panic("vbmap");
	if (ip == 0)
		return (0);

	/*
	 * addresses NADDR-3, NADDR-2, and NADDR-1
	 * have single, double, triple indirect blocks.
	 * the first step is to determine
	 * how many levels of indirection.
	 */
	sh = 0;
	nb = 1;
	bn -= NADDR-3;
	for (j = 3; j > 0; j--) {
		sh += NSHIFT(dev);
		nb <<= NSHIFT(dev);
		if(bn < nb)
			break;
		bn -= nb;
	}
	if (j == 0)
		goto noblk;

	/*
	 * fetch the address from the inode
	 */
	nb = ip->i_un.i_addr[NADDR-j];

	/*
	 * fetch through the indirect blocks
	 */
	for (;;) {
		if (nb == 0)
			return (0);
		bp = bread(dev, nb);
		if (bp->b_flags & B_ERROR) {
			brelse(bp);
			goto noblk;
		}
		if (j == 3)
			break;
		j++;
		sh -= NSHIFT(dev);
		i = (bn>>sh) & NMASK(dev);
		nb = bp->b_un.b_daddr[i];
		brelse(bp);
		if (nb == 0)
			goto noblk;
	}
	return (bp);

noblk:
	return ((struct buf *)0);
}