/* * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz> * * 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, see <http://www.gnu.org/licenses/>. */ /* * Runs several threads that fills up the filesystem repeatedly. */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <pthread.h> #include "tst_safe_pthread.h" #include "tst_test.h" #define MNTPOINT "mntpoint" static volatile int run; static unsigned int nthreads; static int enospc_cnt; static struct worker *workers; struct worker { char dir[PATH_MAX]; }; static void *worker(void *p) { struct worker *w = p; DIR *d; struct dirent *ent; char file[PATH_MAX]; while (run) { tst_fill_fs(w->dir, 0); tst_atomic_inc(&enospc_cnt); d = SAFE_OPENDIR(w->dir); while ((ent = SAFE_READDIR(d))) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; snprintf(file, sizeof(file), "%s/%s", w->dir, ent->d_name); tst_res(TINFO, "Unlinking %s", file); SAFE_UNLINK(file); break; } SAFE_CLOSEDIR(d); } return NULL; } static void testrun(void) { pthread_t threads[nthreads]; unsigned int i, ms; run = 1; for (i = 0; i < nthreads; i++) SAFE_PTHREAD_CREATE(&threads[i], NULL, worker, &workers[i]); for (ms = 0; ; ms++) { usleep(1000); if (ms >= 1000 && enospc_cnt) break; if (enospc_cnt > 100) break; } run = 0; for (i = 0; i < nthreads; i++) SAFE_PTHREAD_JOIN(threads[i], NULL); tst_res(TPASS, "Got %i ENOSPC runtime %ims", enospc_cnt, ms); } static void setup(void) { unsigned int i; nthreads = tst_ncpus_conf() + 2; workers = SAFE_MALLOC(sizeof(struct worker) * nthreads); for (i = 0; i < nthreads; i++) { snprintf(workers[i].dir, sizeof(workers[i].dir), MNTPOINT "/thread%i", i + 1); SAFE_MKDIR(workers[i].dir, 0700); } tst_res(TINFO, "Running %i writer threads", nthreads); } static void cleanup(void) { free(workers); } static struct tst_test test = { .needs_root = 1, .needs_tmpdir = 1, .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, .setup = setup, .cleanup = cleanup, .test_all = testrun, };