]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
6d2010ae | 2 | * Copyright (c) 2000-2010 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | /* | |
29 | * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce | |
30 | * support for mandatory and extensible security protections. This notice | |
31 | * is included in support of clause 2.2 (b) of the Apple Public License, | |
32 | * Version 2.0. | |
1c79356b A |
33 | */ |
34 | ||
1c79356b A |
35 | #include <sys/param.h> |
36 | #include <sys/systm.h> | |
37 | #include <sys/lock.h> | |
91447636 A |
38 | #include <sys/proc_internal.h> |
39 | #include <sys/kauth.h> | |
1c79356b A |
40 | #include <sys/buf.h> |
41 | #include <sys/uio.h> | |
91447636 | 42 | #include <sys/vnode_internal.h> |
1c79356b | 43 | #include <sys/namei.h> |
91447636 A |
44 | #include <sys/ubc_internal.h> |
45 | #include <sys/malloc.h> | |
6d2010ae A |
46 | #include <sys/user.h> |
47 | #if CONFIG_PROTECT | |
48 | #include <sys/cprotect.h> | |
49 | #endif | |
91447636 A |
50 | |
51 | #include <default_pager/default_pager_types.h> | |
52 | #include <default_pager/default_pager_object.h> | |
1c79356b | 53 | |
b0d623f7 | 54 | #include <security/audit/audit.h> |
e5568f75 A |
55 | #include <bsm/audit_kevents.h> |
56 | ||
1c79356b | 57 | #include <mach/mach_types.h> |
91447636 A |
58 | #include <mach/host_priv.h> |
59 | #include <mach/mach_traps.h> | |
60 | #include <mach/boolean.h> | |
61 | ||
62 | #include <kern/kern_types.h> | |
fe8ab488 | 63 | #include <kern/locks.h> |
1c79356b | 64 | #include <kern/host.h> |
91447636 | 65 | #include <kern/task.h> |
1c79356b A |
66 | #include <kern/zalloc.h> |
67 | #include <kern/kalloc.h> | |
91447636 A |
68 | #include <kern/assert.h> |
69 | ||
1c79356b | 70 | #include <libkern/libkern.h> |
1c79356b | 71 | |
91447636 A |
72 | #include <vm/vm_pageout.h> |
73 | #include <vm/vm_map.h> | |
74 | #include <vm/vm_kern.h> | |
1c79356b | 75 | #include <vm/vnode_pager.h> |
91447636 | 76 | #include <vm/vm_protos.h> |
2d21ac55 A |
77 | #if CONFIG_MACF |
78 | #include <security/mac_framework.h> | |
79 | #endif | |
1c79356b | 80 | |
fe8ab488 A |
81 | #include <pexpert/pexpert.h> |
82 | ||
83 | void macx_init(void); | |
84 | ||
85 | static lck_grp_t *macx_lock_group; | |
86 | static lck_mtx_t *macx_lock; | |
39236c6e | 87 | |
1c79356b A |
88 | /* |
89 | * temporary support for delayed instantiation | |
90 | * of default_pager | |
91 | */ | |
92 | int default_pager_init_flag = 0; | |
93 | ||
94 | struct bs_map bs_port_table[MAX_BACKING_STORE] = { | |
95 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
96 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
97 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
98 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
99 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
100 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
101 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
102 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
103 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, | |
104 | {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; | |
105 | ||
106 | /* ###################################################### */ | |
107 | ||
fe8ab488 A |
108 | /* |
109 | * Routine: macx_init | |
110 | * Function: | |
111 | * Initialize locks so that only one caller can change | |
112 | * state at a time. | |
113 | */ | |
114 | void | |
115 | macx_init(void) | |
116 | { | |
117 | macx_lock_group = lck_grp_alloc_init("macx", NULL); | |
118 | macx_lock = lck_mtx_alloc_init(macx_lock_group, NULL); | |
119 | } | |
1c79356b | 120 | |
55e303ae A |
121 | /* |
122 | * Routine: macx_backing_store_recovery | |
123 | * Function: | |
124 | * Syscall interface to set a tasks privilege | |
125 | * level so that it is not subject to | |
126 | * macx_backing_store_suspend | |
127 | */ | |
128 | int | |
129 | macx_backing_store_recovery( | |
91447636 | 130 | struct macx_backing_store_recovery_args *args) |
55e303ae | 131 | { |
91447636 | 132 | int pid = args->pid; |
55e303ae A |
133 | int error; |
134 | struct proc *p = current_proc(); | |
55e303ae | 135 | |
91447636 | 136 | if ((error = suser(kauth_cred_get(), 0))) |
55e303ae A |
137 | goto backing_store_recovery_return; |
138 | ||
139 | /* for now restrict backing_store_recovery */ | |
140 | /* usage to only present task */ | |
91447636 | 141 | if(pid != proc_selfpid()) { |
55e303ae A |
142 | error = EINVAL; |
143 | goto backing_store_recovery_return; | |
144 | } | |
145 | ||
146 | task_backing_store_privileged(p->task); | |
147 | ||
148 | backing_store_recovery_return: | |
55e303ae A |
149 | return(error); |
150 | } | |
151 | ||
152 | /* | |
153 | * Routine: macx_backing_store_suspend | |
154 | * Function: | |
155 | * Syscall interface to stop new demand for | |
156 | * backing store when backing store is low | |
157 | */ | |
158 | ||
159 | int | |
160 | macx_backing_store_suspend( | |
91447636 | 161 | struct macx_backing_store_suspend_args *args) |
55e303ae | 162 | { |
91447636 | 163 | boolean_t suspend = args->suspend; |
55e303ae | 164 | int error; |
55e303ae | 165 | |
fe8ab488 | 166 | lck_mtx_lock(macx_lock); |
91447636 | 167 | if ((error = suser(kauth_cred_get(), 0))) |
55e303ae A |
168 | goto backing_store_suspend_return; |
169 | ||
fe8ab488 | 170 | /* Multiple writers protected by macx_lock */ |
55e303ae A |
171 | vm_backing_store_disable(suspend); |
172 | ||
173 | backing_store_suspend_return: | |
fe8ab488 | 174 | lck_mtx_unlock(macx_lock); |
55e303ae A |
175 | return(error); |
176 | } | |
177 | ||
b0d623f7 | 178 | extern boolean_t backing_store_stop_compaction; |
39236c6e | 179 | extern boolean_t compressor_store_stop_compaction; |
b0d623f7 A |
180 | |
181 | /* | |
182 | * Routine: macx_backing_store_compaction | |
183 | * Function: | |
184 | * Turn compaction of swap space on or off. This is | |
185 | * used during shutdown/restart so that the kernel | |
186 | * doesn't waste time compacting swap files that are | |
187 | * about to be deleted anyway. Compaction is always | |
188 | * on by default when the system comes up and is turned | |
189 | * off when a shutdown/restart is requested. It is | |
190 | * re-enabled if the shutdown/restart is aborted for any reason. | |
fe8ab488 A |
191 | * |
192 | * This routine assumes macx_lock has been locked by macx_triggers -> | |
193 | * mach_macx_triggers -> macx_backing_store_compaction | |
b0d623f7 A |
194 | */ |
195 | ||
196 | int | |
197 | macx_backing_store_compaction(int flags) | |
198 | { | |
199 | int error; | |
200 | ||
fe8ab488 | 201 | lck_mtx_assert(macx_lock, LCK_MTX_ASSERT_OWNED); |
b0d623f7 A |
202 | if ((error = suser(kauth_cred_get(), 0))) |
203 | return error; | |
204 | ||
205 | if (flags & SWAP_COMPACT_DISABLE) { | |
206 | backing_store_stop_compaction = TRUE; | |
39236c6e A |
207 | compressor_store_stop_compaction = TRUE; |
208 | ||
209 | kprintf("backing_store_stop_compaction = TRUE\n"); | |
b0d623f7 A |
210 | |
211 | } else if (flags & SWAP_COMPACT_ENABLE) { | |
212 | backing_store_stop_compaction = FALSE; | |
39236c6e A |
213 | compressor_store_stop_compaction = FALSE; |
214 | ||
215 | kprintf("backing_store_stop_compaction = FALSE\n"); | |
b0d623f7 A |
216 | } |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | /* | |
222 | * Routine: macx_triggers | |
223 | * Function: | |
224 | * Syscall interface to set the call backs for low and | |
225 | * high water marks. | |
226 | */ | |
227 | int | |
228 | macx_triggers( | |
229 | struct macx_triggers_args *args) | |
230 | { | |
231 | int error; | |
232 | ||
fe8ab488 | 233 | lck_mtx_lock(macx_lock); |
b0d623f7 A |
234 | error = suser(kauth_cred_get(), 0); |
235 | if (error) | |
236 | return error; | |
237 | ||
fe8ab488 A |
238 | error = mach_macx_triggers(args); |
239 | ||
240 | lck_mtx_unlock(macx_lock); | |
241 | return error; | |
b0d623f7 A |
242 | } |
243 | ||
0b4c1975 A |
244 | |
245 | extern boolean_t dp_isssd; | |
39236c6e A |
246 | |
247 | /* | |
248 | * In the compressed pager world, the swapfiles are created by the kernel. | |
249 | * Well, all except the first one. That swapfile is absorbed by the kernel at | |
250 | * the end of the macx_swapon function (if swap is enabled). That's why | |
251 | * we allow the first invocation of macx_swapon to succeed. | |
252 | * | |
253 | * If the compressor pool is running low, the kernel messages the dynamic pager | |
254 | * on the port it has registered with the kernel. That port can transport 1 of 2 | |
255 | * pieces of information to dynamic pager: create a swapfile or delete a swapfile. | |
256 | * | |
257 | * We choose to transmit the former. So, that message tells dynamic pager | |
258 | * to create a swapfile and activate it by calling macx_swapon. | |
259 | * | |
260 | * We deny this new macx_swapon request. That leads dynamic pager to interpret the | |
261 | * failure as a serious error and notify all it's clients that swap is running low. | |
262 | * That's how we get the loginwindow "Resume / Force Quit Applications" dialog to appear. | |
263 | * | |
264 | * NOTE: | |
265 | * If the kernel has already created multiple swapfiles by the time the compressor | |
266 | * pool is running low (and it has to play this trick), dynamic pager won't be able to | |
267 | * create a file in user-space and, that too will lead to a similar notification blast | |
268 | * to all of it's clients. So, that behaves as desired too. | |
269 | */ | |
270 | boolean_t macx_swapon_allowed = TRUE; | |
0b4c1975 | 271 | |
1c79356b A |
272 | /* |
273 | * Routine: macx_swapon | |
274 | * Function: | |
275 | * Syscall interface to add a file to backing store | |
276 | */ | |
277 | int | |
278 | macx_swapon( | |
91447636 | 279 | struct macx_swapon_args *args) |
1c79356b | 280 | { |
91447636 A |
281 | int size = args->size; |
282 | vnode_t vp = (vnode_t)NULL; | |
1c79356b | 283 | struct nameidata nd, *ndp; |
1c79356b A |
284 | register int error; |
285 | kern_return_t kr; | |
286 | mach_port_t backing_store; | |
0b4e3aa0 | 287 | memory_object_default_t default_pager; |
1c79356b | 288 | int i; |
91447636 | 289 | off_t file_size; |
2d21ac55 A |
290 | vfs_context_t ctx = vfs_context_current(); |
291 | struct proc *p = current_proc(); | |
0b4c1975 A |
292 | int dp_cluster_size; |
293 | ||
fe8ab488 A |
294 | AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPON); |
295 | AUDIT_ARG(value32, args->priority); | |
296 | ||
297 | lck_mtx_lock(macx_lock); | |
298 | ||
39236c6e A |
299 | if (COMPRESSED_PAGER_IS_ACTIVE) { |
300 | if (macx_swapon_allowed == FALSE) { | |
fe8ab488 A |
301 | error = EINVAL; |
302 | goto swapon_bailout; | |
39236c6e | 303 | } else { |
39236c6e | 304 | macx_swapon_allowed = FALSE; |
fe8ab488 A |
305 | error = 0; |
306 | goto swapon_bailout; | |
39236c6e A |
307 | } |
308 | } | |
1c79356b | 309 | |
1c79356b A |
310 | ndp = &nd; |
311 | ||
91447636 | 312 | if ((error = suser(kauth_cred_get(), 0))) |
1c79356b A |
313 | goto swapon_bailout; |
314 | ||
1c79356b A |
315 | /* |
316 | * Get a vnode for the paging area. | |
317 | */ | |
6d2010ae | 318 | NDINIT(ndp, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, |
91447636 | 319 | ((IS_64BIT_PROCESS(p)) ? UIO_USERSPACE64 : UIO_USERSPACE32), |
b0d623f7 | 320 | (user_addr_t) args->filename, ctx); |
1c79356b A |
321 | |
322 | if ((error = namei(ndp))) | |
323 | goto swapon_bailout; | |
91447636 | 324 | nameidone(ndp); |
1c79356b A |
325 | vp = ndp->ni_vp; |
326 | ||
327 | if (vp->v_type != VREG) { | |
328 | error = EINVAL; | |
1c79356b A |
329 | goto swapon_bailout; |
330 | } | |
1c79356b | 331 | |
91447636 | 332 | /* get file size */ |
2d21ac55 A |
333 | if ((error = vnode_size(vp, &file_size, ctx)) != 0) |
334 | goto swapon_bailout; | |
335 | #if CONFIG_MACF | |
336 | vnode_lock(vp); | |
337 | error = mac_system_check_swapon(vfs_context_ucred(ctx), vp); | |
338 | vnode_unlock(vp); | |
339 | if (error) | |
1c79356b | 340 | goto swapon_bailout; |
2d21ac55 | 341 | #endif |
1c79356b | 342 | |
91447636 | 343 | /* resize to desired size if it's too small */ |
2d21ac55 | 344 | if ((file_size < (off_t)size) && ((error = vnode_setsize(vp, (off_t)size, 0, ctx)) != 0)) |
91447636 | 345 | goto swapon_bailout; |
1c79356b | 346 | |
6d2010ae A |
347 | #if CONFIG_PROTECT |
348 | { | |
6d2010ae | 349 | /* initialize content protection keys manually */ |
316670eb A |
350 | if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) { |
351 | goto swapon_bailout; | |
352 | } | |
6d2010ae A |
353 | } |
354 | #endif | |
355 | ||
356 | ||
0b4c1975 A |
357 | if (default_pager_init_flag == 0) { |
358 | start_def_pager(NULL); | |
359 | default_pager_init_flag = 1; | |
360 | } | |
361 | ||
1c79356b A |
362 | /* add new backing store to list */ |
363 | i = 0; | |
364 | while(bs_port_table[i].vp != 0) { | |
365 | if(i == MAX_BACKING_STORE) | |
366 | break; | |
367 | i++; | |
368 | } | |
369 | if(i == MAX_BACKING_STORE) { | |
370 | error = ENOMEM; | |
1c79356b A |
371 | goto swapon_bailout; |
372 | } | |
373 | ||
374 | /* remember the vnode. This vnode has namei() reference */ | |
375 | bs_port_table[i].vp = vp; | |
376 | ||
377 | /* | |
378 | * Look to see if we are already paging to this file. | |
379 | */ | |
380 | /* make certain the copy send of kernel call will work */ | |
0b4e3aa0 A |
381 | default_pager = MEMORY_OBJECT_DEFAULT_NULL; |
382 | kr = host_default_memory_manager(host_priv_self(), &default_pager, 0); | |
1c79356b A |
383 | if(kr != KERN_SUCCESS) { |
384 | error = EAGAIN; | |
1c79356b A |
385 | bs_port_table[i].vp = 0; |
386 | goto swapon_bailout; | |
387 | } | |
388 | ||
6d2010ae | 389 | if ((dp_isssd = vnode_pager_isSSD(vp)) == TRUE) { |
0b4c1975 A |
390 | /* |
391 | * keep the cluster size small since the | |
392 | * seek cost is effectively 0 which means | |
393 | * we don't care much about fragmentation | |
394 | */ | |
0b4c1975 A |
395 | dp_cluster_size = 2 * PAGE_SIZE; |
396 | } else { | |
397 | /* | |
398 | * use the default cluster size | |
399 | */ | |
0b4c1975 A |
400 | dp_cluster_size = 0; |
401 | } | |
0b4e3aa0 | 402 | kr = default_pager_backing_store_create(default_pager, |
1c79356b | 403 | -1, /* default priority */ |
0b4c1975 | 404 | dp_cluster_size, |
1c79356b | 405 | &backing_store); |
0b4e3aa0 A |
406 | memory_object_default_deallocate(default_pager); |
407 | ||
1c79356b A |
408 | if(kr != KERN_SUCCESS) { |
409 | error = ENOMEM; | |
1c79356b A |
410 | bs_port_table[i].vp = 0; |
411 | goto swapon_bailout; | |
412 | } | |
413 | ||
b0d623f7 A |
414 | /* Mark this vnode as being used for swapfile */ |
415 | vnode_lock_spin(vp); | |
416 | SET(vp->v_flag, VSWAP); | |
417 | vnode_unlock(vp); | |
418 | ||
1c79356b A |
419 | /* |
420 | * NOTE: we are able to supply PAGE_SIZE here instead of | |
421 | * an actual record size or block number because: | |
422 | * a: we do not support offsets from the beginning of the | |
423 | * file (allowing for non page size/record modulo offsets. | |
424 | * b: because allow paging will be done modulo page size | |
425 | */ | |
426 | ||
91447636 A |
427 | kr = default_pager_add_file(backing_store, (vnode_ptr_t) vp, |
428 | PAGE_SIZE, (int)(file_size/PAGE_SIZE)); | |
1c79356b A |
429 | if(kr != KERN_SUCCESS) { |
430 | bs_port_table[i].vp = 0; | |
431 | if(kr == KERN_INVALID_ARGUMENT) | |
432 | error = EINVAL; | |
433 | else | |
434 | error = ENOMEM; | |
b0d623f7 A |
435 | |
436 | /* This vnode is not to be used for swapfile */ | |
437 | vnode_lock_spin(vp); | |
438 | CLR(vp->v_flag, VSWAP); | |
439 | vnode_unlock(vp); | |
440 | ||
1c79356b A |
441 | goto swapon_bailout; |
442 | } | |
443 | bs_port_table[i].bs = (void *)backing_store; | |
444 | error = 0; | |
1c79356b | 445 | |
13fec989 | 446 | ubc_setthreadcred(vp, p, current_thread()); |
55e303ae | 447 | |
1c79356b | 448 | /* |
91447636 | 449 | * take a long term reference on the vnode to keep |
1c79356b A |
450 | * vnreclaim() away from this vnode. |
451 | */ | |
91447636 | 452 | vnode_ref(vp); |
1c79356b A |
453 | |
454 | swapon_bailout: | |
455 | if (vp) { | |
91447636 | 456 | vnode_put(vp); |
1c79356b | 457 | } |
fe8ab488 | 458 | lck_mtx_unlock(macx_lock); |
e5568f75 | 459 | AUDIT_MACH_SYSCALL_EXIT(error); |
6d2010ae A |
460 | |
461 | if (error) | |
462 | printf("macx_swapon FAILED - %d\n", error); | |
463 | else | |
464 | printf("macx_swapon SUCCESS\n"); | |
465 | ||
1c79356b A |
466 | return(error); |
467 | } | |
468 | ||
469 | /* | |
470 | * Routine: macx_swapoff | |
471 | * Function: | |
472 | * Syscall interface to remove a file from backing store | |
473 | */ | |
474 | int | |
475 | macx_swapoff( | |
91447636 | 476 | struct macx_swapoff_args *args) |
1c79356b | 477 | { |
91447636 | 478 | __unused int flags = args->flags; |
1c79356b A |
479 | kern_return_t kr; |
480 | mach_port_t backing_store; | |
481 | ||
482 | struct vnode *vp = 0; | |
483 | struct nameidata nd, *ndp; | |
484 | struct proc *p = current_proc(); | |
485 | int i; | |
486 | int error; | |
2d21ac55 | 487 | vfs_context_t ctx = vfs_context_current(); |
6d2010ae | 488 | int orig_iopol_disk; |
1c79356b | 489 | |
e5568f75 | 490 | AUDIT_MACH_SYSCALL_ENTER(AUE_SWAPOFF); |
91447636 | 491 | |
fe8ab488 A |
492 | lck_mtx_lock(macx_lock); |
493 | ||
1c79356b A |
494 | backing_store = NULL; |
495 | ndp = &nd; | |
496 | ||
91447636 | 497 | if ((error = suser(kauth_cred_get(), 0))) |
1c79356b A |
498 | goto swapoff_bailout; |
499 | ||
1c79356b A |
500 | /* |
501 | * Get the vnode for the paging area. | |
502 | */ | |
6d2010ae | 503 | NDINIT(ndp, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, |
91447636 | 504 | ((IS_64BIT_PROCESS(p)) ? UIO_USERSPACE64 : UIO_USERSPACE32), |
b0d623f7 | 505 | (user_addr_t) args->filename, ctx); |
1c79356b A |
506 | |
507 | if ((error = namei(ndp))) | |
508 | goto swapoff_bailout; | |
91447636 | 509 | nameidone(ndp); |
1c79356b A |
510 | vp = ndp->ni_vp; |
511 | ||
512 | if (vp->v_type != VREG) { | |
513 | error = EINVAL; | |
1c79356b A |
514 | goto swapoff_bailout; |
515 | } | |
2d21ac55 A |
516 | #if CONFIG_MACF |
517 | vnode_lock(vp); | |
518 | error = mac_system_check_swapoff(vfs_context_ucred(ctx), vp); | |
519 | vnode_unlock(vp); | |
520 | if (error) | |
521 | goto swapoff_bailout; | |
522 | #endif | |
1c79356b A |
523 | |
524 | for(i = 0; i < MAX_BACKING_STORE; i++) { | |
525 | if(bs_port_table[i].vp == vp) { | |
1c79356b A |
526 | break; |
527 | } | |
528 | } | |
529 | if (i == MAX_BACKING_STORE) { | |
530 | error = EINVAL; | |
1c79356b A |
531 | goto swapoff_bailout; |
532 | } | |
533 | backing_store = (mach_port_t)bs_port_table[i].bs; | |
534 | ||
39236c6e A |
535 | orig_iopol_disk = proc_get_task_policy(current_task(), current_thread(), |
536 | TASK_POLICY_INTERNAL, TASK_POLICY_IOPOL); | |
6d2010ae | 537 | |
39236c6e A |
538 | proc_set_task_policy(current_task(), current_thread(), TASK_POLICY_INTERNAL, |
539 | TASK_POLICY_IOPOL, IOPOL_THROTTLE); | |
6d2010ae | 540 | |
1c79356b | 541 | kr = default_pager_backing_store_delete(backing_store); |
6d2010ae | 542 | |
39236c6e A |
543 | proc_set_task_policy(current_task(), current_thread(), TASK_POLICY_INTERNAL, |
544 | TASK_POLICY_IOPOL, orig_iopol_disk); | |
6d2010ae | 545 | |
1c79356b A |
546 | switch (kr) { |
547 | case KERN_SUCCESS: | |
548 | error = 0; | |
549 | bs_port_table[i].vp = 0; | |
1c79356b | 550 | /* This vnode is no longer used for swapfile */ |
b0d623f7 | 551 | vnode_lock_spin(vp); |
1c79356b | 552 | CLR(vp->v_flag, VSWAP); |
b0d623f7 | 553 | vnode_unlock(vp); |
1c79356b | 554 | |
91447636 A |
555 | /* get rid of macx_swapon() "long term" reference */ |
556 | vnode_rele(vp); | |
1c79356b | 557 | |
1c79356b A |
558 | break; |
559 | case KERN_FAILURE: | |
560 | error = EAGAIN; | |
561 | break; | |
562 | default: | |
563 | error = EAGAIN; | |
564 | break; | |
565 | } | |
566 | ||
567 | swapoff_bailout: | |
568 | /* get rid of macx_swapoff() namei() reference */ | |
569 | if (vp) | |
91447636 | 570 | vnode_put(vp); |
fe8ab488 | 571 | lck_mtx_unlock(macx_lock); |
e5568f75 | 572 | AUDIT_MACH_SYSCALL_EXIT(error); |
6d2010ae A |
573 | |
574 | if (error) | |
575 | printf("macx_swapoff FAILED - %d\n", error); | |
576 | else | |
577 | printf("macx_swapoff SUCCESS\n"); | |
578 | ||
1c79356b A |
579 | return(error); |
580 | } | |
91447636 A |
581 | |
582 | /* | |
583 | * Routine: macx_swapinfo | |
584 | * Function: | |
585 | * Syscall interface to get general swap statistics | |
586 | */ | |
39236c6e A |
587 | extern uint64_t vm_swap_get_total_space(void); |
588 | extern uint64_t vm_swap_get_used_space(void); | |
589 | extern uint64_t vm_swap_get_free_space(void); | |
590 | extern boolean_t vm_swap_up; | |
591 | ||
91447636 A |
592 | int |
593 | macx_swapinfo( | |
594 | memory_object_size_t *total_p, | |
595 | memory_object_size_t *avail_p, | |
596 | vm_size_t *pagesize_p, | |
597 | boolean_t *encrypted_p) | |
598 | { | |
599 | int error; | |
600 | memory_object_default_t default_pager; | |
601 | default_pager_info_64_t dpi64; | |
602 | kern_return_t kr; | |
603 | ||
604 | error = 0; | |
39236c6e A |
605 | if (COMPRESSED_PAGER_IS_ACTIVE) { |
606 | ||
607 | if (vm_swap_up == TRUE) { | |
608 | ||
609 | *total_p = vm_swap_get_total_space(); | |
610 | *avail_p = vm_swap_get_free_space(); | |
fe8ab488 | 611 | *pagesize_p = (vm_size_t)PAGE_SIZE_64; |
39236c6e A |
612 | *encrypted_p = TRUE; |
613 | ||
614 | } else { | |
615 | ||
616 | *total_p = 0; | |
617 | *avail_p = 0; | |
618 | *pagesize_p = 0; | |
619 | *encrypted_p = FALSE; | |
620 | } | |
621 | } else { | |
91447636 | 622 | |
91447636 | 623 | /* |
39236c6e | 624 | * Get a handle on the default pager. |
91447636 | 625 | */ |
39236c6e A |
626 | default_pager = MEMORY_OBJECT_DEFAULT_NULL; |
627 | kr = host_default_memory_manager(host_priv_self(), &default_pager, 0); | |
628 | if (kr != KERN_SUCCESS) { | |
629 | error = EAGAIN; /* XXX why EAGAIN ? */ | |
630 | goto done; | |
631 | } | |
632 | if (default_pager == MEMORY_OBJECT_DEFAULT_NULL) { | |
633 | /* | |
634 | * The default pager has not initialized yet, | |
635 | * so it can't be using any swap space at all. | |
636 | */ | |
637 | *total_p = 0; | |
638 | *avail_p = 0; | |
639 | *pagesize_p = 0; | |
640 | *encrypted_p = FALSE; | |
641 | goto done; | |
642 | } | |
643 | ||
644 | /* | |
645 | * Get swap usage data from default pager. | |
646 | */ | |
647 | kr = default_pager_info_64(default_pager, &dpi64); | |
648 | if (kr != KERN_SUCCESS) { | |
649 | error = ENOTSUP; | |
650 | goto done; | |
651 | } | |
91447636 | 652 | |
39236c6e A |
653 | /* |
654 | * Provide default pager info to caller. | |
655 | */ | |
656 | *total_p = dpi64.dpi_total_space; | |
657 | *avail_p = dpi64.dpi_free_space; | |
658 | *pagesize_p = dpi64.dpi_page_size; | |
659 | if (dpi64.dpi_flags & DPI_ENCRYPTED) { | |
660 | *encrypted_p = TRUE; | |
661 | } else { | |
662 | *encrypted_p = FALSE; | |
663 | } | |
91447636 A |
664 | |
665 | done: | |
39236c6e A |
666 | if (default_pager != MEMORY_OBJECT_DEFAULT_NULL) { |
667 | /* release our handle on default pager */ | |
668 | memory_object_default_deallocate(default_pager); | |
669 | } | |
91447636 A |
670 | } |
671 | return error; | |
672 | } |