• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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