/* vmpage.c 2.2 2/10/80 */
register struct pte
*pte
;
register struct inode
*ip
;
int otime
, olbolt
, oicr
, a
, s
;
otime
= time
, olbolt
= lbolt
, oicr
= mfpr(ICR
);
v
= clbase(btop(virtaddr
));
if (pte->pg_v || (pte+1)->pg_v)
if ((pte+1)->pg_fod == 0)
if (((struct fpte *)pte)->pg_blkno != ((struct fpte *)(pte+1))->pg_blkno)
panic("pagein pg_blkno");
if (pte->pg_pfnum+1 != (pte+1)->pg_pfnum)
panic("pagein <> pfnum");
} else if ((pte+1)->pg_pfnum)
panic("pagein +1pfnum <> 0");
* 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
== MTEXT
&& cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
) {
sleep((caddr_t
)p
->p_textp
, PSWP
+1);
if (cmap
[pgtocm(pte
->pg_pfnum
)].c_flag
& MFREE
) {
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, vtotp(p
, v
), pte
);
a
= vmtime(otime
, olbolt
, oicr
);
vmfltmon(rmon
, a
, rmonmin
, rres
, NRMON
);
* Now prepare to bring the page in.
* We allocate the page before locking so we will
* be swappable if there is no free memory.
sleep((caddr_t
)&freemem
, PSWP
+2);
* Now 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.
VOID
memall(pte
, CLSIZE
, p
, type
);
pte
->pg_prot
= opte
.pg_prot
;
cmap
[pgtocm(pf
)].c_intrans
= 1;
p
->p_textp
->x_rssize
+= CLSIZE
;
distpte(p
->p_textp
, vtotp(p
, v
), pte
);
fileno
= ((struct fpte
*)&opte
)->pg_fileno
;
panic("pagein pg_fileno");
if (fileno
== PG_FZERO
) {
for (i
= 0; i
< CLSIZE
; i
++)
if (fileno
== PG_FTEXT
) {
panic("pagein PG_FTEXT");
dev
= p
->p_textp
->x_iptr
->i_dev
;
if (u
.u_ofile
[fileno
] == NULL
)
panic("pagein u.u_ofile");
ip
= u
.u_ofile
[fileno
]->f_inode
;
if ((u
.u_vrpages
[fileno
] -= CLSIZE
) <= 0) {
if (u
.u_vrpages
[fileno
] < 0)
panic("pagein u.u_vrpages");
panic("pagein i_vfdcnt");
daddr
= fsbtodb(((struct fpte
*)&opte
)->pg_blkno
);
if (bp
= baddr(dev
, dbtofsb(daddr
))) {
prot
= *(int *)pte
& PG_PROT
;
/* THIS ASSUMES THAT CLSIZE*NBPG==BSIZE */
bcopy(bp
->b_un
.b_addr
, ptob(v
), BSIZE
);
distpte(p
->p_textp
, vtotp(p
, v
), pte
);
daddr
= vtod(p
, v
, &u
.u_dmap
, &u
.u_smap
);
pte
->pg_vreadm
= opte
.pg_vreadm
;
swap(p
, daddr
, ptob(v
), ctob(CLSIZE
), B_READ
, B_PGIN
, dev
);
* Fix page table entries.
distpte(p
->p_textp
, vtotp(p
, v
), pte
);
p
->p_textp
->x_flag
|= XWRIT
;
wakeup((caddr_t
)p
->p_textp
);
a
= vmtime(otime
, olbolt
, oicr
) / 100;
vmfltmon(pmon
, a
, pmonmin
, pres
, NPMON
);
* Memall returned page locked. Unless
* this page is to be used in a raw transfer,
* we should unlock the page.
cmap
[pgtocm(pf
)].c_intrans
= 0;
if ((p
->p_flag
& SDLYU
) == 0)
tbiscl(v
); /* conservative */
* 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(), simulating the missing
* hardware reference bit, and cleaning pages and transferring
register struct proc
*rp
;
register struct text
*xp
;
register struct pte
*pte
;
int maxhand
= pgtocm(maxfree
);
* 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
) {
* 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, 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_flag
& (MLOCK
|MSYS
|MFREE
))
v
= tptov(rp
, c
->c_page
);
pte
= tptopte(rp
, c
->c_page
);
while (rp
->p_flag
& SNOVM
)
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 page is valid; now it is 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
, vtotp(rp
, v
), pte
);
* This check guarantees a minimal investment in
* swapped in processes, by protecting about small
* amount of data space from replacement. This
* prevents very large jobs from dragging everything
* into the ground when they are exhibiting atypical
* behaviour (e.g. LISP garbage collections.)
* Note that this is a rather flimsy replacement
* for working set size estimation. We expect
* most systems to have a reasonable amount of main
* memory, and thus this check will rarely have
* SHOULD DO SOMETHING SIMILAR FOR TEXT SEGMENTS.
if ((c
->c_flag
& MTEXT
) == 0) {
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 (pushes
> MAXPGIO
/ 2)
* If the process is being swapped out
* or about to exit, do not bother with its
if (rp
->p_flag
& (SLOCK
|SWEXIT
))
* 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 iodone and swap in bio.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
);
if (swpexpand(rp
->p_dsize
, rp
->p_ssize
,
&pushutl
.u_dmap
, &pushutl
.u_smap
) == 0) {
daddr
= vtod(rp
, v
, &pushutl
.u_dmap
, &pushutl
.u_smap
);
* Now committed to pushing the page...
mlock((unsigned)cmtopg(hand
));
distpte(xp
, vtotp(rp
, v
), pte
);
swap(rp
, daddr
, ptob(v
), ctob(CLSIZE
), B_WRITE
, B_DIRTY
, swapdev
);
* 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.
* Decrement the resident set size of the current
* text object/process, and put the page in the
* free list. Note that we don't give memfree the
* pte as its argument, since we don't want to destroy
* the pte. If it hasn't already been discarded
* it may yet have a chance to be reclaimed from
if ((c
->c_flag
& MGONE
) == 0)
* We managed to add a page to the free list,
* so we give ourselves another couple of trips
* Extremely unlikely, but we went around
* the loop twice and didn't get anywhere.
* Don't cycle, stop till the next clock tick.
* 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
;
pte
= dptopte(&proc
[2], btop(bp
->b_un
.b_addr
));
wakeup((caddr_t
)&xp
->x_poip
);
while (rp
->p_flag
& SNOVM
)
wakeup((caddr_t
)&rp
->p_poip
);
if ((c
->c_flag
& MGONE
) == 0) {
pte
= tptopte(xp
->x_caddr
, c
->c_page
);
pte
= dptopte(rp
, c
->c_page
);
pte
= 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
);