]> git.saurik.com Git - apple/system_cmds.git/blame - dynamic_pager.tproj/dynamic_pager.c
system_cmds-597.1.1.tar.gz
[apple/system_cmds.git] / dynamic_pager.tproj / dynamic_pager.c
CommitLineData
1815bff5
A
1/* File created by Chris Youngworth, Apple Computer 2/11/99 */
2
3
4#define mig_external
5
6#include <mach/port.h>
7#include <mach/mach_error.h>
8#include <mach/mach_traps.h>
9#include <mach/mach.h>
10#ifndef MACH_BSD
11#define MACH_BSD
12#endif
1815bff5 13#include <mach/mach_syscalls.h>
ef8ad44b 14#include <mach/mach_traps.h>
1815bff5
A
15#include <mach/mig_errors.h>
16#include <sys/param.h>
c3a08f59 17#include <sys/mount.h>
1815bff5
A
18#include <sys/file.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <sys/sysctl.h>
22#include <sys/gmon.h>
34d340d7 23#include <sys/types.h>
1815bff5 24#include <errno.h>
1815bff5
A
25#include <limits.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <nlist.h>
30#include <ctype.h>
31#include <unistd.h>
32#include <paths.h>
34d340d7
A
33#include <dirent.h>
34
ef8ad44b 35#include <CoreFoundation/CoreFoundation.h>
1815bff5
A
36
37#include <default_pager/default_pager_types.h>
aaff5f01 38#include <default_pager_alertsServer.h>
1815bff5 39#include <backing_store_alerts.h>
aaff5f01 40#include <backing_store_triggersServer.h>
1815bff5 41
c3a08f59
A
42/*
43 * HI_WATER_DEFAULT set to this funny value to
44 * match the size that the low space application
45 * is asking for... need to keep MINIMUM_SIZE
46 * above this value.
47 */
48#define HI_WATER_DEFAULT 40000000
49#define MINIMUM_SIZE (1024 * 1024 * 64)
50#define MAXIMUM_SIZE (1024 * 1024 * 1024)
51
52#define MAX_LIMITS 8
53
8459d725
A
54#if TARGET_OS_EMBEDDED
55
56#include <System/sys/content_protection.h>
57
58#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS 1
59#include <SystemConfiguration/SystemConfiguration.h>
60
61enum {
62 VM_PAGING_MODE_DISABLED = 0,
63 VM_PAGING_MODE_FREEZE,
64 VM_PAGING_MODE_DYNAMIC
65};
66
67#define VM_FREEZE_SYSCTL "vm.freeze_enabled"
68#define FREEZE_FIXED_SWAP_SIZE (128 * 1024 * 1024)
69#endif
c3a08f59
A
70
71struct limit {
72 unsigned int size;
73 unsigned int low_water;
74} limits[MAX_LIMITS];
75
76
1815bff5 77int debug = 0;
c3a08f59 78int max_valid = 0;
1815bff5 79int file_count = 0;
c3a08f59
A
80unsigned int hi_water;
81unsigned int local_hi_water;
1815bff5 82int priority = 0;
c3a08f59 83int options = 0;
1815bff5
A
84char fileroot[512];
85
86
87/* global parameters for application notification option */
756446ec
A
88mach_port_t trigger_port = MACH_PORT_NULL;
89mach_port_t notify_port = MACH_PORT_NULL;
c3a08f59
A
90unsigned int notify_high = 0;
91unsigned int bs_recovery;
1815bff5
A
92
93/*
94void setprof __P((struct kvmvars *kvp, int state));
95void dumpstate __P((struct kvmvars *kvp));
96void reset __P((struct kvmvars *kvp));
97*/
98
99
100
101mach_msg_return_t
102server_alert_loop(
103 mach_msg_size_t max_size,
104 mach_port_t rcv_name,
105 mach_msg_options_t options)
106{
107 mig_reply_error_t *bufRequest = 0, *bufReply = 0;
108 register mach_msg_return_t mr;
109 register kern_return_t kr;
110
111 if ((kr = vm_allocate(mach_task_self(),
112 (vm_address_t *)&bufRequest,
113 max_size + MAX_TRAILER_SIZE,
114 TRUE)) != KERN_SUCCESS)
115 return kr;
116 mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
117 if ((kr = vm_allocate(mach_task_self(),
118 (vm_address_t *)&bufReply,
119 max_size + MAX_TRAILER_SIZE,
120 TRUE)) != KERN_SUCCESS)
121 return kr;
122 mlock(bufReply, max_size + MAX_TRAILER_SIZE);
123 while(TRUE) {
83f6dbe8
A
124 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
125 0, max_size, rcv_name,
126 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1815bff5
A
127 if (mr == MACH_MSG_SUCCESS) {
128 /* we have a request message */
129
130 if(!(default_pager_alerts_server(
131 &bufRequest->Head, &bufReply->Head)))
132 backing_store_triggers_server(
133 &bufRequest->Head, &bufReply->Head);
134
135 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
136 bufReply->RetCode != KERN_SUCCESS) {
137 if (bufReply->RetCode == MIG_NO_REPLY)
138 /*
139 * This return code is a little tricky--
140 * it appears that the demux routine found an
141 * error of some sort, but since that error
142 * would not normally get returned either to
143 * the local user or the remote one, we pretend it's
144 * ok.
145 */
146
147 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
148 mach_msg_destroy(&bufRequest->Head);
149 continue;
150 }
151
152 if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
153 /* no reply port, so destroy the reply */
154 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
155 mach_msg_destroy(&bufReply->Head);
156 } else {
157 break;
158 }
159 } else {
160 break;
161 }
162 }
163
164 (void)vm_deallocate(mach_task_self(),
165 (vm_address_t) bufRequest,
166 max_size + MAX_TRAILER_SIZE);
167 (void)vm_deallocate(mach_task_self(),
168 (vm_address_t) bufReply,
169 max_size + MAX_TRAILER_SIZE);
170 return KERN_FAILURE;
171
172}
173
174
175kern_return_t
176backing_store_triggers(dynamic_pager, hi_wat, flags, port)
177 mach_port_t dynamic_pager;
178 int hi_wat;
179 int flags;
180 mach_port_t port;
181{
c3a08f59
A
182 int cur_limits;
183
184 if (file_count > max_valid)
185 cur_limits = max_valid;
186 else
187 cur_limits = file_count;
188
189 if((hi_wat + limits[cur_limits].size) > limits[cur_limits].low_water)
1815bff5 190 return KERN_FAILURE; /* let ipc system clean up port */
756446ec
A
191
192 /* If there was a previous registration, throw it away */
193 if (notify_port != MACH_PORT_NULL) {
194 mach_port_deallocate(mach_task_self(), notify_port);
195 notify_port = MACH_PORT_NULL;
196 }
197
1815bff5
A
198 notify_port = port;
199 notify_high = hi_wat;
200 if(hi_water < notify_high) {
201 local_hi_water = notify_high;
202 } else {
203 local_hi_water = hi_water;
204 }
205 if(notify_high > hi_water) {
206 default_pager_space_alert(trigger_port, HI_WAT_ALERT);
207 }
208 return KERN_SUCCESS;
209}
210
211
212kern_return_t
213default_pager_space_alert(alert_port, flags)
214 mach_port_t alert_port;
215 int flags;
216{
217 char subfile[512];
c3a08f59 218 off_t filesize;
ef8ad44b 219 int error=0, fd=0;
756446ec 220 kern_return_t ret;
c3a08f59
A
221 int cur_limits;
222 unsigned int cur_size;
223 unsigned int notifications;
1815bff5 224
c3a08f59 225
1815bff5 226 if(flags & HI_WAT_ALERT) {
c3a08f59 227
1815bff5 228 file_count++;
c3a08f59
A
229
230 if (file_count > max_valid)
231 cur_limits = max_valid;
232 else
233 cur_limits = file_count;
234
235 cur_size = limits[cur_limits].size;
236 filesize = cur_size;
237
238 /*
239 * because the LO_WAT threshold changes relative to
240 * the size of the swap file we're creating
241 * we need to reset the LO_WAT_ALERT threshold each
242 * time we create a new swap file
243 */
244 if (limits[cur_limits].low_water)
245 notifications = HI_WAT_ALERT | LO_WAT_ALERT;
246 else
247 notifications = HI_WAT_ALERT;
248
1815bff5 249 sprintf(subfile, "%s%d", fileroot, file_count);
fc6d9e4b
A
250#if TARGET_OS_EMBEDDED
251 fd = open_dprotected_np(subfile, O_CREAT|O_EXCL|O_RDWR, PROTECTION_CLASS_F, 0, (mode_t)(S_IRUSR|S_IWUSR));
252#else
ef8ad44b 253 fd = open(subfile, O_CREAT|O_EXCL|O_RDWR,(mode_t)(S_IRUSR|S_IWUSR));
fc6d9e4b 254#endif
ef8ad44b 255 if (fd == -1) {
83f6dbe8
A
256 /* force error recovery below */
257 error = -1;
8459d725 258 }
8459d725
A
259
260 if(!error) {
ef8ad44b 261 error = fcntl(fd, F_SETSIZE, &filesize);
83f6dbe8 262 if(error) {
ef8ad44b 263 error = ftruncate(fd, filesize);
83f6dbe8
A
264 }
265 if(error)
266 unlink(subfile);
ef8ad44b 267 close(fd);
756446ec 268 }
c3a08f59 269
1815bff5 270 if(error == -1) {
1815bff5 271 file_count--;
c3a08f59
A
272
273 if (file_count > max_valid)
274 cur_limits = max_valid;
275 else
276 cur_limits = file_count;
277
278 if (limits[cur_limits].low_water)
279 notifications = HI_WAT_ALERT | LO_WAT_ALERT;
280 else
281 notifications = HI_WAT_ALERT;
ef8ad44b
A
282
283 notifications |= SWAP_FILE_CREATION_ERROR;
c3a08f59 284
1815bff5
A
285 local_hi_water = local_hi_water>>2;
286 if(notify_high >= (local_hi_water)) {
756446ec 287 if(notify_port != MACH_PORT_NULL) {
1815bff5
A
288 /* notify monitoring app of */
289 /* backing store shortage */
290 backing_store_alert(notify_port,
291 HI_WAT_ALERT);
292 mach_port_deallocate(mach_task_self(),
293 notify_port);
756446ec 294 notify_port = MACH_PORT_NULL;
1815bff5 295 notify_high = 0;
1815bff5
A
296 }
297 }
1815bff5
A
298 } else {
299 if(hi_water < notify_high) {
300 if(local_hi_water < notify_high) {
301 bs_recovery = notify_high - local_hi_water;
302 }
303 local_hi_water = notify_high;
304 } else {
305 if(local_hi_water < hi_water) {
306 bs_recovery = hi_water - local_hi_water;
307 }
308 local_hi_water = hi_water;
309 }
ef8ad44b
A
310 ret = macx_swapon((uint64_t)(uintptr_t)subfile,
311 flags, cur_size, priority);
c3a08f59 312
756446ec
A
313 if(ret) {
314 unlink(subfile);
315 file_count--;
c3a08f59
A
316
317 if (file_count > max_valid)
318 cur_limits = max_valid;
319 else
320 cur_limits = file_count;
321
322 if (limits[cur_limits].low_water)
323 notifications = HI_WAT_ALERT | LO_WAT_ALERT;
324 else
325 notifications = HI_WAT_ALERT;
326
756446ec
A
327 local_hi_water = local_hi_water>>2;
328 if(notify_high >= (local_hi_water)) {
329 if(notify_port != MACH_PORT_NULL) {
330 /* notify monitoring app of */
331 /* backing store shortage */
332 backing_store_alert(
333 notify_port,
334 HI_WAT_ALERT);
335 mach_port_deallocate(
336 mach_task_self(),
337 notify_port);
338 notify_port = MACH_PORT_NULL;
339 notify_high = 0;
340 }
341 }
c3a08f59 342 } else if(bs_recovery <= cur_size) {
1815bff5
A
343 if((bs_recovery != 0) && (notify_port)) {
344 backing_store_alert(notify_port,
345 LO_WAT_ALERT);
346 mach_port_deallocate(mach_task_self(),
347 notify_port);
756446ec 348 notify_port = MACH_PORT_NULL;
1815bff5 349 notify_high = 0;
1815bff5
A
350 bs_recovery = 0;
351 }
352 } else
c3a08f59 353 bs_recovery = bs_recovery-cur_size;
1815bff5 354 }
c3a08f59 355 macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port);
1815bff5
A
356 }
357 if(flags & LO_WAT_ALERT) {
1815bff5
A
358 sprintf(subfile, "%s%d", fileroot, file_count);
359 if(hi_water < notify_high) {
360 local_hi_water = notify_high;
361 } else {
362 local_hi_water = hi_water;
363 }
756446ec 364 if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) {
1815bff5
A
365 backing_store_alert(notify_port, LO_WAT_ALERT);
366 mach_port_deallocate(mach_task_self(), notify_port);
756446ec 367 notify_port = MACH_PORT_NULL;
1815bff5 368 notify_high = 0;
1815bff5
A
369 bs_recovery = 0;
370 }
ef8ad44b
A
371 if((error = macx_swapoff((uint64_t)(uintptr_t)subfile,
372 flags)) == 0) {
c3a08f59 373
1815bff5
A
374 unlink(subfile);
375 file_count--;
c3a08f59
A
376
377 if (file_count > max_valid)
378 cur_limits = max_valid;
379 else
380 cur_limits = file_count;
381 } else {
382 if (file_count > max_valid)
383 cur_limits = max_valid;
384 else
385 cur_limits = file_count;
1815bff5 386 }
c3a08f59
A
387 /*
388 * only need to reset the LO_WAT_ALERT... the HI_WAT size is fixed,
389 * it doesn't change even if the swap file size shrinks or grows
390 */
391 macx_triggers(local_hi_water, limits[cur_limits].low_water, LO_WAT_ALERT, alert_port);
1815bff5
A
392 }
393 return KERN_SUCCESS;
394}
395
396void
397wait_on_paging_trigger(trigger_port)
398 mach_port_t trigger_port;
399{
400 kern_return_t result;
401 result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
402 if (result != KERN_SUCCESS) {
403 fprintf(stderr, "dynamic_pager: default pager alert failed\n");
83f6dbe8 404 exit(EXIT_FAILURE);
1815bff5 405 }
83f6dbe8 406 exit(EXIT_SUCCESS);
1815bff5
A
407}
408
409void
2fc1e207 410paging_setup(flags, size, priority, low, high, encrypted)
1815bff5
A
411 int flags;
412 int size;
413 int priority;
414 int low;
415 int high;
2fc1e207 416 boolean_t encrypted;
1815bff5
A
417{
418 off_t filesize = size;
419 char subfile[512];
ef8ad44b 420 int error, fd = 0;
1815bff5
A
421
422 file_count = 0;
423 sprintf(subfile, "%s%d", fileroot, file_count);
fc6d9e4b
A
424#if TARGET_OS_EMBEDDED
425 fd = open_dprotected_np(subfile, O_CREAT|O_EXCL|O_RDWR, PROTECTION_CLASS_F, 0, ((mode_t)(S_IRUSR|S_IWUSR)));
426#else
ef8ad44b 427 fd = open(subfile, O_CREAT|O_EXCL|O_RDWR, ((mode_t)(S_IRUSR|S_IWUSR)));
fc6d9e4b 428#endif
ef8ad44b 429 if (fd == -1) {
83f6dbe8
A
430 fprintf(stderr, "dynamic_pager: cannot create paging file %s!\n",
431 subfile);
432 exit(EXIT_FAILURE);
433 }
83f6dbe8 434
8459d725 435
ef8ad44b 436 error = fcntl(fd, F_SETSIZE, &filesize);
756446ec 437 if(error) {
ef8ad44b 438 error = ftruncate(fd, filesize);
756446ec 439 }
ef8ad44b 440 close(fd);
83f6dbe8
A
441
442 if (error == -1) {
443 fprintf(stderr, "dynamic_pager: cannot extend paging file size %s to %llu!\n",
444 subfile, filesize);
445 exit(EXIT_FAILURE);
446 }
1815bff5 447
2fc1e207
A
448 if (macx_triggers(0, 0,
449 (encrypted
450 ? SWAP_ENCRYPT_ON
451 : SWAP_ENCRYPT_OFF),
452 MACH_PORT_NULL) != 0) {
453 fprintf(stderr,
454 "dynamic_pager: warning: "
455 "could not turn encrypted swap %s\n",
456 (encrypted ? "on" : "off"));
457 }
458
ef8ad44b 459 macx_swapon((uint64_t)(uintptr_t)subfile, flags, size, priority);
c3a08f59 460
1815bff5 461 if(hi_water) {
1c51fdde
A
462 mach_msg_type_name_t poly;
463
1815bff5
A
464 if (mach_port_allocate(mach_task_self(),
465 MACH_PORT_RIGHT_RECEIVE,
466 &trigger_port) != KERN_SUCCESS) {
83f6dbe8
A
467 fprintf(stderr,"dynamic_pager: allocation of trigger port failed\n");
468 exit(EXIT_FAILURE);
1815bff5 469 }
1c51fdde
A
470 /* create a send right on our local port */
471 mach_port_extract_right(mach_task_self(), trigger_port,
472 MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
1815bff5 473 macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
c3a08f59 474
1815bff5 475 if(low) {
c3a08f59 476 macx_triggers(high, low, LO_WAT_ALERT, trigger_port);
1815bff5
A
477 }
478 /* register control port for applications wishing to */
479 /* get backing store notifications or change dynamic */
480 /* pager settings. */
481 set_dp_control_port(mach_host_self(), trigger_port);
482 wait_on_paging_trigger(trigger_port);
483 }
83f6dbe8 484 exit(EXIT_SUCCESS);
1815bff5 485}
34d340d7
A
486
487static void
488clean_swap_directory(const char *path)
489{
490 DIR *dir;
491 struct dirent *entry;
492 char buf[1024];
493
494 dir = opendir(path);
495 if (dir == NULL) {
496 fprintf(stderr,"dynamic_pager: cannot open swap directory %s\n", path);
497 exit(EXIT_FAILURE);
498 }
499
500 while ((entry = readdir(dir)) != NULL) {
501 if (entry->d_namlen>= 4 && strncmp(entry->d_name, "swap", 4) == 0) {
502 snprintf(buf, sizeof buf, "%s/%s", path, entry->d_name);
503 unlink(buf);
504 }
505 }
506
507 closedir(dir);
508}
509
8459d725
A
510#define VM_PREFS_PLIST "/Library/Preferences/com.apple.virtualMemory.plist"
511#define VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY "DisableEncryptedSwap"
34d340d7
A
512
513static boolean_t
514should_encrypt_swap(void)
515{
516 CFPropertyListRef propertyList;
517 CFTypeID propertyListType;
518 CFStringRef errorString;
519 CFDataRef resourceData;
520 SInt32 errorCode;
521 CFURLRef fileURL;
8459d725
A
522 CFTypeRef disable_encrypted_swap;
523 boolean_t should_encrypt = TRUE;
524 boolean_t explicit_value = FALSE;
34d340d7
A
525
526 fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)VM_PREFS_PLIST, strlen(VM_PREFS_PLIST), false);
527 if (fileURL == NULL) {
528 /*fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), VM_PREFS_PLIST);*/
529 goto done;
530 }
531
532 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
533 /*fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), VM_PREFS_PLIST, (int)errorCode);*/
534 CFRelease(fileURL);
535 goto done;
536 }
537
538 CFRelease(fileURL);
539 propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
540 if (propertyList == NULL) {
541 /*fprintf(stderr, "%s: cannot get XML propertyList %s\n", getprogname(), VM_PREFS_PLIST);*/
542 CFRelease(resourceData);
543 goto done;
544 }
545
546 propertyListType = CFGetTypeID(propertyList);
547
548 if (propertyListType == CFDictionaryGetTypeID()) {
8459d725
A
549 disable_encrypted_swap = (CFTypeRef) CFDictionaryGetValue((CFDictionaryRef) propertyList, CFSTR(VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY));
550 if (disable_encrypted_swap == NULL) {
551 /* no value: use the default value i.e. encrypted swap ON */
552 } else if (CFGetTypeID(disable_encrypted_swap) != CFBooleanGetTypeID()) {
34d340d7 553 fprintf(stderr, "%s: wrong type for key \"%s\"\n",
8459d725 554 getprogname(), VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY);
34d340d7 555 /* bogus value, assume it's "true" for safety's sake */
8459d725
A
556 should_encrypt = TRUE;
557 explicit_value = TRUE;
34d340d7 558 } else {
8459d725
A
559 should_encrypt = CFBooleanGetValue((CFBooleanRef)disable_encrypted_swap) ? FALSE : TRUE;
560 explicit_value = TRUE;
34d340d7
A
561 }
562 }
563 else {
564 /*fprintf(stderr, "%s: invalid propertyList type %d (not a dictionary)\n", getprogname(), propertyListType);*/
565 }
566 CFRelease(resourceData);
567 CFRelease(propertyList);
568
569done:
570 if (! explicit_value) {
ef8ad44b
A
571#if TARGET_OS_EMBEDDED
572 should_encrypt = FALSE;
ef8ad44b 573#endif
34d340d7
A
574 }
575
576 return should_encrypt;
577}
578
8459d725
A
579#if TARGET_OS_EMBEDDED
580
581#define VM_PREFS_PAGING_MODE_PLIST "com.apple.virtualMemoryMode.plist"
582#define VM_PREFS_PAGING_MODE_KEY "Mode"
583
584static uint32_t
585get_paging_mode(void)
586{
587 SCPreferencesRef paging_prefs;
588 uint32_t paging_mode;
589
590 paging_mode = VM_PAGING_MODE_FREEZE; /* default */
591
592 paging_prefs = SCPreferencesCreate(NULL, CFSTR("dynamic_pager"), CFSTR(VM_PREFS_PAGING_MODE_PLIST));
593 if (paging_prefs) {
594 CFNumberRef value;
595
596 value = SCPreferencesGetValue(paging_prefs, CFSTR(VM_PREFS_PAGING_MODE_KEY));
597
598 if (value && (CFGetTypeID( value ) == CFNumberGetTypeID() ) ) {
599 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &paging_mode);
600 }
601
602 CFRelease(paging_prefs);
603 }
604
605 return paging_mode;
606}
607
608#endif
609
1815bff5
A
610int
611main(int argc, char **argv)
612{
613 extern char *optarg;
614 extern int optind;
615 char default_filename[] = "/private/var/vm/swapfile";
616 int ch;
ef8ad44b 617 int variable_sized = 1,flags=0;
34d340d7 618 boolean_t encrypted_swap;
8459d725
A
619 static char tmp[1024];
620 struct statfs sfs;
621 char *q;
622#if TARGET_OS_EMBEDDED
623 int err;
624 uint32_t paging_mode;
625 size_t paging_mode_length;
626#endif
34d340d7
A
627
628/*
629 setlinebuf(stdout);
630 setlinebuf(stderr);
631*/
1815bff5
A
632
633 seteuid(getuid());
634 strcpy(fileroot, default_filename);
635
ef8ad44b 636retry:
c3a08f59
A
637 limits[0].size = 20000000;
638 limits[0].low_water = 0;
639
640 hi_water = 0;
641 local_hi_water = 0;
642
34d340d7 643 encrypted_swap = should_encrypt_swap();
c3a08f59 644
34d340d7 645 while ((ch = getopt(argc, argv, "EF:L:H:S:P:QO:")) != EOF) {
1815bff5
A
646 switch((char)ch) {
647
2fc1e207
A
648 case 'E':
649 encrypted_swap = TRUE;
650 break;
651
1815bff5
A
652 case 'F':
653 strncpy(fileroot, optarg, 500);
654 break;
655
656 case 'L':
c3a08f59
A
657 variable_sized = 0;
658 limits[0].low_water = atoi(optarg);
1815bff5
A
659 break;
660 case 'H':
c3a08f59 661 variable_sized = 0;
1815bff5
A
662 hi_water = atoi(optarg);
663 break;
664 case 'S':
c3a08f59
A
665 variable_sized = 0;
666 limits[0].size = atoi(optarg);
1815bff5
A
667 break;
668 case 'P':
669 priority = atoi(optarg);
670 break;
671
34d340d7
A
672 case 'Q':
673 /* just query for "encrypted swap" default value */
674 fprintf(stdout,
675 "dynamic_pager: encrypted swap will be %s\n",
676 encrypted_swap ? "ON": "OFF");
677 exit(0);
678
1815bff5
A
679 default:
680 (void)fprintf(stderr,
681 "usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n");
83f6dbe8 682 exit(EXIT_FAILURE);
1815bff5
A
683 }
684 }
c3a08f59 685
8459d725
A
686 /*
687 * get rid of the filename at the end of the swap file specification
688 * we only want the portion of the pathname that should already exist
689 */
690 strcpy(tmp, fileroot);
691 if ((q = strrchr(tmp, '/')))
692 *q = 0;
693
694 /*
695 * Remove all files in the swap directory.
696 */
697 clean_swap_directory(tmp);
698
699#if TARGET_OS_EMBEDDED
700 paging_mode = get_paging_mode();
701 paging_mode_length = sizeof(paging_mode);
702
703 switch (paging_mode) {
704 case VM_PAGING_MODE_DISABLED:
705 /* Paging disabled; nothing to do here so exit */
706 exit(EXIT_SUCCESS);
707
708 case VM_PAGING_MODE_FREEZE:
709 /* Freeze mode; one swap file of fixed size, so enable and override defaults if set */
710 err = sysctlbyname(VM_FREEZE_SYSCTL, NULL, 0, &paging_mode, paging_mode_length);
711 if (err < 0) {
712 (void)fprintf(stderr, "dynamic_pager: cannot set %s\n", VM_FREEZE_SYSCTL);
713 exit(EXIT_FAILURE);
714 }
715 variable_sized = 0;
716 limits[0].size = FREEZE_FIXED_SWAP_SIZE;
717 break;
718
719 case VM_PAGING_MODE_DYNAMIC:
720 /* Dynamic paging selected; proceed normally */
721 break;
722
723 default:
724 /* Invalid option */
725 (void)fprintf(stderr, "dynamic_pager: invalid paging_mode %d\n", paging_mode);
726 exit(EXIT_FAILURE);
727 }
728#endif
729
730 if (statfs(tmp, &sfs) == -1) {
731 /*
732 * Setup the swap directory.
733 */
734 if (mkdir(tmp, 0755) == -1) {
735 (void)fprintf(stderr, "dynamic_pager: cannot create swap directory %s\n", tmp);
736 exit(EXIT_FAILURE);
737 }
738 }
739 chown(tmp, 0, 0);
740
c3a08f59 741 if (variable_sized) {
c3a08f59
A
742 int i;
743 int mib[4];
744 size_t len;
745 unsigned int size;
746 u_int64_t memsize;
34d340d7 747 u_int64_t fs_limit = 0;
c3a08f59
A
748
749 /*
750 * if we get here, then none of the following options were specified... -L, H, or -S
751 * drop into a new mode that scales the size of the swap file based on how much free
752 * space is left on the volume being used for swap and the amount of physical ram
753 * installed on the system...
754 * basically, we'll pick a maximum size that doesn't exceed the following limits...
83f6dbe8 755 * 1/8 the remaining free space of the swap volume
c3a08f59
A
756 * the size of phsyical ram
757 * MAXIMUM_SIZE - currently set to 1 Gbyte...
758 * once we have the maximum, we'll create a list of sizes and low_water limits
759 * we'll start with 2 files of MINIMUM_SIZE - currently 64 Mbytes...
760 * subsequent entries will double in size up to the calculated maximum... the low_water
761 * limit will be the sum of the current file size and the previous file size for each entry...
762 * as we add or delete files, we'll use the current file_count as an index into this
763 * table... if it's beyond the table size, we'll use the last entry
764 * the table entry will determine the size of the file to be created and the new low_water mark...
765 * the high_water mark is set to HI_WATER_DEFAULT which must be smaller than MINIMUM_SIZE...
766 * currently it is set to 40,000,000 to match the size being requested by the application
767 * monitoring low space conditions... having it set to the same size keeps us from creating
768 * an additional swap file when it really isn't necessary
769 */
770
8459d725 771 if (statfs(tmp, &sfs) == -1) {
34d340d7 772 /*
8459d725
A
773 * We really can't get filesystem status,
774 * so let's not limit the swap files...
34d340d7 775 */
8459d725
A
776 fs_limit = (u_int64_t) -1;
777 }
34d340d7 778
34d340d7
A
779 if (fs_limit != (u_int64_t) -1) {
780 /*
83f6dbe8 781 * Limit the maximum size of a swap file to 1/8 the free
c3a08f59 782 * space available on the filesystem where the swap files
83f6dbe8
A
783 * are to reside. This will allow us to allocate and
784 * deallocate in finer increments on systems without much
785 * free space.
c3a08f59 786 */
83f6dbe8 787 fs_limit = ((u_int64_t)sfs.f_bfree * (u_int64_t)sfs.f_bsize) / 8;
c3a08f59 788 }
34d340d7 789
c3a08f59
A
790 mib[0] = CTL_HW;
791 mib[1] = HW_MEMSIZE;
792 len = sizeof(u_int64_t);
793
794 if (sysctl(mib, 2, &memsize, &len, NULL, 0) < 0) {
795 /*
796 * if the sysctl fails for some reason
797 * use the starting size as the default
798 */
799 memsize = MINIMUM_SIZE;
800 }
801 if (memsize > fs_limit)
802 /*
803 * clip based on filesystem space available
804 */
805 memsize = fs_limit;
806
807 /*
808 * further limit the maximum size of a swap file
809 */
ef8ad44b
A
810 if (memsize <= MINIMUM_SIZE) {
811 (void)fprintf(stderr, "dynamic_pager: Need more space on the disk to enable swapping.\n");
812 sleep(30);
813 goto retry;
814 } else if (memsize <= (MINIMUM_SIZE*2)) {
815 (void)fprintf(stderr, "dynamic_pager: Activating emergency swap file immediately.\n");
816 flags |= USE_EMERGENCY_SWAP_FILE_FIRST;
817 } else if (memsize > MAXIMUM_SIZE) {
c3a08f59 818 memsize = MAXIMUM_SIZE;
ef8ad44b 819 }
c3a08f59
A
820
821 size = MINIMUM_SIZE;
822
823 /*
824 * start small and work our way up to the maximum
825 * sized allowed... this way, we don't tie up too
826 * much disk space if we never do any real paging
827 */
828 for (max_valid = 0, i = 0; i < MAX_LIMITS; i++) {
829 limits[i].size = size;
830
831 if (i == 0)
832 limits[i].low_water = size * 2;
833 else {
834 if ((limits[i - 1].size / 2) > HI_WATER_DEFAULT)
835 limits[i].low_water = size + (limits[i - 1].size / 2);
836 else
837 limits[i].low_water = size + limits[i - 1].size;
838 }
c3a08f59
A
839
840 if (i) {
841 /*
842 * make the first 2 files the same size
843 */
844 size = size * 2;
83f6dbe8
A
845 if (size > memsize)
846 break;
c3a08f59
A
847 }
848 max_valid++;
849 }
850 if (max_valid >= MAX_LIMITS)
851 max_valid = MAX_LIMITS - 1;
852
853 hi_water = HI_WATER_DEFAULT;
854 }
1815bff5 855 local_hi_water = hi_water;
c3a08f59
A
856
857 if((limits[0].low_water != 0) && (limits[0].low_water <= (limits[0].size + hi_water))) {
83f6dbe8
A
858 (void)fprintf(stderr, "dynamic_pager: low water trigger must be larger than size + hi_water\n");
859 exit(EXIT_FAILURE);
1815bff5
A
860 }
861 argc -= optind;
862 argv += optind;
c3a08f59 863
ef8ad44b 864 paging_setup(flags, limits[0].size, priority, limits[0].low_water, hi_water,
2fc1e207 865 encrypted_swap);
c3a08f59 866
1815bff5
A
867 return (0);
868}