X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/2fc1e207eccd68aee093ed29dae719e77bac17dd..aaff5f0175051936f3b5ec9815c2df5d726dc5b6:/dynamic_pager.tproj/dynamic_pager.c diff --git a/dynamic_pager.tproj/dynamic_pager.c b/dynamic_pager.tproj/dynamic_pager.c index 08a7d1a..1621a1d 100644 --- a/dynamic_pager.tproj/dynamic_pager.c +++ b/dynamic_pager.tproj/dynamic_pager.c @@ -11,6 +11,7 @@ #define MACH_BSD #endif #include +#include #include #include #include @@ -19,8 +20,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -29,12 +30,14 @@ #include #include #include +#include + +#include #include -#include +#include #include -#include - +#include /* * HI_WATER_DEFAULT set to this funny value to @@ -48,6 +51,22 @@ #define MAX_LIMITS 8 +#if TARGET_OS_EMBEDDED + +#include + +#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS 1 +#include + +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; @@ -94,22 +113,12 @@ server_alert_loop( 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, @@ -206,9 +215,8 @@ default_pager_space_alert(alert_port, flags) 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; @@ -239,19 +247,25 @@ default_pager_space_alert(alert_port, flags) 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) { @@ -266,6 +280,8 @@ default_pager_space_alert(alert_port, flags) 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)) { @@ -280,7 +296,6 @@ default_pager_space_alert(alert_port, flags) 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) { @@ -293,7 +308,8 @@ default_pager_space_alert(alert_port, flags) } 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); @@ -324,7 +340,6 @@ default_pager_space_alert(alert_port, flags) 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, @@ -354,7 +369,8 @@ default_pager_space_alert(alert_port, flags) 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--; @@ -402,24 +418,32 @@ paging_setup(flags, size, priority, low, high, 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", @@ -438,13 +462,11 @@ paging_setup(flags, size, priority, low, high, encrypted) (encrypted ? "on" : "off")); } - macx_swapon(subfile, flags, size, priority); + 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) { @@ -467,6 +489,130 @@ paging_setup(flags, size, priority, low, high, encrypted) } 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) { @@ -474,20 +620,35 @@ main(int argc, char **argv) extern int optind; char default_filename[] = "/private/var/vm/swapfile"; int ch; - int variable_sized = 1; - boolean_t encrypted_swap = FALSE; + 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, "EF:L:H:S:P:O:")) != EOF) { + while ((ch = getopt(argc, argv, "EF:L:H:S:P:QO:")) != EOF) { switch((char)ch) { case 'E': @@ -514,6 +675,13 @@ main(int argc, char **argv) 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"); @@ -521,16 +689,68 @@ main(int argc, char **argv) } } + /* + * 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 @@ -554,16 +774,16 @@ main(int argc, char **argv) * 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 @@ -571,11 +791,8 @@ main(int argc, char **argv) * 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); @@ -596,8 +813,16 @@ main(int argc, char **argv) /* * 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; @@ -642,7 +867,7 @@ main(int argc, char **argv) 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);