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