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