]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
e5568f75 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
1c79356b | 11 | * |
e5568f75 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | #include <mach/boolean.h> | |
24 | #include <sys/param.h> | |
25 | #include <sys/systm.h> | |
26 | #include <sys/lock.h> | |
27 | #include <sys/proc.h> | |
28 | #include <sys/buf.h> | |
29 | #include <sys/uio.h> | |
30 | #include <sys/vnode.h> | |
31 | #include <sys/namei.h> | |
32 | #include <sys/ubc.h> | |
33 | ||
e5568f75 A |
34 | #include <bsm/audit_kernel.h> |
35 | #include <bsm/audit_kevents.h> | |
36 | ||
1c79356b A |
37 | #include <mach/mach_types.h> |
38 | #include <vm/vm_map.h> | |
39 | #include <vm/vm_kern.h> | |
40 | #include <kern/host.h> | |
1c79356b A |
41 | #include <kern/zalloc.h> |
42 | #include <kern/kalloc.h> | |
43 | #include <libkern/libkern.h> | |
44 | #include <sys/malloc.h> | |
45 | ||
46 | #include <vm/vnode_pager.h> | |
47 | ||
48 | /* | |
49 | * temporary support for delayed instantiation | |
50 | * of default_pager | |
51 | */ | |
52 | int default_pager_init_flag = 0; | |
53 | ||
54 | struct bs_map bs_port_table[MAX_BACKING_STORE] = { | |
55 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
56 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
57 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
58 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
59 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
60 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
61 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
62 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
63 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
64 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; | |
65 | ||
66 | /* ###################################################### */ | |
67 | ||
68 | ||
69 | #include <kern/assert.h> | |
70 | ||
55e303ae A |
71 | /* |
72 | * Routine: macx_backing_store_recovery | |
73 | * Function: | |
74 | * Syscall interface to set a tasks privilege | |
75 | * level so that it is not subject to | |
76 | * macx_backing_store_suspend | |
77 | */ | |
78 | int | |
79 | macx_backing_store_recovery( | |
80 | int pid) | |
81 | { | |
82 | int error; | |
83 | struct proc *p = current_proc(); | |
84 | boolean_t funnel_state; | |
85 | ||
86 | funnel_state = thread_funnel_set(kernel_flock, TRUE); | |
87 | if ((error = suser(p->p_ucred, &p->p_acflag))) | |
88 | goto backing_store_recovery_return; | |
89 | ||
90 | /* for now restrict backing_store_recovery */ | |
91 | /* usage to only present task */ | |
92 | if(pid != p->p_pid) { | |
93 | error = EINVAL; | |
94 | goto backing_store_recovery_return; | |
95 | } | |
96 | ||
97 | task_backing_store_privileged(p->task); | |
98 | ||
99 | backing_store_recovery_return: | |
100 | (void) thread_funnel_set(kernel_flock, FALSE); | |
101 | return(error); | |
102 | } | |
103 | ||
104 | /* | |
105 | * Routine: macx_backing_store_suspend | |
106 | * Function: | |
107 | * Syscall interface to stop new demand for | |
108 | * backing store when backing store is low | |
109 | */ | |
110 | ||
111 | int | |
112 | macx_backing_store_suspend( | |
113 | boolean_t suspend) | |
114 | { | |
115 | int error; | |
116 | struct proc *p = current_proc(); | |
117 | boolean_t funnel_state; | |
118 | ||
119 | funnel_state = thread_funnel_set(kernel_flock, TRUE); | |
120 | if ((error = suser(p->p_ucred, &p->p_acflag))) | |
121 | goto backing_store_suspend_return; | |
122 | ||
123 | vm_backing_store_disable(suspend); | |
124 | ||
125 | backing_store_suspend_return: | |
126 | (void) thread_funnel_set(kernel_flock, FALSE); | |
127 | return(error); | |
128 | } | |
129 | ||
1c79356b A |
130 | /* |
131 | * Routine: macx_swapon | |
132 | * Function: | |
133 | * Syscall interface to add a file to backing store | |
134 | */ | |
135 | int | |
136 | macx_swapon( | |
137 | char *filename, | |
138 | int flags, | |
139 | long size, | |
140 | long priority) | |
141 | { | |
142 | struct vnode *vp = 0; | |
143 | struct nameidata nd, *ndp; | |
144 | struct proc *p = current_proc(); | |
145 | pager_file_t pf; | |
146 | register int error; | |
147 | kern_return_t kr; | |
148 | mach_port_t backing_store; | |
0b4e3aa0 | 149 | memory_object_default_t default_pager; |
1c79356b A |
150 | int i; |
151 | boolean_t funnel_state; | |
152 | ||
153 | struct vattr vattr; | |
154 | ||
e5568f75 A |
155 | AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPON); |
156 | AUDIT_ARG(value, priority); | |
157 | ||
1c79356b A |
158 | funnel_state = thread_funnel_set(kernel_flock, TRUE); |
159 | ndp = &nd; | |
160 | ||
161 | if ((error = suser(p->p_ucred, &p->p_acflag))) | |
162 | goto swapon_bailout; | |
163 | ||
1c79356b A |
164 | if(default_pager_init_flag == 0) { |
165 | start_def_pager(NULL); | |
166 | default_pager_init_flag = 1; | |
167 | } | |
168 | ||
169 | /* | |
170 | * Get a vnode for the paging area. | |
171 | */ | |
e5568f75 | 172 | NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE, |
1c79356b A |
173 | filename, p); |
174 | ||
175 | if ((error = namei(ndp))) | |
176 | goto swapon_bailout; | |
177 | vp = ndp->ni_vp; | |
178 | ||
179 | if (vp->v_type != VREG) { | |
180 | error = EINVAL; | |
181 | VOP_UNLOCK(vp, 0, p); | |
182 | goto swapon_bailout; | |
183 | } | |
184 | UBCINFOCHECK("macx_swapon", vp); | |
185 | ||
186 | if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) { | |
187 | VOP_UNLOCK(vp, 0, p); | |
188 | goto swapon_bailout; | |
189 | } | |
190 | ||
191 | if (vattr.va_size < (u_quad_t)size) { | |
192 | vattr_null(&vattr); | |
193 | vattr.va_size = (u_quad_t)size; | |
194 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
195 | if (error) { | |
196 | VOP_UNLOCK(vp, 0, p); | |
197 | goto swapon_bailout; | |
198 | } | |
199 | } | |
200 | ||
201 | /* add new backing store to list */ | |
202 | i = 0; | |
203 | while(bs_port_table[i].vp != 0) { | |
204 | if(i == MAX_BACKING_STORE) | |
205 | break; | |
206 | i++; | |
207 | } | |
208 | if(i == MAX_BACKING_STORE) { | |
209 | error = ENOMEM; | |
210 | VOP_UNLOCK(vp, 0, p); | |
211 | goto swapon_bailout; | |
212 | } | |
213 | ||
214 | /* remember the vnode. This vnode has namei() reference */ | |
215 | bs_port_table[i].vp = vp; | |
216 | ||
217 | /* | |
218 | * Look to see if we are already paging to this file. | |
219 | */ | |
220 | /* make certain the copy send of kernel call will work */ | |
0b4e3aa0 A |
221 | default_pager = MEMORY_OBJECT_DEFAULT_NULL; |
222 | kr = host_default_memory_manager(host_priv_self(), &default_pager, 0); | |
1c79356b A |
223 | if(kr != KERN_SUCCESS) { |
224 | error = EAGAIN; | |
225 | VOP_UNLOCK(vp, 0, p); | |
226 | bs_port_table[i].vp = 0; | |
227 | goto swapon_bailout; | |
228 | } | |
229 | ||
0b4e3aa0 | 230 | kr = default_pager_backing_store_create(default_pager, |
1c79356b A |
231 | -1, /* default priority */ |
232 | 0, /* default cluster size */ | |
233 | &backing_store); | |
0b4e3aa0 A |
234 | memory_object_default_deallocate(default_pager); |
235 | ||
1c79356b A |
236 | if(kr != KERN_SUCCESS) { |
237 | error = ENOMEM; | |
238 | VOP_UNLOCK(vp, 0, p); | |
239 | bs_port_table[i].vp = 0; | |
240 | goto swapon_bailout; | |
241 | } | |
242 | ||
243 | /* | |
244 | * NOTE: we are able to supply PAGE_SIZE here instead of | |
245 | * an actual record size or block number because: | |
246 | * a: we do not support offsets from the beginning of the | |
247 | * file (allowing for non page size/record modulo offsets. | |
248 | * b: because allow paging will be done modulo page size | |
249 | */ | |
250 | ||
251 | VOP_UNLOCK(vp, 0, p); | |
252 | kr = default_pager_add_file(backing_store, vp, PAGE_SIZE, | |
253 | ((int)vattr.va_size)/PAGE_SIZE); | |
254 | if(kr != KERN_SUCCESS) { | |
255 | bs_port_table[i].vp = 0; | |
256 | if(kr == KERN_INVALID_ARGUMENT) | |
257 | error = EINVAL; | |
258 | else | |
259 | error = ENOMEM; | |
260 | goto swapon_bailout; | |
261 | } | |
262 | bs_port_table[i].bs = (void *)backing_store; | |
263 | error = 0; | |
264 | if (!ubc_hold(vp)) | |
265 | panic("macx_swapon: hold"); | |
266 | ||
267 | /* Mark this vnode as being used for swapfile */ | |
268 | SET(vp->v_flag, VSWAP); | |
269 | ||
55e303ae A |
270 | ubc_setcred(vp, p); |
271 | ||
1c79356b A |
272 | /* |
273 | * take an extra reference on the vnode to keep | |
274 | * vnreclaim() away from this vnode. | |
275 | */ | |
276 | VREF(vp); | |
277 | ||
278 | /* Hold on to the namei reference to the paging file vnode */ | |
279 | vp = 0; | |
280 | ||
281 | swapon_bailout: | |
282 | if (vp) { | |
283 | vrele(vp); | |
284 | } | |
1c79356b | 285 | (void) thread_funnel_set(kernel_flock, FALSE); |
e5568f75 | 286 | AUDIT_MACH_SYSCALL_EXIT(error); |
1c79356b A |
287 | return(error); |
288 | } | |
289 | ||
290 | /* | |
291 | * Routine: macx_swapoff | |
292 | * Function: | |
293 | * Syscall interface to remove a file from backing store | |
294 | */ | |
295 | int | |
296 | macx_swapoff( | |
297 | char *filename, | |
298 | int flags) | |
299 | { | |
300 | kern_return_t kr; | |
301 | mach_port_t backing_store; | |
302 | ||
303 | struct vnode *vp = 0; | |
304 | struct nameidata nd, *ndp; | |
305 | struct proc *p = current_proc(); | |
306 | int i; | |
307 | int error; | |
308 | boolean_t funnel_state; | |
309 | ||
e5568f75 | 310 | AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPOFF); |
1c79356b A |
311 | funnel_state = thread_funnel_set(kernel_flock, TRUE); |
312 | backing_store = NULL; | |
313 | ndp = &nd; | |
314 | ||
315 | if ((error = suser(p->p_ucred, &p->p_acflag))) | |
316 | goto swapoff_bailout; | |
317 | ||
1c79356b A |
318 | /* |
319 | * Get the vnode for the paging area. | |
320 | */ | |
e5568f75 | 321 | NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE, |
1c79356b A |
322 | filename, p); |
323 | ||
324 | if ((error = namei(ndp))) | |
325 | goto swapoff_bailout; | |
326 | vp = ndp->ni_vp; | |
327 | ||
328 | if (vp->v_type != VREG) { | |
329 | error = EINVAL; | |
330 | VOP_UNLOCK(vp, 0, p); | |
331 | goto swapoff_bailout; | |
332 | } | |
333 | ||
334 | for(i = 0; i < MAX_BACKING_STORE; i++) { | |
335 | if(bs_port_table[i].vp == vp) { | |
336 | backing_store; | |
337 | break; | |
338 | } | |
339 | } | |
340 | if (i == MAX_BACKING_STORE) { | |
341 | error = EINVAL; | |
342 | VOP_UNLOCK(vp, 0, p); | |
343 | goto swapoff_bailout; | |
344 | } | |
345 | backing_store = (mach_port_t)bs_port_table[i].bs; | |
346 | ||
347 | VOP_UNLOCK(vp, 0, p); | |
348 | kr = default_pager_backing_store_delete(backing_store); | |
349 | switch (kr) { | |
350 | case KERN_SUCCESS: | |
351 | error = 0; | |
352 | bs_port_table[i].vp = 0; | |
353 | ubc_rele(vp); | |
354 | /* This vnode is no longer used for swapfile */ | |
355 | CLR(vp->v_flag, VSWAP); | |
356 | ||
357 | /* get rid of macx_swapon() namei() reference */ | |
358 | vrele(vp); | |
359 | ||
360 | /* get rid of macx_swapon() "extra" reference */ | |
361 | vrele(vp); | |
362 | break; | |
363 | case KERN_FAILURE: | |
364 | error = EAGAIN; | |
365 | break; | |
366 | default: | |
367 | error = EAGAIN; | |
368 | break; | |
369 | } | |
370 | ||
371 | swapoff_bailout: | |
372 | /* get rid of macx_swapoff() namei() reference */ | |
373 | if (vp) | |
374 | vrele(vp); | |
375 | ||
1c79356b | 376 | (void) thread_funnel_set(kernel_flock, FALSE); |
e5568f75 | 377 | AUDIT_MACH_SYSCALL_EXIT(error); |
1c79356b A |
378 | return(error); |
379 | } |