1 /*
2 * Copyright (c) 2017 Cyril Hrubis <chrubis@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
worker(void * p)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
testrun(void)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
setup(void)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
cleanup(void)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