examples: detect fio backend fd redirection
It's useful to be able to run fio daemonized, and very recent versions of fio redirect stdout/stderr to /dev/null in order to avoid the problem that previously caused the plugin to abort. Detect if this redirection has happened and allow fio to run in this case. Signed-off-by: John Levon <john.levon@nutanix.com> Change-Id: I8ec13a4c26a0acc67b15fa5e8502dc28d341e441 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9691 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Andreas Economides <andreas.economides@nutanix.com>
This commit is contained in:
parent
97c5103a8f
commit
46550aedc9
@ -426,6 +426,27 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fio_redirected_to_dev_null(void)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX] = "";
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
ret = readlink("/proc/self/fd/1", path, sizeof(path));
|
||||||
|
|
||||||
|
if (ret == -1 || strcmp(path, "/dev/null") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = readlink("/proc/self/fd/2", path, sizeof(path));
|
||||||
|
|
||||||
|
if (ret == -1 || strcmp(path, "/dev/null") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called for each thread to fill in the 'real_file_size' member for
|
/* Called for each thread to fill in the 'real_file_size' member for
|
||||||
* each file associated with this thread. This is called prior to
|
* each file associated with this thread. This is called prior to
|
||||||
* the init operation (spdk_fio_init()) below. This call will occur
|
* the init operation (spdk_fio_init()) below. This call will occur
|
||||||
@ -439,16 +460,18 @@ spdk_fio_setup(struct thread_data *td)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct fio_file *f;
|
struct fio_file *f;
|
||||||
|
|
||||||
/* we might be running in a daemonized FIO instance where standard
|
/*
|
||||||
* input and output were closed and fds 0, 1, and 2 are reused
|
* If we're running in a daemonized FIO instance, it's possible
|
||||||
* for something important by FIO. We can't ensure we won't print
|
* fd 1/2 were re-used for something important by FIO. Newer fio
|
||||||
* anything (and so will our dependencies, e.g. DPDK), so abort early.
|
* versions are careful to redirect those to /dev/null, but if we're
|
||||||
* (is_backend is an fio global variable)
|
* not, we'll abort early, so we don't accidentally write messages to
|
||||||
|
* an important file, etc.
|
||||||
*/
|
*/
|
||||||
if (is_backend) {
|
if (is_backend && !fio_redirected_to_dev_null()) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
"SPDK FIO plugin won't work with daemonized FIO server.");
|
"SPDK FIO plugin is in daemon mode, but stdout/stderr "
|
||||||
|
"aren't redirected to /dev/null. Aborting.");
|
||||||
fio_server_text_output(FIO_LOG_ERR, buf, sizeof(buf));
|
fio_server_text_output(FIO_LOG_ERR, buf, sizeof(buf));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -501,6 +501,27 @@ static void parse_pract_flag(int pract)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fio_redirected_to_dev_null(void)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX] = "";
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
ret = readlink("/proc/self/fd/1", path, sizeof(path));
|
||||||
|
|
||||||
|
if (ret == -1 || strcmp(path, "/dev/null") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = readlink("/proc/self/fd/2", path, sizeof(path));
|
||||||
|
|
||||||
|
if (ret == -1 || strcmp(path, "/dev/null") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called once at initialization. This is responsible for gathering the size of
|
/* Called once at initialization. This is responsible for gathering the size of
|
||||||
* each "file", which in our case are in the form
|
* each "file", which in our case are in the form
|
||||||
* 'key=value [key=value] ... ns=value'
|
* 'key=value [key=value] ... ns=value'
|
||||||
@ -519,16 +540,18 @@ static int spdk_fio_setup(struct thread_data *td)
|
|||||||
char *trid_info;
|
char *trid_info;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* we might be running in a daemonized FIO instance where standard
|
/*
|
||||||
* input and output were closed and fds 0, 1, and 2 are reused
|
* If we're running in a daemonized FIO instance, it's possible
|
||||||
* for something important by FIO. We can't ensure we won't print
|
* fd 1/2 were re-used for something important by FIO. Newer fio
|
||||||
* anything (and so will our dependencies, e.g. DPDK), so abort early.
|
* versions are careful to redirect those to /dev/null, but if we're
|
||||||
* (is_backend is an fio global variable)
|
* not, we'll abort early, so we don't accidentally write messages to
|
||||||
|
* an important file, etc.
|
||||||
*/
|
*/
|
||||||
if (is_backend) {
|
if (is_backend && !fio_redirected_to_dev_null()) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
"SPDK FIO plugin won't work with daemonized FIO server.");
|
"SPDK FIO plugin is in daemon mode, but stdout/stderr "
|
||||||
|
"aren't redirected to /dev/null. Aborting.");
|
||||||
fio_server_text_output(FIO_LOG_ERR, buf, sizeof(buf));
|
fio_server_text_output(FIO_LOG_ERR, buf, sizeof(buf));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user