* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)vm_page.c 7.14 (Berkeley) 6/28/90
#include "machine/mtpr.h"
#define uncachecl(pte) uncache(pte)
#define uncachecl(pte) uncache(pte), uncache((pte)+1)
#define uncachecl(pte) { \
for (ii = 0; ii < CLSIZE; ii++) \
#define uncache(pte) /* nothing */
#define uncachecl(pte) /* nothing */
* If page is allocated, but just not valid:
* Wait if intransit, else just revalidate
* Compute <vp,bn> from which page operation would take place
* If page is text page, and filling from file system or swap space:
* If in free list cache, reattach it and then done
* Allocate memory for page in
* If block here, restart because we could have swapped, etc.
* Lock process from swapping for duration
* Update pte's to reflect that page is intransit.
* If page is zero fill on demand:
* Clear pages and flush free list cache of stale cacheing
* for this swap page (e.g. before initializing again due
* If page is fill from file and in buffer cache:
* Copy the page from the buffer cache.
* If not a fill on demand:
* Determine swap address and cluster to page in
* Do the swap to bring the page in
* After swap validate the required new page
* Leave prepaged pages reclaimable (not valid)
* Update shared copies of text page tables
* Complete bookkeeping on pages brought in:
* Hash text pages into core hash structure
* Unlock pages (modulo raw i/o requirements)
* Flush translation buffer
#define pgtrace(e) trace(e,v,u.u_procp->p_pid)
int preptofree
= 1; /* send pre-paged pages to free list */
register struct pte
*pte
;
daddr_t bn
, bncache
, bnswap
;
int otime
, olbolt
, oicr
, s
;
otime
= time
, olbolt
= lbolt
, oicr
= mfpr(ICR
);
* Classify faulted page into a segment and get a pte
vsave
= v
= clbase(btop(virtaddr
));
/* will this ever happen? */
* If page is reclaimable, reclaim it.
* If page is text and intransit, sleep while it is intransit,
* If it is valid after the sleep, we are done.
* Otherwise we have to start checking again, since page could
* even be reclaimable now (we may have swapped for a long time).
if (pte
->pg_fod
== 0 && pte
->pg_pfnum
) {
if (type
== CTEXT
&& cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
) {
sleep((caddr_t
)p
->p_textp
, PSWP
+1);
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
sleep((caddr_t
)c
, PSWP
+1);
* If page is in the free list, then take
* it back into the resident set, updating
* the size recorded for the resident set.
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
sleep((caddr_t
)c
, PSWP
+1);
a
= vmtime(otime
, olbolt
, oicr
);
vmfltmon(rmon
, a
, rmonmin
, rres
, NRMON
);
* <vp,bn> is where data comes from/goes to.
* <vp,bncache> is where data is cached from/to.
* <swapdev_vp,bnswap> is where data will eventually go.
bnswap
= bncache
= bn
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
fileno
= ((struct fpte
*)pte
)->pg_fileno
;
bn
= ((struct fpte
*)pte
)->pg_blkno
;
bnswap
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
if (fileno
== PG_FTEXT
) {
panic("pagein PG_FTEXT");
if (VOP_BMAP(p
->p_textp
->x_vptr
, (daddr_t
)0, &vp
,
swkill(p
, "pagein: filesystem unmounted");
} else if (fileno
== PG_FZERO
) {
* Check for text detached but in free list.
* This can happen only if the page is filling
* from a inode or from the swap device, (e.g. not when reading
* in 407/410 execs to a zero fill page.)
* Honor lock bit to avoid races with pageouts.
if (type
== CTEXT
&& fileno
!= PG_FZERO
&& !nohash
) {
while ((c
= mfind(vp
, bncache
)) != 0) {
if (c
->c_type
!= CTEXT
|| c
->c_gone
== 0 ||
p
->p_textp
->x_rssize
+= CLSIZE
;
* Following code mimics memall().
for (j
= 0; j
< CLSIZE
; j
++) {
pte
->pg_prot
= opte
.pg_prot
;
if (c
->c_intrans
|| c
->c_want
)
panic("pagein intrans|want");
if (c
->c_page
!= vtotp(p
, v
))
panic("pagein c_page chgd");
c
->c_ndx
= p
->p_textp
- &text
[0];
munhash(swapdev_vp
, bnswap
);
* Wasn't reclaimable or reattachable.
* Have to prepare to bring the page in.
* We allocate the page before locking so we will
* be swappable if there is no free memory.
* If we block we have to start over, since anything
sk
= splimp(); /* lock memalls from here into kluster */
if (freemem
< CLSIZE
* KLMAX
) {
while (freemem
< CLSIZE
* KLMAX
)
sleep((caddr_t
)&freemem
, PSWP
+2);
* Now can get memory and committed to bringing in the page.
* Lock this process, get a page,
* construct the new pte, and increment
* the (process or text) resident set size.
if (memall(pte
, CLSIZE
, p
, type
) == 0)
pte
->pg_prot
= opte
.pg_prot
;
cmap
[pgtocm(pf
)].c_intrans
= 1;
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
* Two cases: either fill on demand (zero, or from file or text)
if (fileno
== PG_FZERO
|| fileno
== PG_FTEXT
) {
* Flush any previous text page use of this
munhash(swapdev_vp
, bnswap
);
* If zero fill, short-circuit hard work
* by just clearing pages.
if (fileno
== PG_FZERO
) {
for (i
= 0; i
< CLSIZE
; i
++) {
mtpr(P1DC
, (int)virtaddr
+ i
* NBPG
);
* Fill from inode. Try to find adjacent
* pages to bring in also.
v
= fodkluster(p
, v
, pte
, &klsize
, vp
, &bn
);
trace(TR_XFODMISS
, vp
, bn
);
* Fill from swap area. Try to find adjacent
* pages to bring in also.
v
= kluster(p
, v
, pte
, B_READ
, &klsize
,
(type
== CTEXT
) ? kltxt
:
((p
->p_flag
& SSEQL
) ? klseql
: klin
), bn
);
/* THIS COULD BE COMPUTED INCREMENTALLY... */
bncache
= bn
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
swerror
= swap(p
, bn
, ptob(v
), klsize
* ctob(CLSIZE
),
trace(TR_PGINDONE
, vsave
, u
.u_procp
->p_pid
);
cnt
.v_pgpgin
+= klsize
* CLSIZE
;
a
= vmtime(otime
, olbolt
, oicr
) / 100;
vmfltmon(pmon
, a
, pmonmin
, pres
, NPMON
);
* Fix page table entries.
* Only page requested in is validated, and rest of pages
* can be ``reclaimed''. This allows system to reclaim prepaged pages
* quickly if they are not used and memory is tight.
* Start with the page used so that pageout doesn't free it
xinval(p
->p_textp
->x_vptr
);
distpte(p
->p_textp
, (unsigned)vtotp(p
, vsave
), pte
);
p
->p_textp
->x_flag
|= XWRIT
;
wakeup((caddr_t
)p
->p_textp
);
* Memall returned page(s) locked. Unlock all
* pages in cluster. If locking pages for raw i/o
* leave the page which was required to be paged in locked,
* but still unlock others.
* If text pages, hash into the cmap situation table.
for (i
= 0; i
< klsize
; i
++) {
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
if (type
== CTEXT
&& c
->c_blkno
== 0 && bncache
&& !nohash
&&
bncache
+= btodb(CLBYTES
);
if (v
!= vsave
&& type
!= CTEXT
&& preptofree
&&
* Throw pre-paged data/stack pages at the
* bottom of the free list; leave pg_u clear.
* Text pages paged-in and allocated during the kluster
* must be validated, as they are now in the resident set.
if (v
!= vsave
&& type
== CTEXT
) {
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
* If process is declared fifo, memory is tight,
* and this was a data page-in, free memory
* klsdist pagein clusters away from the current fault.
if ((p
->p_flag
&SSEQL
) && freemem
< lotsfree
&& type
== CDATA
) {
int k
= (vtodp(p
, vsave
) / CLSIZE
) / klseql
;
dpageout(p
, k
* klseql
* CLSIZE
, klout
*CLSIZE
);
dpageout(p
, (k
- klsdist
) * klseql
* CLSIZE
, klout
*CLSIZE
);
dpageout(p
, (k
+ klsdist
) * klseql
* CLSIZE
, klout
*CLSIZE
);
* Take away n pages of data space
* starting at data page dp.
* Used to take pages away from sequential processes.
* Mimics pieces of code in pageout() below.
register struct pte
*pte
;
for (i
= 0; i
< n
; i
+= CLSIZE
, dp
+= CLSIZE
) {
if (pte
->pg_fod
|| pte
->pg_pfnum
== 0)
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
if (c
->c_lock
|| c
->c_free
)
if (bswlist
.av_forw
== NULL
)
v
= kluster(p
, dptov(p
, dp
), pte
, B_WRITE
,
&klsize
, klout
, (daddr_t
)0);
/* THIS ASSUMES THAT p == u.u_procp */
daddr
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
(void) swap(p
, daddr
, ptob(v
), klsize
* ctob(CLSIZE
),
B_WRITE
, B_DIRTY
, swapdev_vp
, pte
->pg_pfnum
);
* Setup the paging constants for the clock algorithm.
* Called after the system is initialized and the amount of memory
* and number of paging devices is known.
* Threshold constants are defined in machine/vmparam.h.
* Lotsfree is threshold where paging daemon turns on.
lotsfree
= LOTSFREE
/ NBPG
;
if (lotsfree
> LOOPPAGES
/ LOTSFREEFRACT
)
lotsfree
= LOOPPAGES
/ LOTSFREEFRACT
;
* Desfree is amount of memory desired free.
* If less than this for extended period, do swapping.
desfree
= DESFREE
/ NBPG
;
if (desfree
> LOOPPAGES
/ DESFREEFRACT
)
desfree
= LOOPPAGES
/ DESFREEFRACT
;
* Minfree is minimal amount of free memory which is tolerable.
minfree
= MINFREE
/ NBPG
;
if (minfree
> desfree
/ MINFREEFRACT
)
minfree
= desfree
/ MINFREEFRACT
;
* Maxpgio thresholds how much paging is acceptable.
* This figures that 2/3 busy on an arm is all that is
* tolerable for paging. We assume one operation per disk rev.
maxpgio
= (DISKRPM
* 2) / 3;
* Clock to scan using max of ~~10% of processor time for sampling,
* this estimated to allow maximum of 200 samples per second.
* This yields a ``fastscan'' of roughly (with CLSIZE=2):
if (fastscan
> LOOPPAGES
/ 5)
fastscan
= LOOPPAGES
/ 5;
* Set slow scan time to 1/2 the fast scan time.
* Calculate the swap allocation constants.
if (dmmin
< CLBYTES
/DEV_BSIZE
)
dmmin
= CLBYTES
/DEV_BSIZE
;
while (dmapsize(dmmin
, dmmax
/ 2) >= MAXDSIZ
&& dmmax
> dmmin
)
maxdmap
= dmapsize(dmmin
, dmmax
);
if (maxtsize
> dtob(NXDAD
* dmtext
))
maxtsize
= dtob(NXDAD
* dmtext
);
* Set up the initial limits on process VM.
* Set the maximum resident set size to be all
* of (reasonably) available memory. This causes
* any single, large process to start random page
* replacement once it fills memory.
u
.u_rlimit
[RLIMIT_STACK
].rlim_cur
= DFLSSIZ
;
u
.u_rlimit
[RLIMIT_STACK
].rlim_max
= MIN(MAXSSIZ
, maxdmap
);
u
.u_rlimit
[RLIMIT_DATA
].rlim_cur
= DFLDSIZ
;
u
.u_rlimit
[RLIMIT_DATA
].rlim_max
= MIN(MAXDSIZ
, maxdmap
);
u
.u_rlimit
[RLIMIT_RSS
].rlim_cur
= u
.u_rlimit
[RLIMIT_RSS
].rlim_max
=
ctob(LOOPPAGES
- desfree
);
proc
[0].p_maxrss
= LOOPPAGES
- desfree
;
register int i
, blk
, size
= 0;
for (i
= 0; i
< NDMAP
; i
++) {
* The page out daemon, which runs as process 2.
* As long as there are at least lotsfree pages,
* this process is not run. When the number of free
* pages stays in the range desfree to lotsfree,
* this daemon runs through the pages in the loop
* at a rate determined in vmsched(). Pageout manages
* two hands on the clock. The front hand moves through
* memory, clearing the valid bit (simulating a reference bit),
* and stealing pages from procs that are over maxrss.
* The back hand travels a distance behind the front hand,
* freeing the pages that have not been referenced in the time
* since the front hand passed. If modified, they are pushed to
* swap before being freed.
register int maxhand
= pgtocm(maxfree
);
register int fronthand
, backhand
;
* Set the two clock hands to be separated by a reasonable amount,
* but no more than 360 degrees apart.
fronthand
= HANDSPREAD
/ CLBYTES
;
if (fronthand
>= maxhand
)
* Before sleeping, look to see if there are any swap I/O headers
* in the ``cleaned'' list that correspond to dirty
* pages that have been pushed asynchronously. If so,
* empty the list by calling cleanup().
* N.B.: We guarantee never to block while the cleaned list is nonempty.
sleep((caddr_t
)&proc
[2], PSWP
+1);
while (nscan
< desscan
&& freemem
< lotsfree
) {
* If checkpage manages to add a page to the free list,
* we give ourselves another couple of trips around the loop.
if (checkpage(fronthand
, FRONT
))
if (checkpage(backhand
, BACK
))
if (++backhand
>= maxhand
)
if (++fronthand
>= maxhand
) {
* Extremely unlikely, but we went around
* the loop twice and didn't get anywhere.
* Don't cycle, stop till the next clock tick.
* An iteration of the clock pointer (hand) around the loop.
* Look at the page at hand. If it is a
* locked (for physical i/o e.g.), system (u., page table)
* or free, then leave it alone.
* Otherwise, if we are running the front hand,
* invalidate the page for simulation of the reference bit.
* If the proc is over maxrss, we take it.
* If running the back hand, check whether the page
* has been reclaimed. If not, free the page,
* pushing it to disk first if necessary.
checkpage(hand
, whichhand
)
register struct proc
*rp
;
register struct text
*xp
;
register struct pte
*pte
;
* Find a process and text pointer for the
* page, and a virtual page number in either the
* process or the text image.
if (c
->c_lock
|| c
->c_free
)
v
= tptov(rp
, c
->c_page
);
pte
= tptopte(rp
, c
->c_page
);
while (rp
->p_flag
& SNOVM
)
if (c
->c_type
== CDATA
) {
v
= dptov(rp
, c
->c_page
);
pte
= dptopte(rp
, c
->c_page
);
v
= sptov(rp
, c
->c_page
);
pte
= sptopte(rp
, c
->c_page
);
if (pte
->pg_pfnum
!= cmtopg(hand
))
* If any processes attached to the text page have used
* it, then mark this one used and on the following
* distpte, they will all be marked used.
if (c
->c_type
== CTEXT
&& tanyu(xp
, vtotp(rp
, v
)))
* If page is referenced, clear its reference bit.
* If page is not referenced, clear valid bit
* and add it to the free list.
* If page is valid; make invalid but reclaimable.
* If this pte is not valid, then it must be reclaimable
* and we can add it to the free list.
distpte(xp
, (unsigned)vtotp(rp
, v
), pte
);
if ((rp
->p_flag
& (SSEQL
|SUANOM
)) == 0 &&
rp
->p_rssize
<= rp
->p_maxrss
)
if (c
->c_type
!= CTEXT
) {
* Guarantee a minimal investment in data
* space for jobs in balance set.
if (rp
->p_rssize
< saferss
- rp
->p_slptime
)
* If the page is currently dirty, we
* have to arrange to have it cleaned before it
* can be freed. We mark it clean immediately.
* If it is reclaimed while being pushed, then modified
* again, we are assured of the correct order of
* writes because we lock the page during the write.
* This guarantees that a swap() of this process (and
* thus this page), initiated in parallel, will,
* in fact, push the page after us.
* The most general worst case here would be for
* a reclaim, a modify and a swapout to occur
* all before the single page transfer completes.
* If the process is being swapped out
* or about to exit, do not bother with its
if (rp
->p_flag
& (SLOCK
|SWEXIT
))
* Limit pushes to avoid saturating
if (pushes
> maxpgio
/ RATETOSCHEDPAGING
)
* Now carefully make sure that there will
* be a header available for the push so that
* we will not block waiting for a header in
* swap(). The reason this is important is
* that we (proc[2]) are the one who cleans
* dirty swap headers and we could otherwise
* deadlock waiting for ourselves to clean
* swap headers. The sleep here on &proc[2]
* is actually (effectively) a sleep on both
* ourselves and &bswlist, and this is known
* to swdone and swap in vm_swp.c. That is,
* &proc[2] will be awakened both when dirty
* headers show up and also to get the pageout
if (bswlist
.av_forw
== NULL
) {
bswlist
.b_flags
|= B_WANTED
;
sleep((caddr_t
)&proc
[2], PSWP
+2);
* Page disposition may have changed
* since process may have exec'ed,
* forked, exited or just about
* anything else... try this page
* frame again, from the top.
uaccess(rp
, Pushmap
, &pushutl
);
* Now committed to pushing the page...
if (c
->c_type
== CTEXT
) {
distpte(xp
, (unsigned)vtotp(rp
, v
), pte
);
v
= kluster(rp
, v
, pte
, B_WRITE
, &klsize
, klout
, (daddr_t
)0);
daddr
= vtod(rp
, v
, &pushutl
.u_dmap
, &pushutl
.u_smap
);
(void) swap(rp
, daddr
, ptob(v
), klsize
* ctob(CLSIZE
),
B_WRITE
, B_DIRTY
, swapdev_vp
, pte
->pg_pfnum
);
* The cleaning of this page will be
* completed later, in cleanup() called
* (synchronously) by us (proc[2]). In
* the meantime, the page frame is locked
* so no havoc can result.
return (1); /* well, it'll be free soon */
* Propagate valid bit changes.
* Decrement the resident set size of the current
* text object/process, and put the page in the
* free list. Don't detach the page yet;
* it may yet have a chance to be reclaimed from
distpte(xp
, (unsigned)vtotp(rp
, v
), pte
);
return (1); /* freed a page! */
* Process the ``cleaned'' list.
* Scan through the linked list of swap I/O headers
* and free the corresponding pages that have been
* cleaned by being written back to the paging area.
* If the page has been reclaimed during this time,
* we do not free the page. As they are processed,
* the swap I/O headers are removed from the cleaned
* list and inserted into the free list.
register struct proc
*rp
;
register struct text
*xp
;
register struct pte
*pte
;
if ((bp
= bclnlist
) == 0)
pte
= vtopte(&proc
[2], btop(bp
->b_un
.b_addr
));
for (i
= 0; i
< bp
->b_bcount
; i
+= CLSIZE
* NBPG
) {
if (pf
!= bp
->b_pfcent
) {
wakeup((caddr_t
)&xp
->x_poip
);
while (rp
->p_flag
& SNOVM
)
wakeup((caddr_t
)&rp
->p_poip
);
upte
= tptopte(xp
->x_caddr
, c
->c_page
);
upte
= dptopte(rp
, c
->c_page
);
upte
= sptopte(rp
, c
->c_page
);
bp
->av_forw
= bswlist
.av_forw
;
if (bswlist
.b_flags
& B_WANTED
) {
bswlist
.b_flags
&= ~B_WANTED
;
wakeup((caddr_t
)&bswlist
);
* Kluster locates pages adjacent to the argument pages
* that are immediately available to include in the pagein/pageout,
* and given the availability of memory includes them.
* It knows that the process image is contiguous in chunks;
* an assumption here is that CLSIZE * KLMAX is a divisor of dmmin,
* so that by looking at KLMAX chunks of pages, all such will
* necessarily be mapped swap contiguous.
kluster(p
, v
, pte0
, rw
, pkl
, klsize
, bn0
)
register struct pte
*pte
;
if (noklust
|| klsize
<= 1 || klsize
> KLMAX
|| (klsize
& (klsize
- 1)))
if (rw
== B_READ
&& freemem
< CLSIZE
* KLMAX
)
cl
= vtosp(p
, v
) / CLSIZE
;
clmax
= p
->p_ssize
/ CLSIZE
;
} else if (isadsv(p
, v
)) {
cl
= vtodp(p
, v
) / CLSIZE
;
clmax
= p
->p_dsize
/ CLSIZE
;
cl
= vtotp(p
, v
) / CLSIZE
;
clmax
= p
->p_textp
->x_size
/ CLSIZE
;
kloff
= cl
& (klsize
- 1);
for (k
= kloff
; --k
>= 0;) {
if (type
== CTEXT
&& rw
== B_READ
&& bn
) {
if (mfind(swapdev_vp
, bn
))
klback
= (kloff
- k
) - 1;
if ((cl
- kloff
) + klsize
> clmax
)
klmax
= clmax
- (cl
- kloff
);
for (k
= kloff
; ++k
< klmax
;) {
if (type
== CTEXT
&& rw
== B_READ
&& bn
) {
if (mfind(swapdev_vp
, bn
))
klforw
= (k
- kloff
) - 1;
if (klforw
+ klback
== 0)
*pkl
= klforw
+ klback
+ 1;
klicnt
[0]--, klicnt
[*pkl
- 1]++;
klocnt
[0]--, klocnt
[*pkl
- 1]++;
for (i
= 0; i
< *pkl
; i
++) {
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
if (memall(pte
, CLSIZE
, p
, type
) == 0)
pte
->pg_prot
= opte
.pg_prot
;
cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
= 1;
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
register struct pte
*pte
;
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
if (c
->c_lock
|| c
->c_intrans
)
* Fodkluster locates pages adjacent to the argument pages
* that are immediately available to include in the pagein,
* and given the availability of memory includes them.
* It wants to page in a file system block if it can.
fodkluster(p
, v0
, pte0
, pkl
, vp
, pbn
)
register struct pte
*pte
;
register struct fpte
*fpte
;
if (freemem
< KLMAX
|| nofodklust
)
vmax
= tptov(p
, clrnd(p
->p_tsize
) - CLSIZE
);
vmax
= dptov(p
, clrnd(p
->p_dsize
) - CLSIZE
);
fpte
= (struct fpte
*)pte0
;
for (klsize
= 1; klsize
< KLMAX
; klsize
++) {
if (fpte
->pg_blkno
!= bn
)
* Flush any previous text page use of this
bnswap
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
munhash(swapdev_vp
, bnswap
);
fpte
= (struct fpte
*)pte0
;
for (; klsize
< KLMAX
; klsize
++) {
if (fpte
->pg_blkno
!= bn
)
* Flush any previous text page use of this
bnswap
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
munhash(swapdev_vp
, bnswap
);
*pbn
-= klback
* btodb(CLBYTES
);
fodklcnt
[0]--; fodklcnt
[klsize
- 1]++;
for (i
= 0; i
< klsize
; i
++) {
if (memall(pte
, CLSIZE
, p
, type
) == 0)
pte
->pg_prot
= opte
.pg_prot
;
cmap
[pgtocm(pf
)].c_intrans
= 1;
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, (unsigned)vtotp(p
, v
), pte
);
* Examine the reference bits in the pte's of all
* processes linked to a particular text segment.
register struct pte
*pte
;
for (p
= xp
->x_caddr
; p
; p
= p
->p_xlink
) {