1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/*
* These routines create initial mmaps in the main process that every
* child process will end up inheriting.
*
* Children will copy the whole initial_mappings list to their own
* private copies, and then perform operations upon them.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "arch.h"
#include "list.h"
#include "maps.h"
#include "random.h"
#include "utils.h"
static void alloc_zero_map(unsigned long size, int prot, const char *name)
{
struct object *new;
int fd;
if (size == 0)
return;
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
outputerr("couldn't open /dev/zero\n");
exit(EXIT_FAILURE);
}
new = alloc_object();
new->map.size = size;
new->map.prot = prot;
new->map.type = INITIAL_ANON;
new->map.ptr = mmap(NULL, size, prot, MAP_ANONYMOUS | MAP_SHARED, fd, 0);
if (new->map.ptr == MAP_FAILED) {
outputerr("mmap failure:%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
new->map.name = zmalloc(80);
sprintf(new->map.name, "anon(%s)", name);
add_object(new, OBJ_GLOBAL, OBJ_MMAP_ANON);
close(fd);
}
unsigned long mapping_sizes[NR_MAPPING_SIZES] = {
-1, /* over-written with page_size below */
MB(1), MB(2),
GB(1),
};
static unsigned long long get_free_mem(void)
{
FILE *fp;
char *buffer;
size_t n = 0;
unsigned long long memfree = 0;
fp = fopen("/proc/meminfo", "r");
if (!fp)
return 0;
buffer = malloc(4096);
if (!buffer)
goto out_close;
while (getline(&buffer, &n, fp) >= 0) {
if (sscanf(buffer, "MemFree: %llu", &memfree) == 1) {
goto done;
}
}
done:
free(buffer);
out_close:
fclose(fp);
return memfree;
}
static void setup_mapping_sizes(void)
{
unsigned long long memfree;
mapping_sizes[0] = page_size;
/* Using 1GB mappings ends up oom'ing a lot, so we don't
* want to do it every single run. It's worth doing it
* occasionally though, to stress the oom paths.
*/
if (!(ONE_IN(100)))
goto disable_1gb_mappings;
memfree = get_free_mem();
if (memfree == 0) {
// Something is really fucked. Let's not try big mappings just in case.
goto disable_1gb_mappings;
}
if ((memfree * 1024) < GB(8ULL)) {
printf("Free memory: %.2fGB\n", (double) memfree / 1024 / 1024);
printf("Low on memory, disabling mmaping of 1GB pages\n");
goto disable_1gb_mappings;
}
// Because of increased mem usage, don't do nr_cpus * 4
if (max_children > 4) {
printf("Limiting children from %u to %u\n",
max_children, max_children / 4);
max_children /= 4;
return;
}
disable_1gb_mappings:
mapping_sizes[3] = page_size;
}
void setup_initial_mappings(void)
{
struct objhead *head;
unsigned int i;
head = get_objhead(OBJ_GLOBAL, OBJ_MMAP_ANON);
head->destroy = &map_destructor;
head->dump = &map_dump;
setup_mapping_sizes();
for (i = 0; i < ARRAY_SIZE(mapping_sizes); i++) {
alloc_zero_map(mapping_sizes[i], PROT_READ | PROT_WRITE, "PROT_READ | PROT_WRITE");
alloc_zero_map(mapping_sizes[i], PROT_READ, "PROT_READ");
alloc_zero_map(mapping_sizes[i], PROT_WRITE, "PROT_WRITE");
}
}
|