Commit | Line | Data |
---|---|---|
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 | */ | |
25 | swapin(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 | ||
70 | nomem: | |
71 | if (xp) | |
72 | xunlock(xp); | |
73 | return (0); | |
74 | } | |
75 | ||
76 | int 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 | */ | |
83 | swapout(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 | } | |
149 | out: | |
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 | */ | |
165 | swdspt(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 |
210 | check: |
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 |
227 | swpt(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 | } |