/* * stress_kcmp * stress sys_kcmp */ static int stress_kcmp(const args_t *args) { pid_t pid1; int fd1; #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) int efd, sfd; int so_reuseaddr = 1; struct epoll_event ev; struct sockaddr *addr = NULL; socklen_t addr_len = 0; #endif int ret = EXIT_SUCCESS; static const char *capfail = "need CAP_SYS_PTRACE capability to run kcmp stressor, " "aborting stress test\n"; if ((fd1 = open("/dev/null", O_WRONLY)) < 0) { pr_fail_err("open"); return EXIT_FAILURE; } #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) efd = -1; if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { sfd = -1; goto again; } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { (void)close(sfd); sfd = -1; goto again; } stress_set_sockaddr(args->name, args->instance, args->ppid, AF_INET, 23000, &addr, &addr_len, NET_ADDR_ANY); if (bind(sfd, addr, addr_len) < 0) { (void)close(sfd); sfd = -1; goto again; } if (listen(sfd, SOMAXCONN) < 0) { (void)close(sfd); sfd = -1; goto again; } efd = epoll_create1(0); if (efd < 0) { (void)close(sfd); sfd = -1; efd = -1; goto again; } (void)memset(&ev, 0, sizeof(ev)); ev.data.fd = efd; ev.events = EPOLLIN | EPOLLET; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &ev) < 0) { (void)close(sfd); (void)close(efd); sfd = -1; efd = -1; } #endif again: pid1 = fork(); if (pid1 < 0) { if (g_keep_stressing_flag && ((errno == EAGAIN) || (errno == ENOMEM))) goto again; pr_fail_dbg("fork"); (void)close(fd1); #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) if (sfd != -1) (void)close(sfd); #endif return EXIT_FAILURE; } else if (pid1 == 0) { (void)setpgid(0, g_pgrp); stress_parent_died_alarm(); /* Child */ while (g_keep_stressing_flag) (void)pause(); /* will never get here */ (void)close(fd1); #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) if (efd != -1) (void)close(efd); if (sfd != -1) (void)close(sfd); #endif _exit(EXIT_SUCCESS); } else { /* Parent */ int fd2, status, pid2; (void)setpgid(pid1, g_pgrp); pid2 = getpid(); if ((fd2 = open("/dev/null", O_WRONLY)) < 0) { pr_fail_err("open"); ret = EXIT_FAILURE; goto reap; } do { KCMP(pid1, pid2, SHIM_KCMP_FILE, fd1, fd2); KCMP(pid1, pid1, SHIM_KCMP_FILE, fd1, fd1); KCMP(pid2, pid2, SHIM_KCMP_FILE, fd1, fd1); KCMP(pid2, pid2, SHIM_KCMP_FILE, fd2, fd2); KCMP(pid1, pid2, SHIM_KCMP_FILES, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_FILES, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_FILES, 0, 0); KCMP(pid1, pid2, SHIM_KCMP_FS, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_FS, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_FS, 0, 0); KCMP(pid1, pid2, SHIM_KCMP_IO, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_IO, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_IO, 0, 0); KCMP(pid1, pid2, SHIM_KCMP_SIGHAND, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_SIGHAND, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_SIGHAND, 0, 0); KCMP(pid1, pid2, SHIM_KCMP_SYSVSEM, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_SYSVSEM, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_SYSVSEM, 0, 0); KCMP(pid1, pid2, SHIM_KCMP_VM, 0, 0); KCMP(pid1, pid1, SHIM_KCMP_VM, 0, 0); KCMP(pid2, pid2, SHIM_KCMP_VM, 0, 0); #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) if (efd != -1) { struct kcmp_epoll_slot slot; slot.efd = efd; slot.tfd = sfd; slot.toff = 0; KCMP(pid1, pid2, SHIM_KCMP_EPOLL_TFD, efd, (unsigned long)&slot); KCMP(pid2, pid1, SHIM_KCMP_EPOLL_TFD, efd, (unsigned long)&slot); KCMP(pid2, pid2, SHIM_KCMP_EPOLL_TFD, efd, (unsigned long)&slot); } #endif /* Same simple checks */ if (g_opt_flags & OPT_FLAGS_VERIFY) { KCMP_VERIFY(pid1, pid1, SHIM_KCMP_FILE, fd1, fd1, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_FILES, 0, 0, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_FS, 0, 0, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_IO, 0, 0, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_SIGHAND, 0, 0, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_SYSVSEM, 0, 0, 0); KCMP_VERIFY(pid1, pid1, SHIM_KCMP_VM, 0, 0, 0); KCMP_VERIFY(pid1, pid2, SHIM_KCMP_SYSVSEM, 0, 0, 0); #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) if (efd != -1) { struct kcmp_epoll_slot slot; slot.efd = efd; slot.tfd = sfd; slot.toff = 0; KCMP(pid1, pid2, SHIM_KCMP_EPOLL_TFD, efd, (unsigned long)&slot); } #endif } inc_counter(args); } while (keep_stressing()); reap: if (fd2 >= 0) (void)close(fd2); (void)kill(pid1, SIGKILL); (void)shim_waitpid(pid1, &status, 0); (void)close(fd1); } #if defined(HAVE_SYS_EPOLL_H) && NEED_GLIBC(2,3,2) if (efd != -1) (void)close(efd); if (sfd != -1) (void)close(sfd); #endif return ret; }
/* * stress_udp * stress by heavy udp ops */ int stress_udp( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { pid_t pid, ppid = getppid(); int rc = EXIT_SUCCESS; pr_dbg(stderr, "%s: process [%d] using udp port %d\n", name, getpid(), opt_udp_port + instance); again: pid = fork(); if (pid < 0) { if (opt_do_run && (errno == EAGAIN)) goto again; pr_failed_dbg(name, "fork"); return EXIT_FAILURE; } else if (pid == 0) { /* Child, client */ struct sockaddr *addr; do { char buf[UDP_BUF]; socklen_t len; int fd; int j = 0; if ((fd = socket(opt_udp_domain, SOCK_DGRAM, 0)) < 0) { pr_failed_dbg(name, "socket"); /* failed, kick parent to finish */ (void)kill(getppid(), SIGALRM); exit(EXIT_FAILURE); } stress_set_sockaddr(name, instance, ppid, opt_udp_domain, opt_udp_port, &addr, &len); do { size_t i; for (i = 16; i < sizeof(buf); i += 16, j++) { memset(buf, 'A' + (j % 26), sizeof(buf)); ssize_t ret = sendto(fd, buf, i, 0, addr, len); if (ret < 0) { if (errno != EINTR) pr_failed_dbg(name, "sendto"); break; } } } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)close(fd); } while (opt_do_run && (!max_ops || *counter < max_ops)); #ifdef AF_UNIX if (opt_udp_domain == AF_UNIX) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif /* Inform parent we're all done */ (void)kill(getppid(), SIGALRM); exit(EXIT_SUCCESS); } else { /* Parent, server */ char buf[UDP_BUF]; int fd, status; int so_reuseaddr = 1; socklen_t addr_len = 0; struct sigaction new_action; struct sockaddr *addr; new_action.sa_handler = handle_udp_sigalrm; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction(SIGALRM, &new_action, NULL) < 0) { pr_failed_err(name, "sigaction"); rc = EXIT_FAILURE; goto die; } if ((fd = socket(opt_udp_domain, SOCK_DGRAM, 0)) < 0) { pr_failed_dbg(name, "socket"); rc = EXIT_FAILURE; goto die; } stress_set_sockaddr(name, instance, ppid, opt_udp_domain, opt_udp_port, &addr, &addr_len); if (bind(fd, addr, addr_len) < 0) { pr_failed_dbg(name, "bind"); rc = EXIT_FAILURE; goto die_close; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { pr_failed_dbg(name, "setsockopt"); rc = EXIT_FAILURE; goto die_close; } do { socklen_t len = addr_len; ssize_t n = recvfrom(fd, buf, sizeof(buf), 0, addr, &len); if (n == 0) break; if (n < 0) { if (errno != EINTR) pr_failed_dbg(name, "recvfrom"); break; } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); die_close: (void)close(fd); die: #ifdef AF_UNIX if (opt_udp_domain == AF_UNIX) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif if (pid) { (void)kill(pid, SIGKILL); (void)waitpid(pid, &status, 0); } } return rc; }
/* * epoll_server() * wait on connections and read data */ static void epoll_server( const int child, uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t ppid) { int efd = -1, sfd = -1, rc = EXIT_SUCCESS; int so_reuseaddr = 1; int port = opt_epoll_port + child + (max_servers * instance); struct sigaction new_action; struct epoll_event *events = NULL; struct sockaddr *addr = NULL; socklen_t addr_len = 0; new_action.sa_handler = handle_socket_sigalrm; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction(SIGALRM, &new_action, NULL) < 0) { pr_fail_err(name, "sigaction"); rc = EXIT_FAILURE; goto die; } if ((sfd = socket(opt_epoll_domain, SOCK_STREAM, 0)) < 0) { pr_fail_err(name, "socket"); rc = EXIT_FAILURE; goto die; } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { pr_fail_err(name, "setsockopt"); rc = EXIT_FAILURE; goto die_close; } stress_set_sockaddr(name, instance, ppid, opt_epoll_domain, port, &addr, &addr_len); if (bind(sfd, addr, addr_len) < 0) { pr_fail_err(name, "bind"); rc = EXIT_FAILURE; goto die_close; } if (epoll_set_fd_nonblock(sfd) < 0) { pr_fail_err(name, "setting socket to non-blocking"); rc = EXIT_FAILURE; goto die_close; } if (listen(sfd, SOMAXCONN) < 0) { pr_fail_err(name, "listen"); rc = EXIT_FAILURE; goto die_close; } if ((efd = epoll_create1(0)) < 0) { pr_fail_err(name, "epoll_create1"); rc = EXIT_FAILURE; goto die_close; } if (epoll_ctl_add(efd, sfd) < 0) { pr_fail_err(name, "epoll ctl add"); rc = EXIT_FAILURE; goto die_close; } if ((events = calloc(MAX_EPOLL_EVENTS, sizeof(struct epoll_event))) == NULL) { pr_fail_err(name, "epoll ctl add"); rc = EXIT_FAILURE; goto die_close; } do { int n, i; memset(events, 0, MAX_EPOLL_EVENTS * sizeof(struct epoll_event)); errno = 0; /* * Wait for 100ms for an event, allowing us to * to break out if opt_do_run has been changed */ n = epoll_wait(efd, events, MAX_EPOLL_EVENTS, 100); if (n < 0) { if (errno != EINTR) { pr_fail_err(name, "epoll_wait"); rc = EXIT_FAILURE; goto die_close; } break; } for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* * Error has occurred or fd is not * for reading anymore.. so reap fd */ (void)close(events[i].data.fd); } else if (sfd == events[i].data.fd) { /* * The listening socket has notification(s) * pending, so handle incoming connections */ if (epoll_notification(name, efd, sfd) < 0) break; } else { /* * The fd has data available, so read it */ epoll_recv_data(events[i].data.fd); } } } while (opt_do_run && (!max_ops || *counter < max_ops)); die_close: if (efd != -1) (void)close(efd); if (sfd != -1) (void)close(sfd); die: #ifdef AF_UNIX if (addr && (opt_epoll_domain == AF_UNIX)) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif free(events); exit(rc); }
/* * epoll_client() * rapidly try to connect to server(s) and * send a relatively short message */ static int epoll_client( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t ppid) { int port_counter = 0; uint64_t connect_timeouts = 0; struct sigaction new_action; struct sigevent sev; struct itimerspec timer; struct sockaddr *addr = NULL; new_action.sa_flags = 0; new_action.sa_handler = epoll_timer_handler; sigemptyset(&new_action.sa_mask); if (sigaction(SIGRTMIN, &new_action, NULL) < 0) { pr_fail_err(name, "sigaction"); return -1; } do { char buf[4096]; int fd, saved_errno; int retries = 0; int ret = -1; int port = opt_epoll_port + port_counter + (max_servers * instance); socklen_t addr_len = 0; /* Cycle through the servers */ port_counter = (port_counter + 1) % max_servers; retry: if (!opt_do_run) break; if ((fd = socket(opt_epoll_domain, SOCK_STREAM, 0)) < 0) { pr_fail_dbg(name, "socket"); return -1; } sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &epoll_timerid; if (timer_create(CLOCK_REALTIME, &sev, &epoll_timerid) < 0) { pr_fail_err(name, "timer_create"); (void)close(fd); return -1; } /* * Allow 1 second for connection to occur, * connect can block if the connection table * fills up because we're waiting for TIME-OUTs * to occur on previously closed connections */ timer.it_value.tv_sec = 0; timer.it_value.tv_nsec = 250000000; timer.it_interval.tv_sec = timer.it_value.tv_sec; timer.it_interval.tv_nsec = timer.it_value.tv_nsec; if (timer_settime(epoll_timerid, 0, &timer, NULL) < 0) { pr_fail_err(name, "timer_settime"); (void)close(fd); return -1; } stress_set_sockaddr(name, instance, ppid, opt_epoll_domain, port, &addr, &addr_len); errno = 0; ret = connect(fd, addr, addr_len); saved_errno = errno; /* No longer need timer */ if (timer_delete(epoll_timerid) < 0) { pr_fail_err(name, "timer_delete"); (void)close(fd); return -1; } if (ret < 0) { switch (saved_errno) { case EINTR: connect_timeouts++; break; case ECONNREFUSED: /* No servers yet running */ case ENOENT: /* unix domain not yet created */ break; default: pr_dbg(stderr, "%s: connect failed: %d (%s)\n", name, saved_errno, strerror(saved_errno)); break; } (void)close(fd); usleep(100000); /* Twiddle fingers for a moment */ retries++; if (retries > 1000) { /* Sigh, give up.. */ errno = saved_errno; pr_fail_dbg(name, "too many connects"); return -1; } goto retry; } memset(buf, 'A' + (*counter % 26), sizeof(buf)); if (send(fd, buf, sizeof(buf), 0) < 0) { (void)close(fd); pr_fail_dbg(name, "send"); break; } (void)close(fd); #if defined(_POSIX_PRIORITY_SCHEDULING) sched_yield(); #endif (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); #ifdef AF_UNIX if (addr && (opt_epoll_domain == AF_UNIX)) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif if (connect_timeouts) pr_dbg(stderr, "%s: %" PRIu64 " x 0.25 second connect timeouts, " "connection table full (instance %" PRIu32 ")\n", name, connect_timeouts, instance); return EXIT_SUCCESS; }
/* * stress_socket_server() * server writer */ static int stress_socket_server( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t pid, const pid_t ppid) { char buf[SOCKET_BUF]; int fd, status; int so_reuseaddr = 1; socklen_t addr_len = 0; struct sockaddr *addr; uint64_t msgs = 0; int rc = EXIT_SUCCESS; setpgid(pid, pgrp); if (stress_sighandler(name, SIGALRM, handle_socket_sigalrm, NULL) < 0) { rc = EXIT_FAILURE; goto die; } if ((fd = socket(opt_socket_domain, SOCK_STREAM, 0)) < 0) { rc = exit_status(errno); pr_fail_dbg(name, "socket"); goto die; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { pr_fail_dbg(name, "setsockopt"); rc = EXIT_FAILURE; goto die_close; } stress_set_sockaddr(name, instance, ppid, opt_socket_domain, opt_socket_port, &addr, &addr_len); if (bind(fd, addr, addr_len) < 0) { rc = exit_status(errno); pr_fail_dbg(name, "bind"); goto die_close; } if (listen(fd, 10) < 0) { pr_fail_dbg(name, "listen"); rc = EXIT_FAILURE; goto die_close; } do { int sfd = accept(fd, (struct sockaddr *)NULL, NULL); if (sfd >= 0) { size_t i, j; struct sockaddr addr; socklen_t len; int sndbuf; struct msghdr msg; struct iovec vec[sizeof(buf)/16]; #if defined(HAVE_SENDMMSG) struct mmsghdr msgvec[MSGVEC_SIZE]; unsigned int msg_len = 0; #endif #if defined(SOCKET_NODELAY) int one = 1; #endif len = sizeof(addr); if (getsockname(fd, &addr, &len) < 0) { pr_fail_dbg(name, "getsockname"); (void)close(sfd); break; } len = sizeof(sndbuf); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len) < 0) { pr_fail_dbg(name, "getsockopt"); (void)close(sfd); break; } #if defined(SOCKET_NODELAY) if (opt_flags & OPT_FLAGS_SOCKET_NODELAY) { if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) { pr_inf(stderr, "%s: setsockopt TCP_NODELAY " "failed and disabled, errno=%d (%s)\n", name, errno, strerror(errno)); opt_flags &= ~OPT_FLAGS_SOCKET_NODELAY; } } #endif memset(buf, 'A' + (*counter % 26), sizeof(buf)); switch (opt_socket_opts) { case SOCKET_OPT_SEND: for (i = 16; i < sizeof(buf); i += 16) { ssize_t ret = send(sfd, buf, i, 0); if (ret < 0) { if (errno != EINTR) pr_fail_dbg(name, "send"); break; } else msgs++; } break; case SOCKET_OPT_SENDMSG: for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) { vec[j].iov_base = buf; vec[j].iov_len = i; } memset(&msg, 0, sizeof(msg)); msg.msg_iov = vec; msg.msg_iovlen = j; if (sendmsg(sfd, &msg, 0) < 0) { if (errno != EINTR) pr_fail_dbg(name, "sendmsg"); } else msgs += j; break; #if defined(HAVE_SENDMMSG) case SOCKET_OPT_SENDMMSG: memset(msgvec, 0, sizeof(msgvec)); for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) { vec[j].iov_base = buf; vec[j].iov_len = i; msg_len += i; } for (i = 0; i < MSGVEC_SIZE; i++) { msgvec[i].msg_hdr.msg_iov = vec; msgvec[i].msg_hdr.msg_iovlen = j; } if (sendmmsg(sfd, msgvec, MSGVEC_SIZE, 0) < 0) { if (errno != EINTR) pr_fail_dbg(name, "sendmmsg"); } else msgs += (MSGVEC_SIZE * j); break; #endif default: /* Should never happen */ pr_err(stderr, "%s: bad option %d\n", name, opt_socket_opts); (void)close(sfd); goto die_close; } if (getpeername(sfd, &addr, &len) < 0) { pr_fail_dbg(name, "getpeername"); } (void)close(sfd); } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); die_close: (void)close(fd); die: #ifdef AF_UNIX if (opt_socket_domain == AF_UNIX) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif if (pid) { (void)kill(pid, SIGKILL); (void)waitpid(pid, &status, 0); } pr_dbg(stderr, "%s: %" PRIu64 " messages sent\n", name, msgs); return rc; }
/* * stress_socket_client() * client reader */ static void stress_socket_client( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t ppid) { struct sockaddr *addr; setpgid(0, pgrp); stress_parent_died_alarm(); do { char buf[SOCKET_BUF]; int fd; int retries = 0; socklen_t addr_len = 0; retry: if (!opt_do_run) { (void)kill(getppid(), SIGALRM); exit(EXIT_FAILURE); } if ((fd = socket(opt_socket_domain, SOCK_STREAM, 0)) < 0) { pr_fail_dbg(name, "socket"); /* failed, kick parent to finish */ (void)kill(getppid(), SIGALRM); exit(EXIT_FAILURE); } stress_set_sockaddr(name, instance, ppid, opt_socket_domain, opt_socket_port, &addr, &addr_len); if (connect(fd, addr, addr_len) < 0) { (void)close(fd); usleep(10000); retries++; if (retries > 100) { /* Give up.. */ pr_fail_dbg(name, "connect"); (void)kill(getppid(), SIGALRM); exit(EXIT_FAILURE); } goto retry; } do { ssize_t n = recv(fd, buf, sizeof(buf), 0); if (n == 0) break; if (n < 0) { if (errno != EINTR) pr_fail_dbg(name, "recv"); break; } } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)shutdown(fd, SHUT_RDWR); (void)close(fd); } while (opt_do_run && (!max_ops || *counter < max_ops)); #ifdef AF_UNIX if (opt_socket_domain == AF_UNIX) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif /* Inform parent we're all done */ (void)kill(getppid(), SIGALRM); }