#ifndef MACH_BSD
#define MACH_BSD
#endif
-#include <mach/bootstrap.h>
#include <mach/mach_syscalls.h>
+#include <mach/mach_traps.h>
#include <mach/mig_errors.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/gmon.h>
+#include <sys/types.h>
#include <errno.h>
-#include <kvm.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <paths.h>
+#include <dirent.h>
+
+#include <CoreFoundation/CoreFoundation.h>
#include <default_pager/default_pager_types.h>
-#include <default_pager_alerts_server.h>
+#include <default_pager_alertsServer.h>
#include <backing_store_alerts.h>
-#include <backing_store_triggers_server.h>
-
+#include <backing_store_triggersServer.h>
/*
* HI_WATER_DEFAULT set to this funny value to
#define MAX_LIMITS 8
+#if TARGET_OS_EMBEDDED
+
+#include <System/sys/content_protection.h>
+
+#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS 1
+#include <SystemConfiguration/SystemConfiguration.h>
+
+enum {
+ VM_PAGING_MODE_DISABLED = 0,
+ VM_PAGING_MODE_FREEZE,
+ VM_PAGING_MODE_DYNAMIC
+};
+
+#define VM_FREEZE_SYSCTL "vm.freeze_enabled"
+#define FREEZE_FIXED_SWAP_SIZE (128 * 1024 * 1024)
+#endif
struct limit {
unsigned int size;
max_size + MAX_TRAILER_SIZE,
TRUE)) != KERN_SUCCESS)
return kr;
- if ((kr = vm_protect(mach_task_self(),
- (vm_address_t)bufRequest,
- max_size + MAX_TRAILER_SIZE,
- FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
- return kr;
mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
if ((kr = vm_allocate(mach_task_self(),
(vm_address_t *)&bufReply,
max_size + MAX_TRAILER_SIZE,
TRUE)) != KERN_SUCCESS)
return kr;
- if ((kr = vm_protect(mach_task_self(),
- (vm_address_t)bufReply,
- max_size + MAX_TRAILER_SIZE,
- FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
- return kr;
mlock(bufReply, max_size + MAX_TRAILER_SIZE);
while(TRUE) {
mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
int flags;
{
char subfile[512];
- FILE *file_ptr;
off_t filesize;
- int error;
+ int error=0, fd=0;
kern_return_t ret;
int cur_limits;
unsigned int cur_size;
notifications = HI_WAT_ALERT;
sprintf(subfile, "%s%d", fileroot, file_count);
- file_ptr = fopen(subfile, "w+");
- if (file_ptr == NULL) {
+ fd = open(subfile, O_CREAT|O_EXCL|O_RDWR,(mode_t)(S_IRUSR|S_IWUSR));
+ if (fd == -1) {
/* force error recovery below */
error = -1;
- } else {
- fchmod(fileno(file_ptr), (mode_t)01600);
- error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
+ }
+#if TARGET_OS_EMBEDDED
+ else {
+ error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
+ }
+#endif
+
+ if(!error) {
+ error = fcntl(fd, F_SETSIZE, &filesize);
if(error) {
- error = ftruncate(fileno(file_ptr), filesize);
+ error = ftruncate(fd, filesize);
}
if(error)
unlink(subfile);
- fclose(file_ptr);
+ close(fd);
}
if(error == -1) {
notifications = HI_WAT_ALERT | LO_WAT_ALERT;
else
notifications = HI_WAT_ALERT;
+
+ notifications |= SWAP_FILE_CREATION_ERROR;
local_hi_water = local_hi_water>>2;
if(notify_high >= (local_hi_water)) {
notify_high = 0;
}
}
- macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port);
} else {
if(hi_water < notify_high) {
if(local_hi_water < notify_high) {
}
local_hi_water = hi_water;
}
- ret = macx_swapon(subfile, flags, cur_size, priority);
+ ret = macx_swapon((uint64_t)(uintptr_t)subfile,
+ flags, cur_size, priority);
if(ret) {
unlink(subfile);
notify_high = 0;
}
}
- macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port);
} else if(bs_recovery <= cur_size) {
if((bs_recovery != 0) && (notify_port)) {
backing_store_alert(notify_port,
notify_high = 0;
bs_recovery = 0;
}
- if((error = macx_swapoff(subfile, flags)) == 0) {
+ if((error = macx_swapoff((uint64_t)(uintptr_t)subfile,
+ flags)) == 0) {
unlink(subfile);
file_count--;
}
void
-paging_setup(flags, size, priority, low, high)
+paging_setup(flags, size, priority, low, high, encrypted)
int flags;
int size;
int priority;
int low;
int high;
+ boolean_t encrypted;
{
off_t filesize = size;
char subfile[512];
- FILE *file_ptr;
- int error;
+ int error, fd = 0;
file_count = 0;
sprintf(subfile, "%s%d", fileroot, file_count);
- file_ptr = fopen(subfile, "w+");
- if (file_ptr == NULL) {
+ fd = open(subfile, O_CREAT|O_EXCL|O_RDWR, ((mode_t)(S_IRUSR|S_IWUSR)));
+ if (fd == -1) {
fprintf(stderr, "dynamic_pager: cannot create paging file %s!\n",
subfile);
exit(EXIT_FAILURE);
}
- fchmod(fileno(file_ptr), (mode_t)01600);
- error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
+#if TARGET_OS_EMBEDDED
+ error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
+ if (error == -1) {
+ fprintf(stderr, "dynamic_pager: cannot set file protection class!\n");
+ unlink(subfile);
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ error = fcntl(fd, F_SETSIZE, &filesize);
if(error) {
- error = ftruncate(fileno(file_ptr), filesize);
+ error = ftruncate(fd, filesize);
}
- fclose(file_ptr);
+ close(fd);
if (error == -1) {
fprintf(stderr, "dynamic_pager: cannot extend paging file size %s to %llu!\n",
exit(EXIT_FAILURE);
}
- macx_swapon(subfile, flags, size, priority);
+ if (macx_triggers(0, 0,
+ (encrypted
+ ? SWAP_ENCRYPT_ON
+ : SWAP_ENCRYPT_OFF),
+ MACH_PORT_NULL) != 0) {
+ fprintf(stderr,
+ "dynamic_pager: warning: "
+ "could not turn encrypted swap %s\n",
+ (encrypted ? "on" : "off"));
+ }
+
+ macx_swapon((uint64_t)(uintptr_t)subfile, flags, size, priority);
if(hi_water) {
mach_msg_type_name_t poly;
- daemon(0,0);
-
if (mach_port_allocate(mach_task_self(),
MACH_PORT_RIGHT_RECEIVE,
&trigger_port) != KERN_SUCCESS) {
}
exit(EXIT_SUCCESS);
}
+
+static void
+clean_swap_directory(const char *path)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char buf[1024];
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ fprintf(stderr,"dynamic_pager: cannot open swap directory %s\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_namlen>= 4 && strncmp(entry->d_name, "swap", 4) == 0) {
+ snprintf(buf, sizeof buf, "%s/%s", path, entry->d_name);
+ unlink(buf);
+ }
+ }
+
+ closedir(dir);
+}
+
+#define VM_PREFS_PLIST "/Library/Preferences/com.apple.virtualMemory.plist"
+#define VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY "DisableEncryptedSwap"
+
+static boolean_t
+should_encrypt_swap(void)
+{
+ CFPropertyListRef propertyList;
+ CFTypeID propertyListType;
+ CFStringRef errorString;
+ CFDataRef resourceData;
+ SInt32 errorCode;
+ CFURLRef fileURL;
+ CFTypeRef disable_encrypted_swap;
+ boolean_t should_encrypt = TRUE;
+ boolean_t explicit_value = FALSE;
+
+ fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)VM_PREFS_PLIST, strlen(VM_PREFS_PLIST), false);
+ if (fileURL == NULL) {
+ /*fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), VM_PREFS_PLIST);*/
+ goto done;
+ }
+
+ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
+ /*fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), VM_PREFS_PLIST, (int)errorCode);*/
+ CFRelease(fileURL);
+ goto done;
+ }
+
+ CFRelease(fileURL);
+ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
+ if (propertyList == NULL) {
+ /*fprintf(stderr, "%s: cannot get XML propertyList %s\n", getprogname(), VM_PREFS_PLIST);*/
+ CFRelease(resourceData);
+ goto done;
+ }
+
+ propertyListType = CFGetTypeID(propertyList);
+
+ if (propertyListType == CFDictionaryGetTypeID()) {
+ disable_encrypted_swap = (CFTypeRef) CFDictionaryGetValue((CFDictionaryRef) propertyList, CFSTR(VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY));
+ if (disable_encrypted_swap == NULL) {
+ /* no value: use the default value i.e. encrypted swap ON */
+ } else if (CFGetTypeID(disable_encrypted_swap) != CFBooleanGetTypeID()) {
+ fprintf(stderr, "%s: wrong type for key \"%s\"\n",
+ getprogname(), VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY);
+ /* bogus value, assume it's "true" for safety's sake */
+ should_encrypt = TRUE;
+ explicit_value = TRUE;
+ } else {
+ should_encrypt = CFBooleanGetValue((CFBooleanRef)disable_encrypted_swap) ? FALSE : TRUE;
+ explicit_value = TRUE;
+ }
+ }
+ else {
+ /*fprintf(stderr, "%s: invalid propertyList type %d (not a dictionary)\n", getprogname(), propertyListType);*/
+ }
+ CFRelease(resourceData);
+ CFRelease(propertyList);
+
+done:
+ if (! explicit_value) {
+#if TARGET_OS_EMBEDDED
+ should_encrypt = FALSE;
+#endif
+ }
+
+ return should_encrypt;
+}
+
+#if TARGET_OS_EMBEDDED
+
+#define VM_PREFS_PAGING_MODE_PLIST "com.apple.virtualMemoryMode.plist"
+#define VM_PREFS_PAGING_MODE_KEY "Mode"
+
+static uint32_t
+get_paging_mode(void)
+{
+ SCPreferencesRef paging_prefs;
+ uint32_t paging_mode;
+
+ paging_mode = VM_PAGING_MODE_FREEZE; /* default */
+
+ paging_prefs = SCPreferencesCreate(NULL, CFSTR("dynamic_pager"), CFSTR(VM_PREFS_PAGING_MODE_PLIST));
+ if (paging_prefs) {
+ CFNumberRef value;
+
+ value = SCPreferencesGetValue(paging_prefs, CFSTR(VM_PREFS_PAGING_MODE_KEY));
+
+ if (value && (CFGetTypeID( value ) == CFNumberGetTypeID() ) ) {
+ CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &paging_mode);
+ }
+
+ CFRelease(paging_prefs);
+ }
+
+ return paging_mode;
+}
+
+#endif
+
int
main(int argc, char **argv)
{
extern int optind;
char default_filename[] = "/private/var/vm/swapfile";
int ch;
- int variable_sized = 1;
+ int variable_sized = 1,flags=0;
+ boolean_t encrypted_swap;
+ static char tmp[1024];
+ struct statfs sfs;
+ char *q;
+#if TARGET_OS_EMBEDDED
+ int err;
+ uint32_t paging_mode;
+ size_t paging_mode_length;
+#endif
+
+/*
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+*/
seteuid(getuid());
strcpy(fileroot, default_filename);
+retry:
limits[0].size = 20000000;
limits[0].low_water = 0;
hi_water = 0;
local_hi_water = 0;
+ encrypted_swap = should_encrypt_swap();
- while ((ch = getopt(argc, argv, "F:L:H:S:P:O:")) != EOF) {
+ while ((ch = getopt(argc, argv, "EF:L:H:S:P:QO:")) != EOF) {
switch((char)ch) {
+ case 'E':
+ encrypted_swap = TRUE;
+ break;
+
case 'F':
strncpy(fileroot, optarg, 500);
break;
priority = atoi(optarg);
break;
+ case 'Q':
+ /* just query for "encrypted swap" default value */
+ fprintf(stdout,
+ "dynamic_pager: encrypted swap will be %s\n",
+ encrypted_swap ? "ON": "OFF");
+ exit(0);
+
default:
(void)fprintf(stderr,
"usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n");
}
}
+ /*
+ * get rid of the filename at the end of the swap file specification
+ * we only want the portion of the pathname that should already exist
+ */
+ strcpy(tmp, fileroot);
+ if ((q = strrchr(tmp, '/')))
+ *q = 0;
+
+ /*
+ * Remove all files in the swap directory.
+ */
+ clean_swap_directory(tmp);
+
+#if TARGET_OS_EMBEDDED
+ paging_mode = get_paging_mode();
+ paging_mode_length = sizeof(paging_mode);
+
+ switch (paging_mode) {
+ case VM_PAGING_MODE_DISABLED:
+ /* Paging disabled; nothing to do here so exit */
+ exit(EXIT_SUCCESS);
+
+ case VM_PAGING_MODE_FREEZE:
+ /* Freeze mode; one swap file of fixed size, so enable and override defaults if set */
+ err = sysctlbyname(VM_FREEZE_SYSCTL, NULL, 0, &paging_mode, paging_mode_length);
+ if (err < 0) {
+ (void)fprintf(stderr, "dynamic_pager: cannot set %s\n", VM_FREEZE_SYSCTL);
+ exit(EXIT_FAILURE);
+ }
+ variable_sized = 0;
+ limits[0].size = FREEZE_FIXED_SWAP_SIZE;
+ break;
+
+ case VM_PAGING_MODE_DYNAMIC:
+ /* Dynamic paging selected; proceed normally */
+ break;
+
+ default:
+ /* Invalid option */
+ (void)fprintf(stderr, "dynamic_pager: invalid paging_mode %d\n", paging_mode);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ if (statfs(tmp, &sfs) == -1) {
+ /*
+ * Setup the swap directory.
+ */
+ if (mkdir(tmp, 0755) == -1) {
+ (void)fprintf(stderr, "dynamic_pager: cannot create swap directory %s\n", tmp);
+ exit(EXIT_FAILURE);
+ }
+ }
+ chown(tmp, 0, 0);
+
if (variable_sized) {
- static char tmp[1024];
- struct statfs sfs;
- char *q;
int i;
int mib[4];
size_t len;
unsigned int size;
u_int64_t memsize;
- u_int64_t fs_limit;
+ u_int64_t fs_limit = 0;
/*
* if we get here, then none of the following options were specified... -L, H, or -S
* an additional swap file when it really isn't necessary
*/
- /*
- * get rid of the filename at the end of the swap file specification
- * we only want the portion of the pathname that should already exist
- */
- strcpy(tmp, fileroot);
- if (q = strrchr(tmp, '/'))
- *q = 0;
-
- if (statfs(tmp, &sfs) != -1) {
- /*
+ if (statfs(tmp, &sfs) == -1) {
+ /*
+ * We really can't get filesystem status,
+ * so let's not limit the swap files...
+ */
+ fs_limit = (u_int64_t) -1;
+ }
+
+ if (fs_limit != (u_int64_t) -1) {
+ /*
* Limit the maximum size of a swap file to 1/8 the free
* space available on the filesystem where the swap files
* are to reside. This will allow us to allocate and
* free space.
*/
fs_limit = ((u_int64_t)sfs.f_bfree * (u_int64_t)sfs.f_bsize) / 8;
-
- } else {
- (void)fprintf(stderr, "dynamic_pager: swap directory must exist\n");
- exit(EXIT_FAILURE);
}
+
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
len = sizeof(u_int64_t);
/*
* further limit the maximum size of a swap file
*/
- if (memsize > MAXIMUM_SIZE)
+ if (memsize <= MINIMUM_SIZE) {
+ (void)fprintf(stderr, "dynamic_pager: Need more space on the disk to enable swapping.\n");
+ sleep(30);
+ goto retry;
+ } else if (memsize <= (MINIMUM_SIZE*2)) {
+ (void)fprintf(stderr, "dynamic_pager: Activating emergency swap file immediately.\n");
+ flags |= USE_EMERGENCY_SWAP_FILE_FIRST;
+ } else if (memsize > MAXIMUM_SIZE) {
memsize = MAXIMUM_SIZE;
+ }
size = MINIMUM_SIZE;
argc -= optind;
argv += optind;
- paging_setup(0, limits[0].size, priority, limits[0].low_water, hi_water);
+ paging_setup(flags, limits[0].size, priority, limits[0].low_water, hi_water,
+ encrypted_swap);
return (0);
}