BSD 4_3 release
[unix-history] / usr / src / sys / sys / vm_swap.c
CommitLineData
95f51977
C
1/*
2 * Copyright (c) 1982, 1986 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)vm_swap.c 7.1 (Berkeley) 6/5/86
7 */
8f0af4d3
C
8
9#include "../machine/pte.h"
10
95f51977
C
11#include "param.h"
12#include "systm.h"
13#include "dir.h"
14#include "user.h"
15#include "proc.h"
16#include "text.h"
17#include "map.h"
18#include "buf.h"
19#include "cmap.h"
20#include "vm.h"
8f0af4d3
C
21
22/*
23 * Swap a process in.
24 */
25swapin(p)
26 register struct proc *p;
27{
28 register struct text *xp;
29 register int i, s;
30
31 if (xp = p->p_textp)
32 xlock(xp);
33 p->p_szpt = clrnd(ctopt(p->p_ssize+p->p_dsize+p->p_tsize+UPAGES));
34 if (vgetpt(p, memall) == 0)
35 goto nomem;
36 if (vgetu(p, memall, Swapmap, &swaputl, (struct user *)0) == 0) {
37 vrelpt(p);
38 goto nomem;
39 }
40
41 swdspt(p, &swaputl, B_READ);
42 /*
43 * Make sure swdspt didn't smash u. pte's
44 */
45 for (i = 0; i < UPAGES; i++) {
46 if (Swapmap[i].pg_pfnum != p->p_addr[i].pg_pfnum)
47 panic("swapin");
48 }
49 vrelswu(p, &swaputl);
50 if (xp) {
51 xlink(p);
52 xunlock(xp);
53 }
54
55 p->p_rssize = 0;
95f51977 56 s = splclock();
8f0af4d3
C
57 if (p->p_stat == SRUN)
58 setrq(p);
59 p->p_flag |= SLOAD;
60 if (p->p_flag & SSWAP) {
61 swaputl.u_pcb.pcb_sswap = (int *)&u.u_ssave;
62 p->p_flag &= ~SSWAP;
63 }
64 splx(s);
65 p->p_time = 0;
66 multprog++;
67 cnt.v_swpin++;
68 return (1);
69
70nomem:
71 if (xp)
72 xunlock(xp);
73 return (0);
74}
75
76int xswapwant, xswaplock;
77/*
78 * Swap out process p.
79 * ds and ss are the old data size and the stack size
80 * of the process, and are supplied during page table
81 * expansion swaps.
82 */
83swapout(p, ds, ss)
84 register struct proc *p;
85 size_t ds, ss;
86{
87 register struct pte *map;
88 register struct user *utl;
8f0af4d3
C
89 int s;
90 int rc = 1;
91
92 s = 1;
93 map = Xswapmap;
94 utl = &xswaputl;
95 if (xswaplock & s)
96 if ((xswaplock & 2) == 0) {
97 s = 2;
98 map = Xswap2map;
99 utl = &xswap2utl;
100 }
8f0af4d3
C
101 while (xswaplock & s) {
102 xswapwant |= s;
103 sleep((caddr_t)map, PSWP);
104 }
105 xswaplock |= s;
8f0af4d3
C
106 uaccess(p, map, utl);
107 if (vgetswu(p, utl) == 0) {
95f51977 108 p->p_flag |= SLOAD;
8f0af4d3
C
109 rc = 0;
110 goto out;
111 }
112 utl->u_ru.ru_nswap++;
113 utl->u_odsize = ds;
114 utl->u_ossize = ss;
115 p->p_flag |= SLOCK;
116 if (p->p_textp) {
117 if (p->p_textp->x_ccount == 1)
118 p->p_textp->x_swrss = p->p_textp->x_rssize;
95f51977 119 xdetach(p->p_textp, p);
8f0af4d3
C
120 }
121 p->p_swrss = p->p_rssize;
95f51977
C
122 vsswap(p, dptopte(p, 0), CDATA, 0, (int)ds, &utl->u_dmap);
123 vsswap(p, sptopte(p, CLSIZE-1), CSTACK, 0, (int)ss, &utl->u_smap);
8f0af4d3
C
124 if (p->p_rssize != 0)
125 panic("swapout rssize");
126
127 swdspt(p, utl, B_WRITE);
95f51977
C
128 /*
129 * If freeing the user structure and kernel stack
130 * for the current process, have to run a bit longer
131 * using the pages which are about to be freed...
132 * vrelu will then block memory allocation by raising ipl.
133 */
8f0af4d3
C
134 vrelu(p, 1);
135 if ((p->p_flag & SLOAD) && (p->p_stat != SRUN || p != u.u_procp))
136 panic("swapout");
137 p->p_flag &= ~SLOAD;
138 vrelpt(p);
139 p->p_flag &= ~SLOCK;
140 p->p_time = 0;
141
142 multprog--;
143 cnt.v_swpout++;
144
145 if (runout) {
146 runout = 0;
147 wakeup((caddr_t)&runout);
148 }
149out:
150 xswaplock &= ~s;
151 if (xswapwant & s) {
152 xswapwant &= ~s;
153 wakeup((caddr_t)map);
154 }
8f0af4d3
C
155 return (rc);
156}
157
158/*
159 * Swap the data and stack page tables in or out.
160 * Only hard thing is swapping out when new pt size is different than old.
161 * If we are growing new pt pages, then we must spread pages with 2 swaps.
162 * If we are shrinking pt pages, then we must merge stack pte's into last
163 * data page so as not to lose them (and also do two swaps).
164 */
165swdspt(p, utl, rdwri)
166 register struct proc *p;
167 register struct user *utl;
168{
169 register int szpt, tsz, ssz;
170 int tdlast, slast, tdsz;
171 register struct pte *pte;
172 register int i;
173
174 szpt = clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES));
175 tsz = p->p_tsize / NPTEPG;
176 if (szpt == p->p_szpt) {
177 swptstat.pteasy++;
178 swpt(rdwri, p, 0, tsz,
179 (p->p_szpt - tsz) * NBPG - UPAGES * sizeof (struct pte));
180 goto check;
181 }
182 if (szpt < p->p_szpt)
183 swptstat.ptshrink++;
184 else
185 swptstat.ptexpand++;
186 ssz = clrnd(ctopt(utl->u_ossize+UPAGES));
187 if (szpt < p->p_szpt && utl->u_odsize && (utl->u_ossize+UPAGES)) {
188 /*
189 * Page tables shrinking... see if last text+data and
190 * last stack page must be merged... if so, copy
191 * stack pte's from last stack page to end of last
192 * data page, and decrease size of stack pt to be swapped.
193 */
194 tdlast = (p->p_tsize + utl->u_odsize) % (NPTEPG * CLSIZE);
195 slast = (utl->u_ossize + UPAGES) % (NPTEPG * CLSIZE);
196 if (tdlast && slast && tdlast + slast <= (NPTEPG * CLSIZE)) {
197 swptstat.ptpack++;
198 tdsz = clrnd(ctopt(p->p_tsize + utl->u_odsize));
199 bcopy((caddr_t)sptopte(p, utl->u_ossize - 1),
200 (caddr_t)&p->p_p0br[tdsz * NPTEPG - slast],
201 (unsigned)(slast * sizeof (struct pte)));
202 ssz -= CLSIZE;
203 }
204 }
205 if (ssz)
206 swpt(rdwri, p, szpt - ssz - tsz, p->p_szpt - ssz, ssz * NBPG);
207 if (utl->u_odsize)
208 swpt(rdwri, p, 0, tsz,
95f51977 209 (int)(clrnd(ctopt(p->p_tsize + utl->u_odsize)) - tsz) * NBPG);
8f0af4d3
C
210check:
211 for (i = 0; i < utl->u_odsize; i++) {
212 pte = dptopte(p, i);
213 if (pte->pg_v || pte->pg_fod == 0 && (pte->pg_pfnum||pte->pg_m))
214 panic("swdspt");
215 }
216 for (i = 0; i < utl->u_ossize; i++) {
217 pte = sptopte(p, i);
218 if (pte->pg_v || pte->pg_fod == 0 && (pte->pg_pfnum||pte->pg_m))
219 panic("swdspt");
220 }
221}
222
95f51977
C
223/*
224 * Swap a section of the page tables.
225 * Errors are handled at a lower level (by doing a panic).
226 */
8f0af4d3
C
227swpt(rdwri, p, doff, a, n)
228 int rdwri;
229 struct proc *p;
230 int doff, a, n;
231{
232
233 if (n <= 0)
234 return;
95f51977 235 (void)swap(p, p->p_swaddr + ctod(UPAGES) + ctod(doff),
8f0af4d3
C
236 (caddr_t)&p->p_p0br[a * NPTEPG], n, rdwri, B_PAGET, swapdev, 0);
237}