]>
Commit | Line | Data |
---|---|---|
1815bff5 A |
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/bootstrap.h> | |
14 | #include <mach/mach_syscalls.h> | |
15 | #include <mach/mig_errors.h> | |
16 | #include <sys/param.h> | |
c3a08f59 | 17 | #include <sys/mount.h> |
1815bff5 A |
18 | #include <sys/file.h> |
19 | #include <sys/mman.h> | |
20 | #include <sys/stat.h> | |
21 | #include <sys/sysctl.h> | |
22 | #include <sys/gmon.h> | |
23 | #include <errno.h> | |
24 | #include <kvm.h> | |
25 | #include <limits.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <nlist.h> | |
30 | #include <ctype.h> | |
31 | #include <unistd.h> | |
32 | #include <paths.h> | |
33 | ||
34 | #include <default_pager/default_pager_types.h> | |
35 | #include <default_pager_alerts_server.h> | |
36 | #include <backing_store_alerts.h> | |
37 | #include <backing_store_triggers_server.h> | |
38 | ||
c3a08f59 A |
39 | |
40 | /* | |
41 | * HI_WATER_DEFAULT set to this funny value to | |
42 | * match the size that the low space application | |
43 | * is asking for... need to keep MINIMUM_SIZE | |
44 | * above this value. | |
45 | */ | |
46 | #define HI_WATER_DEFAULT 40000000 | |
47 | #define MINIMUM_SIZE (1024 * 1024 * 64) | |
48 | #define MAXIMUM_SIZE (1024 * 1024 * 1024) | |
49 | ||
50 | #define MAX_LIMITS 8 | |
51 | ||
52 | ||
53 | struct limit { | |
54 | unsigned int size; | |
55 | unsigned int low_water; | |
56 | } limits[MAX_LIMITS]; | |
57 | ||
58 | ||
1815bff5 | 59 | int debug = 0; |
c3a08f59 | 60 | int max_valid = 0; |
1815bff5 | 61 | int file_count = 0; |
c3a08f59 A |
62 | unsigned int hi_water; |
63 | unsigned int local_hi_water; | |
1815bff5 | 64 | int priority = 0; |
c3a08f59 | 65 | int options = 0; |
1815bff5 A |
66 | char fileroot[512]; |
67 | ||
68 | ||
69 | /* global parameters for application notification option */ | |
756446ec A |
70 | mach_port_t trigger_port = MACH_PORT_NULL; |
71 | mach_port_t notify_port = MACH_PORT_NULL; | |
c3a08f59 A |
72 | unsigned int notify_high = 0; |
73 | unsigned int bs_recovery; | |
1815bff5 A |
74 | |
75 | /* | |
76 | void setprof __P((struct kvmvars *kvp, int state)); | |
77 | void dumpstate __P((struct kvmvars *kvp)); | |
78 | void reset __P((struct kvmvars *kvp)); | |
79 | */ | |
80 | ||
81 | ||
82 | ||
83 | mach_msg_return_t | |
84 | server_alert_loop( | |
85 | mach_msg_size_t max_size, | |
86 | mach_port_t rcv_name, | |
87 | mach_msg_options_t options) | |
88 | { | |
89 | mig_reply_error_t *bufRequest = 0, *bufReply = 0; | |
90 | register mach_msg_return_t mr; | |
91 | register kern_return_t kr; | |
92 | ||
93 | if ((kr = vm_allocate(mach_task_self(), | |
94 | (vm_address_t *)&bufRequest, | |
95 | max_size + MAX_TRAILER_SIZE, | |
96 | TRUE)) != KERN_SUCCESS) | |
97 | return kr; | |
1c51fdde A |
98 | if ((kr = vm_protect(mach_task_self(), |
99 | (vm_address_t)bufRequest, | |
100 | max_size + MAX_TRAILER_SIZE, | |
101 | FALSE, VM_PROT_ALL)) != KERN_SUCCESS) | |
102 | return kr; | |
1815bff5 A |
103 | mlock(bufRequest, max_size + MAX_TRAILER_SIZE); |
104 | if ((kr = vm_allocate(mach_task_self(), | |
105 | (vm_address_t *)&bufReply, | |
106 | max_size + MAX_TRAILER_SIZE, | |
107 | TRUE)) != KERN_SUCCESS) | |
108 | return kr; | |
1c51fdde A |
109 | if ((kr = vm_protect(mach_task_self(), |
110 | (vm_address_t)bufReply, | |
111 | max_size + MAX_TRAILER_SIZE, | |
112 | FALSE, VM_PROT_ALL)) != KERN_SUCCESS) | |
113 | return kr; | |
1815bff5 A |
114 | mlock(bufReply, max_size + MAX_TRAILER_SIZE); |
115 | while(TRUE) { | |
83f6dbe8 A |
116 | mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options, |
117 | 0, max_size, rcv_name, | |
118 | MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
1815bff5 A |
119 | if (mr == MACH_MSG_SUCCESS) { |
120 | /* we have a request message */ | |
121 | ||
122 | if(!(default_pager_alerts_server( | |
123 | &bufRequest->Head, &bufReply->Head))) | |
124 | backing_store_triggers_server( | |
125 | &bufRequest->Head, &bufReply->Head); | |
126 | ||
127 | if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && | |
128 | bufReply->RetCode != KERN_SUCCESS) { | |
129 | if (bufReply->RetCode == MIG_NO_REPLY) | |
130 | /* | |
131 | * This return code is a little tricky-- | |
132 | * it appears that the demux routine found an | |
133 | * error of some sort, but since that error | |
134 | * would not normally get returned either to | |
135 | * the local user or the remote one, we pretend it's | |
136 | * ok. | |
137 | */ | |
138 | ||
139 | bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; | |
140 | mach_msg_destroy(&bufRequest->Head); | |
141 | continue; | |
142 | } | |
143 | ||
144 | if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { | |
145 | /* no reply port, so destroy the reply */ | |
146 | if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) | |
147 | mach_msg_destroy(&bufReply->Head); | |
148 | } else { | |
149 | break; | |
150 | } | |
151 | } else { | |
152 | break; | |
153 | } | |
154 | } | |
155 | ||
156 | (void)vm_deallocate(mach_task_self(), | |
157 | (vm_address_t) bufRequest, | |
158 | max_size + MAX_TRAILER_SIZE); | |
159 | (void)vm_deallocate(mach_task_self(), | |
160 | (vm_address_t) bufReply, | |
161 | max_size + MAX_TRAILER_SIZE); | |
162 | return KERN_FAILURE; | |
163 | ||
164 | } | |
165 | ||
166 | ||
167 | kern_return_t | |
168 | backing_store_triggers(dynamic_pager, hi_wat, flags, port) | |
169 | mach_port_t dynamic_pager; | |
170 | int hi_wat; | |
171 | int flags; | |
172 | mach_port_t port; | |
173 | { | |
c3a08f59 A |
174 | int cur_limits; |
175 | ||
176 | if (file_count > max_valid) | |
177 | cur_limits = max_valid; | |
178 | else | |
179 | cur_limits = file_count; | |
180 | ||
181 | if((hi_wat + limits[cur_limits].size) > limits[cur_limits].low_water) | |
1815bff5 | 182 | return KERN_FAILURE; /* let ipc system clean up port */ |
756446ec A |
183 | |
184 | /* If there was a previous registration, throw it away */ | |
185 | if (notify_port != MACH_PORT_NULL) { | |
186 | mach_port_deallocate(mach_task_self(), notify_port); | |
187 | notify_port = MACH_PORT_NULL; | |
188 | } | |
189 | ||
1815bff5 A |
190 | notify_port = port; |
191 | notify_high = hi_wat; | |
192 | if(hi_water < notify_high) { | |
193 | local_hi_water = notify_high; | |
194 | } else { | |
195 | local_hi_water = hi_water; | |
196 | } | |
197 | if(notify_high > hi_water) { | |
198 | default_pager_space_alert(trigger_port, HI_WAT_ALERT); | |
199 | } | |
200 | return KERN_SUCCESS; | |
201 | } | |
202 | ||
203 | ||
204 | kern_return_t | |
205 | default_pager_space_alert(alert_port, flags) | |
206 | mach_port_t alert_port; | |
207 | int flags; | |
208 | { | |
209 | char subfile[512]; | |
210 | FILE *file_ptr; | |
c3a08f59 | 211 | off_t filesize; |
1815bff5 | 212 | int error; |
756446ec | 213 | kern_return_t ret; |
c3a08f59 A |
214 | int cur_limits; |
215 | unsigned int cur_size; | |
216 | unsigned int notifications; | |
1815bff5 | 217 | |
c3a08f59 | 218 | |
1815bff5 | 219 | if(flags & HI_WAT_ALERT) { |
c3a08f59 | 220 | |
1815bff5 | 221 | file_count++; |
c3a08f59 A |
222 | |
223 | if (file_count > max_valid) | |
224 | cur_limits = max_valid; | |
225 | else | |
226 | cur_limits = file_count; | |
227 | ||
228 | cur_size = limits[cur_limits].size; | |
229 | filesize = cur_size; | |
230 | ||
231 | /* | |
232 | * because the LO_WAT threshold changes relative to | |
233 | * the size of the swap file we're creating | |
234 | * we need to reset the LO_WAT_ALERT threshold each | |
235 | * time we create a new swap file | |
236 | */ | |
237 | if (limits[cur_limits].low_water) | |
238 | notifications = HI_WAT_ALERT | LO_WAT_ALERT; | |
239 | else | |
240 | notifications = HI_WAT_ALERT; | |
241 | ||
1815bff5 A |
242 | sprintf(subfile, "%s%d", fileroot, file_count); |
243 | file_ptr = fopen(subfile, "w+"); | |
83f6dbe8 A |
244 | if (file_ptr == NULL) { |
245 | /* force error recovery below */ | |
246 | error = -1; | |
247 | } else { | |
248 | fchmod(fileno(file_ptr), (mode_t)01600); | |
249 | error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize); | |
250 | if(error) { | |
251 | error = ftruncate(fileno(file_ptr), filesize); | |
252 | } | |
253 | if(error) | |
254 | unlink(subfile); | |
255 | fclose(file_ptr); | |
756446ec | 256 | } |
c3a08f59 | 257 | |
1815bff5 | 258 | if(error == -1) { |
1815bff5 | 259 | file_count--; |
c3a08f59 A |
260 | |
261 | if (file_count > max_valid) | |
262 | cur_limits = max_valid; | |
263 | else | |
264 | cur_limits = file_count; | |
265 | ||
266 | if (limits[cur_limits].low_water) | |
267 | notifications = HI_WAT_ALERT | LO_WAT_ALERT; | |
268 | else | |
269 | notifications = HI_WAT_ALERT; | |
270 | ||
1815bff5 A |
271 | local_hi_water = local_hi_water>>2; |
272 | if(notify_high >= (local_hi_water)) { | |
756446ec | 273 | if(notify_port != MACH_PORT_NULL) { |
1815bff5 A |
274 | /* notify monitoring app of */ |
275 | /* backing store shortage */ | |
276 | backing_store_alert(notify_port, | |
277 | HI_WAT_ALERT); | |
278 | mach_port_deallocate(mach_task_self(), | |
279 | notify_port); | |
756446ec | 280 | notify_port = MACH_PORT_NULL; |
1815bff5 | 281 | notify_high = 0; |
1815bff5 A |
282 | } |
283 | } | |
c3a08f59 | 284 | macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port); |
1815bff5 A |
285 | } else { |
286 | if(hi_water < notify_high) { | |
287 | if(local_hi_water < notify_high) { | |
288 | bs_recovery = notify_high - local_hi_water; | |
289 | } | |
290 | local_hi_water = notify_high; | |
291 | } else { | |
292 | if(local_hi_water < hi_water) { | |
293 | bs_recovery = hi_water - local_hi_water; | |
294 | } | |
295 | local_hi_water = hi_water; | |
296 | } | |
c3a08f59 A |
297 | ret = macx_swapon(subfile, flags, cur_size, priority); |
298 | ||
756446ec A |
299 | if(ret) { |
300 | unlink(subfile); | |
301 | file_count--; | |
c3a08f59 A |
302 | |
303 | if (file_count > max_valid) | |
304 | cur_limits = max_valid; | |
305 | else | |
306 | cur_limits = file_count; | |
307 | ||
308 | if (limits[cur_limits].low_water) | |
309 | notifications = HI_WAT_ALERT | LO_WAT_ALERT; | |
310 | else | |
311 | notifications = HI_WAT_ALERT; | |
312 | ||
756446ec A |
313 | local_hi_water = local_hi_water>>2; |
314 | if(notify_high >= (local_hi_water)) { | |
315 | if(notify_port != MACH_PORT_NULL) { | |
316 | /* notify monitoring app of */ | |
317 | /* backing store shortage */ | |
318 | backing_store_alert( | |
319 | notify_port, | |
320 | HI_WAT_ALERT); | |
321 | mach_port_deallocate( | |
322 | mach_task_self(), | |
323 | notify_port); | |
324 | notify_port = MACH_PORT_NULL; | |
325 | notify_high = 0; | |
326 | } | |
327 | } | |
c3a08f59 A |
328 | macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port); |
329 | } else if(bs_recovery <= cur_size) { | |
1815bff5 A |
330 | if((bs_recovery != 0) && (notify_port)) { |
331 | backing_store_alert(notify_port, | |
332 | LO_WAT_ALERT); | |
333 | mach_port_deallocate(mach_task_self(), | |
334 | notify_port); | |
756446ec | 335 | notify_port = MACH_PORT_NULL; |
1815bff5 | 336 | notify_high = 0; |
1815bff5 A |
337 | bs_recovery = 0; |
338 | } | |
339 | } else | |
c3a08f59 | 340 | bs_recovery = bs_recovery-cur_size; |
1815bff5 | 341 | } |
c3a08f59 | 342 | macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port); |
1815bff5 A |
343 | } |
344 | if(flags & LO_WAT_ALERT) { | |
1815bff5 A |
345 | sprintf(subfile, "%s%d", fileroot, file_count); |
346 | if(hi_water < notify_high) { | |
347 | local_hi_water = notify_high; | |
348 | } else { | |
349 | local_hi_water = hi_water; | |
350 | } | |
756446ec | 351 | if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) { |
1815bff5 A |
352 | backing_store_alert(notify_port, LO_WAT_ALERT); |
353 | mach_port_deallocate(mach_task_self(), notify_port); | |
756446ec | 354 | notify_port = MACH_PORT_NULL; |
1815bff5 | 355 | notify_high = 0; |
1815bff5 A |
356 | bs_recovery = 0; |
357 | } | |
c3a08f59 A |
358 | if((error = macx_swapoff(subfile, flags)) == 0) { |
359 | ||
1815bff5 A |
360 | unlink(subfile); |
361 | file_count--; | |
c3a08f59 A |
362 | |
363 | if (file_count > max_valid) | |
364 | cur_limits = max_valid; | |
365 | else | |
366 | cur_limits = file_count; | |
367 | } else { | |
368 | if (file_count > max_valid) | |
369 | cur_limits = max_valid; | |
370 | else | |
371 | cur_limits = file_count; | |
1815bff5 | 372 | } |
c3a08f59 A |
373 | /* |
374 | * only need to reset the LO_WAT_ALERT... the HI_WAT size is fixed, | |
375 | * it doesn't change even if the swap file size shrinks or grows | |
376 | */ | |
377 | macx_triggers(local_hi_water, limits[cur_limits].low_water, LO_WAT_ALERT, alert_port); | |
1815bff5 A |
378 | } |
379 | return KERN_SUCCESS; | |
380 | } | |
381 | ||
382 | void | |
383 | wait_on_paging_trigger(trigger_port) | |
384 | mach_port_t trigger_port; | |
385 | { | |
386 | kern_return_t result; | |
387 | result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE); | |
388 | if (result != KERN_SUCCESS) { | |
389 | fprintf(stderr, "dynamic_pager: default pager alert failed\n"); | |
83f6dbe8 | 390 | exit(EXIT_FAILURE); |
1815bff5 | 391 | } |
83f6dbe8 | 392 | exit(EXIT_SUCCESS); |
1815bff5 A |
393 | } |
394 | ||
395 | void | |
396 | paging_setup(flags, size, priority, low, high) | |
397 | int flags; | |
398 | int size; | |
399 | int priority; | |
400 | int low; | |
401 | int high; | |
402 | { | |
403 | off_t filesize = size; | |
404 | char subfile[512]; | |
405 | FILE *file_ptr; | |
756446ec | 406 | int error; |
1815bff5 A |
407 | |
408 | file_count = 0; | |
409 | sprintf(subfile, "%s%d", fileroot, file_count); | |
410 | file_ptr = fopen(subfile, "w+"); | |
83f6dbe8 A |
411 | if (file_ptr == NULL) { |
412 | fprintf(stderr, "dynamic_pager: cannot create paging file %s!\n", | |
413 | subfile); | |
414 | exit(EXIT_FAILURE); | |
415 | } | |
1815bff5 | 416 | fchmod(fileno(file_ptr), (mode_t)01600); |
83f6dbe8 | 417 | |
756446ec A |
418 | error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize); |
419 | if(error) { | |
83f6dbe8 | 420 | error = ftruncate(fileno(file_ptr), filesize); |
756446ec | 421 | } |
1815bff5 | 422 | fclose(file_ptr); |
83f6dbe8 A |
423 | |
424 | if (error == -1) { | |
425 | fprintf(stderr, "dynamic_pager: cannot extend paging file size %s to %llu!\n", | |
426 | subfile, filesize); | |
427 | exit(EXIT_FAILURE); | |
428 | } | |
1815bff5 A |
429 | |
430 | macx_swapon(subfile, flags, size, priority); | |
c3a08f59 | 431 | |
1815bff5 | 432 | if(hi_water) { |
1c51fdde A |
433 | mach_msg_type_name_t poly; |
434 | ||
1815bff5 A |
435 | daemon(0,0); |
436 | ||
437 | if (mach_port_allocate(mach_task_self(), | |
438 | MACH_PORT_RIGHT_RECEIVE, | |
439 | &trigger_port) != KERN_SUCCESS) { | |
83f6dbe8 A |
440 | fprintf(stderr,"dynamic_pager: allocation of trigger port failed\n"); |
441 | exit(EXIT_FAILURE); | |
1815bff5 | 442 | } |
1c51fdde A |
443 | /* create a send right on our local port */ |
444 | mach_port_extract_right(mach_task_self(), trigger_port, | |
445 | MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly); | |
1815bff5 | 446 | macx_triggers(high, low, HI_WAT_ALERT, trigger_port); |
c3a08f59 | 447 | |
1815bff5 | 448 | if(low) { |
c3a08f59 | 449 | macx_triggers(high, low, LO_WAT_ALERT, trigger_port); |
1815bff5 A |
450 | } |
451 | /* register control port for applications wishing to */ | |
452 | /* get backing store notifications or change dynamic */ | |
453 | /* pager settings. */ | |
454 | set_dp_control_port(mach_host_self(), trigger_port); | |
455 | wait_on_paging_trigger(trigger_port); | |
456 | } | |
83f6dbe8 | 457 | exit(EXIT_SUCCESS); |
1815bff5 A |
458 | } |
459 | int | |
460 | main(int argc, char **argv) | |
461 | { | |
462 | extern char *optarg; | |
463 | extern int optind; | |
464 | char default_filename[] = "/private/var/vm/swapfile"; | |
465 | int ch; | |
c3a08f59 | 466 | int variable_sized = 1; |
1815bff5 A |
467 | |
468 | seteuid(getuid()); | |
469 | strcpy(fileroot, default_filename); | |
470 | ||
c3a08f59 A |
471 | limits[0].size = 20000000; |
472 | limits[0].low_water = 0; | |
473 | ||
474 | hi_water = 0; | |
475 | local_hi_water = 0; | |
476 | ||
477 | ||
1815bff5 A |
478 | while ((ch = getopt(argc, argv, "F:L:H:S:P:O:")) != EOF) { |
479 | switch((char)ch) { | |
480 | ||
481 | case 'F': | |
482 | strncpy(fileroot, optarg, 500); | |
483 | break; | |
484 | ||
485 | case 'L': | |
c3a08f59 A |
486 | variable_sized = 0; |
487 | limits[0].low_water = atoi(optarg); | |
1815bff5 A |
488 | break; |
489 | case 'H': | |
c3a08f59 | 490 | variable_sized = 0; |
1815bff5 A |
491 | hi_water = atoi(optarg); |
492 | break; | |
493 | case 'S': | |
c3a08f59 A |
494 | variable_sized = 0; |
495 | limits[0].size = atoi(optarg); | |
1815bff5 A |
496 | break; |
497 | case 'P': | |
498 | priority = atoi(optarg); | |
499 | break; | |
500 | ||
501 | default: | |
502 | (void)fprintf(stderr, | |
503 | "usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n"); | |
83f6dbe8 | 504 | exit(EXIT_FAILURE); |
1815bff5 A |
505 | } |
506 | } | |
c3a08f59 A |
507 | |
508 | if (variable_sized) { | |
509 | static char tmp[1024]; | |
510 | struct statfs sfs; | |
511 | char *q; | |
512 | int i; | |
513 | int mib[4]; | |
514 | size_t len; | |
515 | unsigned int size; | |
516 | u_int64_t memsize; | |
517 | u_int64_t fs_limit; | |
518 | ||
519 | /* | |
520 | * if we get here, then none of the following options were specified... -L, H, or -S | |
521 | * drop into a new mode that scales the size of the swap file based on how much free | |
522 | * space is left on the volume being used for swap and the amount of physical ram | |
523 | * installed on the system... | |
524 | * basically, we'll pick a maximum size that doesn't exceed the following limits... | |
83f6dbe8 | 525 | * 1/8 the remaining free space of the swap volume |
c3a08f59 A |
526 | * the size of phsyical ram |
527 | * MAXIMUM_SIZE - currently set to 1 Gbyte... | |
528 | * once we have the maximum, we'll create a list of sizes and low_water limits | |
529 | * we'll start with 2 files of MINIMUM_SIZE - currently 64 Mbytes... | |
530 | * subsequent entries will double in size up to the calculated maximum... the low_water | |
531 | * limit will be the sum of the current file size and the previous file size for each entry... | |
532 | * as we add or delete files, we'll use the current file_count as an index into this | |
533 | * table... if it's beyond the table size, we'll use the last entry | |
534 | * the table entry will determine the size of the file to be created and the new low_water mark... | |
535 | * the high_water mark is set to HI_WATER_DEFAULT which must be smaller than MINIMUM_SIZE... | |
536 | * currently it is set to 40,000,000 to match the size being requested by the application | |
537 | * monitoring low space conditions... having it set to the same size keeps us from creating | |
538 | * an additional swap file when it really isn't necessary | |
539 | */ | |
540 | ||
541 | /* | |
542 | * get rid of the filename at the end of the swap file specification | |
543 | * we only want the portion of the pathname that should already exist | |
544 | */ | |
545 | strcpy(tmp, fileroot); | |
546 | if (q = strrchr(tmp, '/')) | |
547 | *q = 0; | |
548 | ||
549 | if (statfs(tmp, &sfs) != -1) { | |
550 | /* | |
83f6dbe8 | 551 | * Limit the maximum size of a swap file to 1/8 the free |
c3a08f59 | 552 | * space available on the filesystem where the swap files |
83f6dbe8 A |
553 | * are to reside. This will allow us to allocate and |
554 | * deallocate in finer increments on systems without much | |
555 | * free space. | |
c3a08f59 | 556 | */ |
83f6dbe8 | 557 | fs_limit = ((u_int64_t)sfs.f_bfree * (u_int64_t)sfs.f_bsize) / 8; |
c3a08f59 A |
558 | |
559 | } else { | |
83f6dbe8 A |
560 | (void)fprintf(stderr, "dynamic_pager: swap directory must exist\n"); |
561 | exit(EXIT_FAILURE); | |
c3a08f59 A |
562 | } |
563 | mib[0] = CTL_HW; | |
564 | mib[1] = HW_MEMSIZE; | |
565 | len = sizeof(u_int64_t); | |
566 | ||
567 | if (sysctl(mib, 2, &memsize, &len, NULL, 0) < 0) { | |
568 | /* | |
569 | * if the sysctl fails for some reason | |
570 | * use the starting size as the default | |
571 | */ | |
572 | memsize = MINIMUM_SIZE; | |
573 | } | |
574 | if (memsize > fs_limit) | |
575 | /* | |
576 | * clip based on filesystem space available | |
577 | */ | |
578 | memsize = fs_limit; | |
579 | ||
580 | /* | |
581 | * further limit the maximum size of a swap file | |
582 | */ | |
583 | if (memsize > MAXIMUM_SIZE) | |
584 | memsize = MAXIMUM_SIZE; | |
585 | ||
586 | size = MINIMUM_SIZE; | |
587 | ||
588 | /* | |
589 | * start small and work our way up to the maximum | |
590 | * sized allowed... this way, we don't tie up too | |
591 | * much disk space if we never do any real paging | |
592 | */ | |
593 | for (max_valid = 0, i = 0; i < MAX_LIMITS; i++) { | |
594 | limits[i].size = size; | |
595 | ||
596 | if (i == 0) | |
597 | limits[i].low_water = size * 2; | |
598 | else { | |
599 | if ((limits[i - 1].size / 2) > HI_WATER_DEFAULT) | |
600 | limits[i].low_water = size + (limits[i - 1].size / 2); | |
601 | else | |
602 | limits[i].low_water = size + limits[i - 1].size; | |
603 | } | |
c3a08f59 A |
604 | |
605 | if (i) { | |
606 | /* | |
607 | * make the first 2 files the same size | |
608 | */ | |
609 | size = size * 2; | |
83f6dbe8 A |
610 | if (size > memsize) |
611 | break; | |
c3a08f59 A |
612 | } |
613 | max_valid++; | |
614 | } | |
615 | if (max_valid >= MAX_LIMITS) | |
616 | max_valid = MAX_LIMITS - 1; | |
617 | ||
618 | hi_water = HI_WATER_DEFAULT; | |
619 | } | |
1815bff5 | 620 | local_hi_water = hi_water; |
c3a08f59 A |
621 | |
622 | if((limits[0].low_water != 0) && (limits[0].low_water <= (limits[0].size + hi_water))) { | |
83f6dbe8 A |
623 | (void)fprintf(stderr, "dynamic_pager: low water trigger must be larger than size + hi_water\n"); |
624 | exit(EXIT_FAILURE); | |
1815bff5 A |
625 | } |
626 | argc -= optind; | |
627 | argv += optind; | |
c3a08f59 A |
628 | |
629 | paging_setup(0, limits[0].size, priority, limits[0].low_water, hi_water); | |
630 | ||
1815bff5 A |
631 | return (0); |
632 | } |