-/* File created by Chris Youngworth, Apple Computer 2/11/99 */
-
-
#define mig_external
-#include <mach/port.h>
-#include <mach/mach_error.h>
-#include <mach/mach_traps.h>
-#include <mach/mach.h>
-#ifndef MACH_BSD
-#define MACH_BSD
-#endif
-#include <mach/bootstrap.h>
-#include <mach/mach_syscalls.h>
-#include <mach/mig_errors.h>
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/mman.h>
+#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
-#include <sys/gmon.h>
-#include <errno.h>
-#include <kvm.h>
-#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <nlist.h>
-#include <ctype.h>
#include <unistd.h>
-#include <paths.h>
-
-#include <default_pager/default_pager_types.h>
-#include <default_pager_alerts_server.h>
-#include <backing_store_alerts.h>
-#include <backing_store_triggers_server.h>
-
-int debug = 0;
-int file_count = 0;
-int low_water = 0;
-int hi_water = 0;
-int local_hi_water = 0;
-int size = 20000000;
-int priority = 0;
-int options = 0;
-char fileroot[512];
-
-
-/* global parameters for application notification option */
-mach_port_t trigger_port = MACH_PORT_NULL;
-mach_port_t notify_port = MACH_PORT_NULL;
-int notify_high = 0;
-int bs_recovery;
+#include <dirent.h>
/*
-void setprof __P((struct kvmvars *kvp, int state));
-void dumpstate __P((struct kvmvars *kvp));
-void reset __P((struct kvmvars *kvp));
-*/
-
-
-
-mach_msg_return_t
-server_alert_loop(
- mach_msg_size_t max_size,
- mach_port_t rcv_name,
- mach_msg_options_t options)
-{
- mig_reply_error_t *bufRequest = 0, *bufReply = 0;
- register mach_msg_return_t mr;
- register kern_return_t kr;
-
- if ((kr = vm_allocate(mach_task_self(),
- (vm_address_t *)&bufRequest,
- 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_overwrite_trap(&bufRequest->Head, MACH_RCV_MSG|options,
- 0, max_size, rcv_name,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
- (mach_msg_header_t *) 0, 0);
- if (mr == MACH_MSG_SUCCESS) {
- /* we have a request message */
-
- if(!(default_pager_alerts_server(
- &bufRequest->Head, &bufReply->Head)))
- backing_store_triggers_server(
- &bufRequest->Head, &bufReply->Head);
-
- if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
- bufReply->RetCode != KERN_SUCCESS) {
- if (bufReply->RetCode == MIG_NO_REPLY)
- /*
- * This return code is a little tricky--
- * it appears that the demux routine found an
- * error of some sort, but since that error
- * would not normally get returned either to
- * the local user or the remote one, we pretend it's
- * ok.
- */
-
- bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
- mach_msg_destroy(&bufRequest->Head);
- continue;
- }
-
- if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
- /* no reply port, so destroy the reply */
- if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
- mach_msg_destroy(&bufReply->Head);
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- (void)vm_deallocate(mach_task_self(),
- (vm_address_t) bufRequest,
- max_size + MAX_TRAILER_SIZE);
- (void)vm_deallocate(mach_task_self(),
- (vm_address_t) bufReply,
- max_size + MAX_TRAILER_SIZE);
- return KERN_FAILURE;
-
-}
-
-
-kern_return_t
-backing_store_triggers(dynamic_pager, hi_wat, flags, port)
- mach_port_t dynamic_pager;
- int hi_wat;
- int flags;
- mach_port_t port;
+ * We don't exit with a non-zero status anywhere here for 2 reasons:
+ * - the kernel can continue to create swapfiles in "/private/var/vm/swapfile<index>"
+ * - we want this job to run only once at boot and exit regardless of whether:
+ * -- it could clean up the swap directory
+ * -- it could set the prefix for the swapfile name.
+ */
+
+static void
+clean_swap_directory(const char *path)
{
- if((hi_wat + size) > low_water)
- return KERN_FAILURE; /* let ipc system clean up port */
-
- /* If there was a previous registration, throw it away */
- if (notify_port != MACH_PORT_NULL) {
- mach_port_deallocate(mach_task_self(), notify_port);
- notify_port = MACH_PORT_NULL;
+ 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(0);
}
- notify_port = port;
- notify_high = hi_wat;
- if(hi_water < notify_high) {
- local_hi_water = notify_high;
- } else {
- local_hi_water = hi_water;
- }
- if(notify_high > hi_water) {
- default_pager_space_alert(trigger_port, HI_WAT_ALERT);
- }
- return KERN_SUCCESS;
-}
-
-
-kern_return_t
-default_pager_space_alert(alert_port, flags)
- mach_port_t alert_port;
- int flags;
-{
- char subfile[512];
- FILE *file_ptr;
- off_t filesize = size;
- int error;
- kern_return_t ret;
-
- if(flags & HI_WAT_ALERT) {
-/* printf("HI WAT ALERT!!\n"); */
- file_count++;
- sprintf(subfile, "%s%d", fileroot, file_count);
- file_ptr = fopen(subfile, "w+");
- fchmod(fileno(file_ptr), (mode_t)01600);
- error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
- if(error) {
- error = ftruncate(fileno(file_ptr), (off_t)size);
- }
- fclose(file_ptr);
- if(error == -1) {
- unlink(subfile);
- file_count--;
- local_hi_water = local_hi_water>>2;
- if(notify_high >= (local_hi_water)) {
- if(notify_port != MACH_PORT_NULL) {
- /* notify monitoring app of */
- /* backing store shortage */
- backing_store_alert(notify_port,
- HI_WAT_ALERT);
- mach_port_deallocate(mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- }
- }
- macx_triggers(local_hi_water,
- low_water, HI_WAT_ALERT, alert_port);
- } else {
- if(hi_water < notify_high) {
- if(local_hi_water < notify_high) {
- bs_recovery = notify_high - local_hi_water;
- }
- local_hi_water = notify_high;
- } else {
- if(local_hi_water < hi_water) {
- bs_recovery = hi_water - local_hi_water;
- }
- local_hi_water = hi_water;
- }
- ret = macx_swapon(subfile, flags, size, priority);
- if(ret) {
- unlink(subfile);
- file_count--;
- local_hi_water = local_hi_water>>2;
- if(notify_high >= (local_hi_water)) {
- if(notify_port != MACH_PORT_NULL) {
- /* notify monitoring app of */
- /* backing store shortage */
- backing_store_alert(
- notify_port,
- HI_WAT_ALERT);
- mach_port_deallocate(
- mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- }
- }
- macx_triggers(local_hi_water,
- low_water, HI_WAT_ALERT, alert_port);
- } else if(bs_recovery <= size) {
- if((bs_recovery != 0) && (notify_port)) {
- backing_store_alert(notify_port,
- LO_WAT_ALERT);
- mach_port_deallocate(mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- bs_recovery = 0;
- }
- } else
- bs_recovery = bs_recovery-size;
+ 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);
}
-
- macx_triggers(local_hi_water,
- low_water, HI_WAT_ALERT, alert_port);
}
- if(flags & LO_WAT_ALERT) {
-/* Turn into a logged message printf("LO WAT ALERT!!\n"); */
- sprintf(subfile, "%s%d", fileroot, file_count);
- if(hi_water < notify_high) {
- local_hi_water = notify_high;
- } else {
- local_hi_water = hi_water;
- }
- if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) {
- backing_store_alert(notify_port, LO_WAT_ALERT);
- mach_port_deallocate(mach_task_self(), notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- bs_recovery = 0;
- }
- if(macx_swapoff(subfile, flags) == 0) {
- unlink(subfile);
- file_count--;
- }
- macx_triggers(local_hi_water, low_water, LO_WAT_ALERT, alert_port);
- }
- return KERN_SUCCESS;
-}
-void
-wait_on_paging_trigger(trigger_port)
- mach_port_t trigger_port;
-{
- kern_return_t result;
- result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
- if (result != KERN_SUCCESS) {
- fprintf(stderr, "dynamic_pager: default pager alert failed\n");
- exit(1);
- }
- exit(0);
+ closedir(dir);
}
-void
-paging_setup(flags, size, priority, low, high)
- int flags;
- int size;
- int priority;
- int low;
- int high;
-{
- off_t filesize = size;
- char subfile[512];
- FILE *file_ptr;
- int error;
-
- file_count = 0;
- sprintf(subfile, "%s%d", fileroot, file_count);
- file_ptr = fopen(subfile, "w+");
- fchmod(fileno(file_ptr), (mode_t)01600);
- error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
- if(error) {
- error = ftruncate(fileno(file_ptr), (off_t)size);
- }
- fclose(file_ptr);
-
- macx_swapon(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) {
- fprintf(stderr,"allocation of trigger port failed\n");
- exit(1);
- }
- /* create a send right on our local port */
- mach_port_extract_right(mach_task_self(), trigger_port,
- MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
- macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
- if(low) {
- macx_triggers(high,
- low, LO_WAT_ALERT, trigger_port);
- }
- /* register control port for applications wishing to */
- /* get backing store notifications or change dynamic */
- /* pager settings. */
- set_dp_control_port(mach_host_self(), trigger_port);
- wait_on_paging_trigger(trigger_port);
- }
- exit(0);
-}
int
main(int argc, char **argv)
{
- extern char *optarg;
- extern int optind;
- char default_filename[] = "/private/var/vm/swapfile";
int ch;
+ static char tmp[1024];
+ struct statfs sfs;
+ char *q;
+ char fileroot[512];
seteuid(getuid());
- strcpy(fileroot, default_filename);
+ fileroot[0] = '\0';
- while ((ch = getopt(argc, argv, "F:L:H:S:P:O:")) != EOF) {
+ while ((ch = getopt(argc, argv, "F:")) != EOF) {
switch((char)ch) {
case 'F':
strncpy(fileroot, optarg, 500);
break;
- case 'L':
- low_water = atoi(optarg);
- break;
- case 'H':
- hi_water = atoi(optarg);
- break;
- case 'S':
- size = atoi(optarg);
- break;
- case 'P':
- priority = atoi(optarg);
- break;
-
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");
- exit(1);
+ "usage: dynamic_pager [-F filename]\n");
+ exit(0);
}
}
- local_hi_water = hi_water;
- if((low_water != 0) && (low_water <= (size + hi_water))) {
- (void)fprintf(stderr, "usage: low water trigger must be larger than size + hi_water\n");
- exit(1);
+
+ /*
+ * set vm.swapfileprefix if a fileroot was passed from the command
+ * line, otherwise get the value from the kernel
+ */
+ if (fileroot[0] != '\0') {
+ if (sysctlbyname("vm.swapfileprefix", NULL, 0, fileroot, sizeof(fileroot)) == -1) {
+ perror("Failed to set swapfile name prefix");
+ }
+ } else {
+ size_t fileroot_len = sizeof(fileroot);
+ if (sysctlbyname("vm.swapfileprefix", fileroot, &fileroot_len, NULL, 0) == -1) {
+ perror("Failed to get swapfile name prefix");
+ /*
+ * can't continue without a fileroot
+ */
+ return (0);
+ }
}
- argc -= optind;
- argv += optind;
- paging_setup(0, size, priority, low_water, hi_water);
+
+ /*
+ * 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 (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);
+ }
+ }
+
+ chown(tmp, 0, 0);
+
return (0);
}