]> git.saurik.com Git - apple/system_cmds.git/blobdiff - dynamic_pager.tproj/dynamic_pager.c
system_cmds-550.6.tar.gz
[apple/system_cmds.git] / dynamic_pager.tproj / dynamic_pager.c
index 0b20ab25124203185fef86405fdb6cb1cffcda71..1621a1dfa2e722a69982d49c9d6b7bac572d9a32 100644 (file)
@@ -10,8 +10,8 @@
 #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>
@@ -20,8 +20,8 @@
 #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;
@@ -95,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,
@@ -207,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;
@@ -240,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) {
@@ -267,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)) {
@@ -281,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) {
@@ -294,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);
@@ -325,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,
@@ -355,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--;
@@ -393,33 +408,42 @@ wait_on_paging_trigger(trigger_port)
 }
 
 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",
@@ -427,13 +451,22 @@ paging_setup(flags, size, priority, low, high)
                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)  {
@@ -456,6 +489,130 @@ paging_setup(flags, size, priority, low, high)
        }
        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)
 {
@@ -463,21 +620,41 @@ 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;
@@ -498,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");
@@ -505,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
@@ -538,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
@@ -555,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);
@@ -580,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;
 
@@ -626,7 +867,8 @@ 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);
 }