* 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_text.c 7.9 (Berkeley) 6/28/90
while ((xp)->x_flag & XLOCK) { \
sleep((caddr_t)(xp), PSWP); \
if ((xp)->x_flag & XWANT) \
(xp)->x_flag &= ~(XLOCK|XWANT); \
#define FREE_AT_HEAD(xp) { \
(xp)->x_forw->x_back = &(xp)->x_forw; \
#define FREE_AT_TAIL(xp) { \
*((xp)->x_back) = (xp)->x_forw; \
(xp)->x_forw->x_back = (xp)->x_back; \
* We place up to ``maxtextcache'' free text table entries on a free list
* to form an LRU cache. This causes the swap (but not RAM) resources to
* be saved. These text images are treated as "sticky", and are placed on
* the free list when unused. They may be reclaimed from the free list
* until reused. The cache changes to MRU once the maximum limit is
* reached since we just cease caching new texts rather than replacing
* the LRU one (should be fixed). All cached text resources may be
* reclaimed by calling xpurge(). Currently, swpexpand() and xalloc() do
* this if an attempted swap allocation fails.
* Note that although true "sticky" texts are handling in the same way,
* they are not considered part of the cache; i.e. they are not subject
* to the maximum limit nor are they purged with xpurge(). They are in
* a sense "locked down" cache entries.
struct text
*xhead
, **xtail
; /* text table free list */
int xcache
; /* number of "sticky" texts retained */
int maxtextcache
= -1; /* maximum number of "sticky" texts */
struct xstats xstats
; /* cache statistics */
register struct text
*xp
;
for (xp
= text
; xp
< textNTEXT
; xp
++)
* relinquish use of the shared text segment
register struct text
*xp
;
register struct vnode
*vp
;
if ((xp
= u
.u_procp
->p_textp
) == NULL
)
if (--xp
->x_count
== 0 &&
(VOP_GETATTR(vp
, &vattr
, u
.u_cred
) != 0 ||
(vattr
.va_mode
& VSVTX
) == 0)) {
if (xcache
>= maxtextcache
|| xp
->x_flag
& XTRC
||
vattr
.va_nlink
== 0) { /* XXX */
xp
->x_rssize
-= vmemfree(tptopte(u
.u_procp
, 0),
sleep((caddr_t
)&xp
->x_poip
, PSWP
+1);
if (xp
->x_flag
& XWRIT
) {
u
.u_procp
->p_textp
= NULL
;
* Attach to a shared text segment.
* If there is no shared text, just return.
* If there is, hook up to it:
* if it is not currently being used, it has to be read
* in from the vnode (vp); the written bit is set to force it
* to be written out as appropriate.
* If it is being used, but is not currently in core,
* a swap has to be done to get it back.
xalloc(vp
, ep
, toff
, cred
)
register struct vnode
*vp
;
register struct text
*xp
;
while ((xp
= vp
->v_text
) != NULL
) {
* Wait for text to be unlocked,
* then start over (may have changed state).
if (xp
->x_flag
& XCACHED
) {
xp
->x_flag
&= ~(XCACHED
|XUNUSED
);
if (ckey_cnt
[xp
->x_ckey
])
xp
->x_ckey
= getcodekey();
xp
->x_flag
= XLOAD
|XLOCK
;
xp
->x_size
= clrnd(btoc(ep
->a_text
));
if (vsxalloc(xp
) == NULL
) {
/* flush text cache and try again */
if (xpurge() == 0 || vsxalloc(xp
) == NULL
) {
swkill(p
, "xalloc: no swap space");
if ((p
->p_flag
& SPAGV
) == 0) {
(void) vn_rdwr(UIO_READ
, vp
,
(caddr_t
)ctob(tptov(p
, 0)),
UIO_USERSPACE
, (IO_UNIT
|IO_NODELOCKED
), cred
, (int *)0);
xp
->x_ckey
= getcodekey();
* Lock and unlock a text segment from swapping
register struct text
*xp
;
* Wait for xp to be unlocked if it is currently locked.
register struct text
*xp
;
register struct text
*xp
;
* Decrement the in-core usage count of a shared text segment,
* which must be locked. When the count drops to zero,
register struct text
*xp
;
if (--xp
->x_ccount
== 0) {
if (xp
->x_flag
& XWRIT
) {
vsswap(p
, tptopte(p
, 0), CTEXT
, 0, (int)xp
->x_size
,
(void) swap(p
, xp
->x_ptdaddr
,
(int)xp
->x_size
* sizeof (struct pte
),
B_WRITE
, B_PAGET
, swapdev_vp
, 0);
xp
->x_rssize
-= vmemfree(tptopte(p
, 0),
* Detach a process from the in-core text.
* External interface to xccdec, used when swapping out a process.
register struct text
*xp
;
if (xp
&& xp
->x_ccount
!= 0) {
* Free the swap image of all unused saved-text text segments
* which are from file system mp (used by umount system call).
register struct text
*xp
;
for (xp
= text
; xp
< textNTEXT
; xp
++)
if (xp
->x_vptr
!= NULL
&&
(mp
== NULL
|| (xp
->x_vptr
->v_mount
== mp
)) &&
(xp
->x_flag
& XLOCK
) == 0)
* Flush all cached text segments to reclaim swap space.
* Used during swap allocation when out of swap space.
register struct text
*xp
;
for (xp
= text
; xp
< textNTEXT
; xp
++)
if (xp
->x_vptr
&& (xp
->x_flag
& (XLOCK
|XCACHED
)) == XCACHED
) {
* remove a shared text segment from the text table, if possible.
register struct vnode
*vp
;
* remove text image from the text table.
* the use count must be zero.
register struct text
*xp
;
register struct vnode
*vp
;
vsxfree(xp
, (long)xp
->x_size
);
* Take care of text cache statistics
if (xp
->x_flag
& XCACHED
) {
if (xp
->x_flag
& XUNUSED
)
xp
->x_flag
&= ~(XCACHED
|XUNUSED
);
xstats
.alloc_cacheflush
++;
* Add a process to those sharing a text segment by
* getting the page tables and then linking to x_caddr.
register struct text
*xp
= p
->p_textp
;
p
->p_xlink
= xp
->x_caddr
;
register struct text
*xp
= p
->p_textp
;
xp
->x_caddr
= p
->p_xlink
;
for (q
= xp
->x_caddr
; q
->p_xlink
; q
= q
->p_xlink
)
* Replace p by q in a text incore linked list.
* Used by vfork(), internally.
register struct text
*xp
= q
->p_textp
;
q
->p_xlink
= xp
->x_caddr
;
* Invalidate the text associated with vp.
* Purge in core cache of pages associated with vp and kill all active
register struct text
*xp
;
if (xp
->x_flag
& XPAGV
) {
for (p
= xp
->x_caddr
; p
; p
= p
->p_xlink
) {
printf("pid %d killed due to text modification\n",
* Take care of the text cache.
* If there was a process still using the text just mark
* the text as XTRC so it won't be cached. If no one was
* using it then it is in the cache and we need to flush