From 9c2e8a77c1b6fe9b7b684eb10ea205078647f904 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 28 Sep 2020 23:30:44 +0900 Subject: [PATCH] executor/linux: report large files when exiting with ENOSPC error There are reports which terminated due to ENOSPC error, but it seems that all temporary files are deleted after the test. Let's check from /proc/*/fd/* side in case somebody is using large temporary files created by open(O_TMPFILE). --- executor/executor.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/executor/executor.cc b/executor/executor.cc index 9473b871f588..21b4783b5f27 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -1478,6 +1478,42 @@ void setup_features(char** enable, int n) } } +#if GOOS_linux +#include +#include + +static int nftw_callback(const char* fpath, const struct stat* sbuf, int tflag, struct FTW* ftwbuf) +{ + static char buffer[4096] = {}; + static struct stat sbuf2 = {}; + + if (S_ISLNK(sbuf->st_mode) && strstr(fpath, "/fd/") && !stat(fpath, &sbuf2) && + (unsigned long long)sbuf2.st_blocks >= 1048576ULL / 512) + fprintf(stderr, "%10llu %s\n", (unsigned long long)sbuf2.st_size, + readlink(fpath, buffer, sizeof(buffer) - 1) > 0 ? buffer : fpath); + return 0; +} +#endif + +static void check_large_files(int err) +{ +#if GOOS_linux + char buffer[4096] = {}; + struct statfs sbuf = {}; + + if (err != ENOSPC) + return; + fprintf(stderr, "Current directory is %s\n", getcwd(buffer, sizeof(buffer) - 1)); + statfs(".", &sbuf); + fprintf(stderr, " Free blocks: %llu/%llu\n", (unsigned long long)sbuf.f_bfree, (unsigned long long)sbuf.f_blocks); + fprintf(stderr, " Block size: %llu\n", (unsigned long long)sbuf.f_bsize); + fprintf(stderr, " Filesystem type: %lx\n", (unsigned long)sbuf.f_type); + fprintf(stderr, " Free inodes: %llu/%llu\n", (unsigned long long)sbuf.f_ffree, (unsigned long long)sbuf.f_files); + fprintf(stderr, "Scanning large files from /proc/\052/fd/\052\n"); + nftw("/proc/", nftw_callback, 512, FTW_DEPTH | FTW_PHYS | FTW_MOUNT); +#endif +} + void fail(const char* msg, ...) { int e = errno; @@ -1486,6 +1522,7 @@ void fail(const char* msg, ...) vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, " (errno %d)\n", e); + check_large_files(e); // fail()'s are often used during the validation of kernel reactions to queries // that were issued by pseudo syscalls implementations. As fault injection may @@ -1511,6 +1548,7 @@ void exitf(const char* msg, ...) vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, " (errno %d)\n", e); + check_large_files(e); doexit(0); }