1 Star 0 Fork 2

gaoxuelong / stress-ng

forked from HoperunHarmony / stress-ng 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
stress-open.c 13.00 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
/*
* Copyright (C) 2013-2021 Canonical, Ltd.
* Copyright (C) 2022 Colin Ian King.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "stress-ng.h"
#if defined(HAVE_LINUX_OPENAT2_H)
#include <linux/openat2.h>
#endif
#if defined(HAVE_UTIME_H)
#include <utime.h>
#endif
typedef int (*stress_open_func_t)(void);
static const stress_help_t help[] = {
{ "o N", "open N", "start N workers exercising open/close" },
{ NULL, "open-ops N", "stop after N open/close bogo operations" },
{ NULL, "open-fd", "open files in /proc/$pid/fd" },
{ NULL, NULL, NULL }
};
static int stress_set_open_fd(const char *opt)
{
bool open_fd = true;
(void)opt;
return stress_set_setting("open-fd", TYPE_ID_BOOL, &open_fd);
}
static const stress_opt_set_func_t opt_set_funcs[] = {
{ OPT_open_fd, stress_set_open_fd, },
{ 0, NULL }
};
#if defined(HAVE_OPENAT) && \
defined(AT_FDCWD)
/*
* obsolete_futimesat()
* modern libc maps the obsolete futimesat to utimesat
*/
static inline int obsolete_futimesat(
int dir_fd,
const char *pathname,
const struct timeval tv[2])
{
int ret;
#if defined(__NR_futimesat)
/* Try direct system call first */
ret = (int)syscall(__NR_futimesat, dir_fd, pathname, tv);
if ((ret == 0) || (errno != ENOSYS))
return ret;
#endif
#if defined(HAVE_FUTIMESAT)
/* Try libc variant next */
ret = (int)futimesat(dir_fd, pathname, tv);
if ((ret == 0) || (errno != ENOSYS))
return ret;
#endif
/* Not available */
(void)dir_fd;
(void)pathname;
(void)tv;
errno = ENOSYS;
ret = -1;
return ret;
}
#endif
/*
* obsolete_futimes()
* modern libc maps the obsolete futimes to utimes
*/
static inline int obsolete_futimes(int fd, const struct timeval tv[2])
{
int ret;
#if defined(__NR_futimes)
/* Try direct system call first */
ret = (int)syscall(__NR_futimet, fd, tv);
if ((ret == 0) || (errno != ENOSYS))
return ret;
#endif
#if defined(HAVE_FUTIMES)
/* Try libc variant next */
ret = (int)futimes(fd, tv);
if ((ret == 0) || (errno != ENOSYS))
return ret;
#endif
/* Not available */
(void)fd;
(void)tv;
errno = ENOSYS;
ret = -1;
return ret;
}
static inline int open_arg2(const char *pathname, int flags)
{
int fd;
#if defined(__NR_open)
fd = (int)syscall(__NR_open, pathname, flags);
#else
fd = open(pathname, flags);
#endif
if (fd >= 0)
(void)obsolete_futimes(fd, NULL);
return fd;
}
static inline int open_arg3(const char *pathname, int flags, mode_t mode)
{
int fd;
#if defined(__NR_open)
fd = (int)syscall(__NR_open, pathname, flags, mode);
#else
fd = open(pathname, flags, mode);
#endif
if (fd >= 0) {
struct timeval tv[2];
/* Exercise illegal futimes, usec too small */
tv[0].tv_usec = -1;
tv[0].tv_sec = -1;
tv[1].tv_usec = -1;
tv[1].tv_sec = -1;
(void)obsolete_futimes(fd, tv);
}
return fd;
}
static int open_dev_zero_rd(void)
{
int flags = 0;
#if defined(O_ASYNC)
flags |= (stress_mwc32() & O_ASYNC);
#endif
#if defined(O_CLOEXEC)
flags |= (stress_mwc32() & O_CLOEXEC);
#endif
#if defined(O_LARGEFILE)
flags |= (stress_mwc32() & O_LARGEFILE);
#endif
#if defined(O_NOFOLLOW)
flags |= (stress_mwc32() & O_NOFOLLOW);
#endif
#if defined(O_NONBLOCK)
flags |= (stress_mwc32() & O_NONBLOCK);
#endif
#if defined(O_NDELAY)
flags |= (stress_mwc32() & O_NDELAY);
#endif
return open_arg2("/dev/zero", O_RDONLY | flags);
}
static int open_dev_null_wr(void)
{
int flags = 0;
#if defined(O_ASYNC)
flags |= (stress_mwc32() & O_ASYNC);
#endif
#if defined(O_CLOEXEC)
flags |= (stress_mwc32() & O_CLOEXEC);
#endif
#if defined(O_LARGEFILE)
flags |= (stress_mwc32() & O_LARGEFILE);
#endif
#if defined(O_NOFOLLOW)
flags |= (stress_mwc32() & O_NOFOLLOW);
#endif
#if defined(O_NONBLOCK)
flags |= (stress_mwc32() & O_NONBLOCK);
#endif
#if defined(O_DSYNC)
flags |= (stress_mwc32() & O_DSYNC);
#endif
#if defined(O_SYNC)
flags |= (stress_mwc32() & O_SYNC);
#endif
return open_arg2("/dev/null", O_WRONLY | flags);
}
#if defined(O_TMPFILE)
static int open_tmp_rdwr(void)
{
int flags = 0;
#if defined(O_TRUNC)
flags |= (stress_mwc32() & O_TRUNC);
#endif
#if defined(O_APPEND)
flags |= (stress_mwc32() & O_APPEND);
#endif
#if defined(O_NOATIME)
flags |= (stress_mwc32() & O_NOATIME);
#endif
#if defined(O_DIRECT)
flags |= (stress_mwc32() & O_DIRECT);
#endif
return open_arg3("/tmp", O_TMPFILE | flags | O_RDWR, S_IRUSR | S_IWUSR);
}
#endif
#if defined(O_TMPFILE)
static int open_tmpfile_no_rdwr(void)
{
/* Force -EINVAL, need O_WRONLY or O_RDWR to succeed */
return open_arg3("/tmp", O_TMPFILE, S_IRUSR | S_IWUSR);
}
#endif
#if defined(HAVE_POSIX_OPENPT) && \
defined(O_RDWR) && \
defined(N_NOCTTY)
static int open_pt(void)
{
return posix_openpt(O_RDWR | O_NOCTTY);
}
#endif
#if defined(O_TMPFILE) && \
defined(O_EXCL)
static int open_tmp_rdwr_excl(void)
{
return open_arg3("/tmp", O_TMPFILE | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
}
#endif
#if defined(O_DIRECTORY)
static int open_dir(void)
{
return open_arg2(".", O_DIRECTORY | O_RDONLY);
}
#endif
#if defined(O_PATH)
static int open_path(void)
{
return open_arg2(".", O_DIRECTORY | O_PATH);
}
#endif
#if defined(O_CREAT)
static int open_create_eisdir(void)
{
return open_arg3(".", O_CREAT, S_IRUSR | S_IWUSR);
}
#endif
#if defined(HAVE_OPENAT) && \
defined(AT_FDCWD)
static int open_with_openat_cwd(void)
{
char cwd[PATH_MAX];
char filename[PATH_MAX];
const char *temp_path = stress_get_temp_path();
int fd, ret;
if (!temp_path)
return -1;
if (!getcwd(cwd, sizeof(cwd)))
return -1;
if (chdir(temp_path) < 0)
return -1;
(void)snprintf(filename, sizeof(filename), "stress-open-%d-%" PRIu32,
(int)getpid(), stress_mwc32());
fd = openat(AT_FDCWD, filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd >= 0) {
struct timeval tv[2];
(void)obsolete_futimesat(AT_FDCWD, filename, NULL);
/* Exercise illegal times */
tv[0].tv_usec = 1000001;
tv[0].tv_sec = 0;
tv[1].tv_usec = 1000001;
tv[1].tv_sec = 0;
(void)obsolete_futimesat(AT_FDCWD, filename, tv);
(void)shim_force_unlink(filename);
}
ret = chdir(cwd);
(void)ret;
return fd;
}
#endif
#if defined(HAVE_OPENAT) && \
defined(AT_FDCWD) && \
defined(O_PATH) && \
defined(O_DIRECTORY)
static int open_with_openat_dir_fd(void)
{
char filename[PATH_MAX];
int fd, dir_fd;
(void)snprintf(filename, sizeof(filename), "stress-open-%d-%" PRIu32,
(int)getpid(), stress_mwc32());
dir_fd = open_arg2(".", O_DIRECTORY | O_PATH);
if (dir_fd < 0)
return -1;
fd = openat(dir_fd, filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd >= 0) {
(void)obsolete_futimesat(dir_fd, filename, NULL);
(void)shim_unlink(filename);
}
(void)close(dir_fd);
return fd;
}
#endif
#if defined(HAVE_OPENAT2) && \
defined(HAVE_LINUX_OPENAT2_H) && \
defined(RESOLVE_NO_SYMLINKS) && \
defined(__NR_openat2)
static int open_with_openat2_cwd(void)
{
static const unsigned int resolve_flags[] = {
#if defined(RESOLVE_BENEATH)
RESOLVE_BENEATH,
#endif
#if defined(RESOLVE_IN_ROOT)
RESOLVE_IN_ROOT,
#endif
#if defined(RESOLVE_NO_MAGICLINKS)
RESOLVE_NO_MAGICLINKS,
#endif
#if defined(RESOLVE_NO_SYMLINKS)
RESOLVE_NO_SYMLINKS,
#endif
#if defined(RESOLVE_NO_XDEV)
RESOLVE_NO_XDEV,
#endif
#if defined(RESOLVE_CACHED)
RESOLVE_CACHED,
#endif
0,
(unsigned int)~0, /* Intentionally illegal */
};
char cwd[PATH_MAX];
char filename[PATH_MAX];
const char *temp_path = stress_get_temp_path();
int fd = -1, ret;
size_t i = 0;
static size_t j;
struct open_how how;
if (!temp_path)
return -1;
if (!getcwd(cwd, sizeof(cwd)))
return -1;
if (chdir(temp_path) < 0)
return -1;
(void)snprintf(filename, sizeof(filename), "stress-open-%d-%" PRIu32,
(int)getpid(), stress_mwc32());
/*
* Work through resolve flags to find one that can
* open the file successfully
*/
for (i = 0; i < SIZEOF_ARRAY(resolve_flags); i++) {
(void)memset(&how, 0, sizeof(how));
how.flags = O_CREAT | O_RDWR;
how.mode = S_IRUSR | S_IWUSR;
how.resolve = resolve_flags[j++];
if (j >= SIZEOF_ARRAY(resolve_flags))
j = 0;
/* Exercise illegal usize field */
fd = (int)syscall(__NR_openat2, AT_FDCWD, filename, &how, 0);
if (fd >= 0) {
/* Unxexpected, but handle it anyhow */
(void)shim_unlink(filename);
break;
}
fd = (int)syscall(__NR_openat2, AT_FDCWD, filename, &how, sizeof(how));
if (fd >= 0) {
(void)shim_unlink(filename);
break;
}
}
ret = chdir(cwd);
(void)ret;
return fd;
}
#endif
static stress_open_func_t open_funcs[] = {
open_dev_zero_rd,
open_dev_null_wr,
#if defined(O_TMPFILE)
open_tmp_rdwr,
#endif
#if defined(O_TMPFILE) && \
defined(O_EXCL)
open_tmp_rdwr_excl,
#endif
#if defined(O_TMPFILE)
open_tmpfile_no_rdwr,
#endif
#if defined(O_DIRECTORY)
open_dir,
#endif
#if defined(O_PATH)
open_path,
#endif
#if defined(HAVE_POSIX_OPENPT) && \
defined(O_RDWR) && \
defined(N_NOCTTY)
open_pt,
#endif
#if defined(O_CREAT)
open_create_eisdir,
#endif
#if defined(HAVE_OPENAT) && \
defined(AT_FDCWD)
open_with_openat_cwd,
#endif
#if defined(HAVE_OPENAT) && \
defined(AT_FDCWD) && \
defined(O_PATH) && \
defined(O_DIRECTORY)
open_with_openat_dir_fd,
#endif
#if defined(HAVE_OPENAT2) && \
defined(HAVE_LINUX_OPENAT2_H) && \
defined(RESOLVE_NO_SYMLINKS) && \
defined(__NR_openat2)
open_with_openat2_cwd,
#endif
};
/*
* stress_fd_dir()
* try to open the files the the stressor parent has open
* via the file names provided in /proc/$PID/fd. This
* ignores opens that fail.
*/
static void stress_fd_dir(const char *path)
{
for (;;) {
struct dirent *de;
DIR *dir;
dir = opendir(path);
if (!dir)
return;
while ((de = readdir(dir)) != NULL) {
char name[PATH_MAX];
int fd;
stress_mk_filename(name, sizeof(name), path, de->d_name);
fd = open(name, O_RDONLY);
if (fd >= 0)
(void)close(fd);
}
(void)closedir(dir);
}
}
/*
* stress_open()
* stress system by rapid open/close calls
*/
static int stress_open(const stress_args_t *args)
{
int *fds;
char path[PATH_MAX];
size_t max_fds = stress_get_max_file_limit();
size_t sz;
pid_t pid = -1;
const pid_t mypid = getpid();
struct stat statbuf;
bool open_fd = false;
/*
* 32 bit systems may OOM if we have too many open fds, so
* try to constrain the max limit as a workaround.
*/
if (sizeof(void *) == 4)
max_fds = STRESS_MINIMUM(max_fds, 65536);
sz = max_fds * sizeof(*fds);
fds = (int *)mmap(NULL, sz, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (fds == MAP_FAILED) {
max_fds = STRESS_FD_MAX;
sz = max_fds * sizeof(*fds);
fds = (int *)mmap(NULL, sz, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (fds == MAP_FAILED) {
pr_inf("%s: cannot allocate file descriptors\n", args->name);
return EXIT_NO_RESOURCE;
}
}
(void)stress_get_setting("open-fd", &open_fd);
if (open_fd) {
(void)snprintf(path, sizeof(path), "/proc/%" PRIdMAX "/fd", (intmax_t)mypid);
if ((stat(path, &statbuf) == 0) &&
((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
pid = fork();
if (pid == 0) {
stress_fd_dir(path);
_exit(0);
}
}
}
stress_set_proc_state(args->name, STRESS_STATE_RUN);
do {
size_t i, n;
int ret;
unsigned int min_fd = UINT_MAX, max_fd = 0;
for (i = 0; i < max_fds; i++) {
for (;;) {
int idx;
if (!keep_stressing(args)) {
if (pid > 1)
(void)kill(pid, SIGKILL);
goto close_all;
}
idx = stress_mwc32() % SIZEOF_ARRAY(open_funcs);
fds[i] = open_funcs[idx]();
if (fds[i] >= 0)
break;
/* Check if we hit the open file limit */
if ((errno == EMFILE) || (errno == ENFILE)) {
if (pid > 1)
(void)kill(pid, SIGKILL);
goto close_all;
}
/* Other error occurred, retry */
}
if (fds[i] >= 0) {
if (fds[i] > (int)max_fd)
max_fd = (unsigned int)fds[i];
if (fds[i] < (int)min_fd)
min_fd = (unsigned int)fds[i];
}
stress_read_fdinfo(mypid, fds[i]);
inc_counter(args);
}
close_all:
n = i;
/*
* try fast close of a range, fall back to
* normal close if ENOSYS
*/
ret = shim_close_range(min_fd, max_fd, 0);
if ((ret < 1) && (errno == ENOSYS)) {
for (i = 0; i < n; i++)
(void)close(fds[i]);
}
} while (keep_stressing(args));
stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
(void)munmap((void *)fds, sz);
if (pid > 1) {
int status;
(void)kill(pid, SIGKILL);
(void)waitpid(pid, &status, 0);
}
return EXIT_SUCCESS;
}
stressor_info_t stress_open_info = {
.stressor = stress_open,
.class = CLASS_FILESYSTEM | CLASS_OS,
.opt_set_funcs = opt_set_funcs,
.help = help
};
1
https://gitee.com/gaoxuelong/stress-ng.git
git@gitee.com:gaoxuelong/stress-ng.git
gaoxuelong
stress-ng
stress-ng
master

搜索帮助