| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz> |
| */ |
| |
| /* |
| * 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, |
| .mount_device = 1, |
| .mntpoint = MNTPOINT, |
| .all_filesystems = 1, |
| .setup = setup, |
| .cleanup = cleanup, |
| .test_all = testrun, |
| }; |