1 /* 2 * Copyright (c) 2017 Cyril Hrubis <chrubis (at) suse.cz> 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* 19 * Runs several threads that fills up the filesystem repeatedly. 20 */ 21 22 #define _GNU_SOURCE 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <pthread.h> 29 #include "tst_safe_pthread.h" 30 #include "tst_test.h" 31 32 #define MNTPOINT "mntpoint" 33 34 static volatile int run; 35 static unsigned int nthreads; 36 static int enospc_cnt; 37 static struct worker *workers; 38 39 struct worker { 40 char dir[PATH_MAX]; 41 }; 42 43 static void *worker(void *p) 44 { 45 struct worker *w = p; 46 DIR *d; 47 struct dirent *ent; 48 char file[PATH_MAX]; 49 50 while (run) { 51 tst_fill_fs(w->dir, 0); 52 53 tst_atomic_inc(&enospc_cnt); 54 55 d = SAFE_OPENDIR(w->dir); 56 while ((ent = SAFE_READDIR(d))) { 57 58 if (!strcmp(ent->d_name, ".") || 59 !strcmp(ent->d_name, "..")) 60 continue; 61 62 snprintf(file, sizeof(file), "%s/%s", 63 w->dir, ent->d_name); 64 65 tst_res(TINFO, "Unlinking %s", file); 66 67 SAFE_UNLINK(file); 68 break; 69 } 70 SAFE_CLOSEDIR(d); 71 } 72 73 return NULL; 74 } 75 76 static void testrun(void) 77 { 78 pthread_t threads[nthreads]; 79 unsigned int i, ms; 80 81 run = 1; 82 for (i = 0; i < nthreads; i++) 83 SAFE_PTHREAD_CREATE(&threads[i], NULL, worker, &workers[i]); 84 85 for (ms = 0; ; ms++) { 86 usleep(1000); 87 88 if (ms >= 1000 && enospc_cnt) 89 break; 90 91 if (enospc_cnt > 100) 92 break; 93 } 94 95 run = 0; 96 for (i = 0; i < nthreads; i++) 97 SAFE_PTHREAD_JOIN(threads[i], NULL); 98 99 tst_res(TPASS, "Got %i ENOSPC runtime %ims", enospc_cnt, ms); 100 } 101 102 static void setup(void) 103 { 104 unsigned int i; 105 106 nthreads = tst_ncpus_conf() + 2; 107 workers = SAFE_MALLOC(sizeof(struct worker) * nthreads); 108 109 for (i = 0; i < nthreads; i++) { 110 snprintf(workers[i].dir, sizeof(workers[i].dir), 111 MNTPOINT "/thread%i", i + 1); 112 SAFE_MKDIR(workers[i].dir, 0700); 113 } 114 115 tst_res(TINFO, "Running %i writer threads", nthreads); 116 } 117 118 static void cleanup(void) 119 { 120 free(workers); 121 } 122 123 static struct tst_test test = { 124 .needs_root = 1, 125 .needs_tmpdir = 1, 126 .mount_device = 1, 127 .mntpoint = MNTPOINT, 128 .all_filesystems = 1, 129 .setup = setup, 130 .cleanup = cleanup, 131 .test_all = testrun, 132 }; 133