/* * stress_shm_sysv_child() * stress out the shm allocations. This can be killed by * the out of memory killer, so we need to keep the parent * informed of the allocated shared memory ids so these can * be reaped cleanly if this process gets prematurely killed. */ static int stress_shm_sysv_child( const int fd, uint64_t *const counter, const uint64_t max_ops, const char *name, const size_t max_sz, const size_t page_size) { struct sigaction new_action; void *addrs[MAX_SHM_SYSV_SEGMENTS]; key_t keys[MAX_SHM_SYSV_SEGMENTS]; int shm_ids[MAX_SHM_SYSV_SEGMENTS]; shm_msg_t msg; size_t i; int rc = EXIT_SUCCESS; bool ok = true; int mask = ~0; int instances; new_action.sa_handler = handle_shm_sysv_sigalrm; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction(SIGALRM, &new_action, NULL) < 0) { pr_fail_err(name, "sigaction"); return EXIT_FAILURE; } memset(addrs, 0, sizeof(addrs)); memset(keys, 0, sizeof(keys)); for (i = 0; i < MAX_SHM_SYSV_SEGMENTS; i++) shm_ids[i] = -1; /* Make sure this is killable by OOM killer */ set_oom_adjustment(name, true); if ((instances = stressor_instances(STRESS_SHM_SYSV)) < 1) instances = (int)stress_get_processors_configured(); /* Should never happen, but be safe */ if (instances < 1) instances = 1; do { size_t sz = max_sz; for (i = 0; i < opt_shm_sysv_segments; i++) { int shm_id, count = 0; void *addr; key_t key; size_t shmall, freemem, totalmem; /* Try hard not to overcommit at this current time */ stress_get_memlimits(&shmall, &freemem, &totalmem); shmall /= instances; freemem /= instances; if ((shmall > page_size) && sz > shmall) sz = shmall; if ((freemem > page_size) && sz > freemem) sz = freemem; if (!opt_do_run) goto reap; for (count = 0; count < KEY_GET_RETRIES; count++) { bool unique = true; const int rnd = mwc32() % SIZEOF_ARRAY(shm_flags); const int rnd_flag = shm_flags[rnd] & mask; if (sz < page_size) goto reap; /* Get a unique key */ do { size_t j; if (!opt_do_run) goto reap; /* Get a unique random key */ key = (key_t)mwc16(); for (j = 0; j < i - 1; j++) { if (key == keys[j]) { unique = false; break; } } if (!opt_do_run) goto reap; } while (!unique); shm_id = shmget(key, sz, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | rnd_flag); if (shm_id >= 0) break; if (errno == EINTR) goto reap; if (errno == EPERM) { /* ignore using the flag again */ mask &= ~rnd_flag; } if ((errno == EINVAL) || (errno == ENOMEM)) { /* * On some systems we may need * to reduce the size */ sz = sz / 2; } } if (shm_id < 0) { ok = false; pr_fail(stderr, "%s: shmget failed: errno=%d (%s)\n", name, errno, strerror(errno)); rc = EXIT_FAILURE; goto reap; } /* Inform parent of the new shm ID */ msg.index = i; msg.shm_id = shm_id; if (write(fd, &msg, sizeof(msg)) < 0) { pr_err(stderr, "%s: write failed: errno=%d: (%s)\n", name, errno, strerror(errno)); rc = EXIT_FAILURE; goto reap; } addr = shmat(shm_id, NULL, 0); if (addr == (char *) -1) { ok = false; pr_fail(stderr, "%s: shmat failed: errno=%d (%s)\n", name, errno, strerror(errno)); rc = EXIT_FAILURE; goto reap; } addrs[i] = addr; shm_ids[i] = shm_id; keys[i] = key; if (!opt_do_run) goto reap; (void)mincore_touch_pages(addr, sz); if (!opt_do_run) goto reap; (void)madvise_random(addr, sz); if (!opt_do_run) goto reap; if (stress_shm_sysv_check(addr, sz, page_size) < 0) { ok = false; pr_fail(stderr, "%s: memory check failed\n", name); rc = EXIT_FAILURE; goto reap; } (*counter)++; } reap: for (i = 0; i < opt_shm_sysv_segments; i++) { if (addrs[i]) { if (shmdt(addrs[i]) < 0) { pr_fail(stderr, "%s: shmdt failed: errno=%d (%s)\n", name, errno, strerror(errno)); } } if (shm_ids[i] >= 0) { if (shmctl(shm_ids[i], IPC_RMID, NULL) < 0) { if (errno != EIDRM) pr_fail(stderr, "%s: shmctl failed: errno=%d (%s)\n", name, errno, strerror(errno)); } } /* Inform parent shm ID is now free */ msg.index = i; msg.shm_id = -1; if (write(fd, &msg, sizeof(msg)) < 0) { pr_dbg(stderr, "%s: write failed: errno=%d: (%s)\n", name, errno, strerror(errno)); ok = false; } addrs[i] = NULL; shm_ids[i] = -1; keys[i] = 0; } } while (ok && opt_do_run && (!max_ops || *counter < max_ops)); /* Inform parent of end of run */ msg.index = -1; msg.shm_id = -1; if (write(fd, &msg, sizeof(msg)) < 0) { pr_err(stderr, "%s: write failed: errno=%d: (%s)\n", name, errno, strerror(errno)); rc = EXIT_FAILURE; } return rc; }
/* * stress_mmapfork() * stress mappings + fork VM subystem */ int stress_mmapfork( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { pid_t pids[MAX_PIDS]; struct sysinfo info; void *ptr; int instances; (void)instance; if ((instances = stressor_instances(STRESS_MMAPFORK)) < 1) instances = (int)stress_get_processors_configured(); do { size_t i, n; size_t len; memset(pids, 0, sizeof(pids)); for (n = 0; n < MAX_PIDS; n++) { retry: if (!opt_do_run) goto reap; pids[n] = fork(); if (pids[n] < 0) { /* Out of resources for fork, re-do, ugh */ if (errno == EAGAIN) { usleep(10000); goto retry; } break; } if (pids[n] == 0) { /* Child */ if (sysinfo(&info) < 0) { pr_failed_err(name, "sysinfo"); _exit(0); } len = ((size_t)info.freeram / (instances * MAX_PIDS)) / 2; ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_POPULATE | MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (ptr != MAP_FAILED) { madvise(ptr, len, MADV_WILLNEED); memset(ptr, 0, len); madvise(ptr, len, MADV_DONTNEED); munmap(ptr, len); } _exit(0); } } reap: for (i = 0; i < n; i++) { int status; if (waitpid(pids[i], &status, 0) < 0) { if (errno != EINTR) pr_err(stderr, "%s: waitpid errno=%d (%s)\n", name, errno, strerror(errno)); } } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); return EXIT_SUCCESS; }