]> git.saurik.com Git - apple/xnu.git/blame - bsd/vm/dp_backing_file.c
xnu-517.7.21.tar.gz
[apple/xnu.git] / bsd / vm / dp_backing_file.c
CommitLineData
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 */
52int default_pager_init_flag = 0;
53
54struct 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 */
78int
79macx_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
99backing_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
111int
112macx_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
125backing_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 */
135int
136macx_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
281swapon_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 */
295int
296macx_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
371swapoff_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}