1 /*
2  * Copyright (C) 2013-2021 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (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, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * This code is a complete clean re-write of the stress tool by
19  * Colin Ian King <colin.king@canonical.com> and attempts to be
20  * backwardly compatible with the stress tool by Amos Waterland
21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
22  * functionality.
23  *
24  */
25 #include "stress-ng.h"
26 
27 static const stress_help_t help[] = {
28 	{ NULL,	"inode-flags N",	"start N workers exercising various inode flags" },
29 	{ NULL,	"inode-flags-ops N",	"stop inode-flags workers after N bogo operations" },
30 	{ NULL,	NULL,			NULL }
31 };
32 
33 #if defined(HAVE_LIB_PTHREAD) && \
34     defined(HAVE_LIBGEN_H) && \
35     defined(FS_IOC_GETFLAGS) && \
36     defined(FS_IOC_SETFLAGS) && \
37     defined(FS_IOC_SETFLAGS) && \
38     defined(O_DIRECTORY)
39 
40 #define MAX_INODE_FLAG_THREADS		(4)
41 
42 typedef struct {
43 	int dir_fd;
44 	int file_fd;
45 } stress_data_t;
46 
47 static volatile bool keep_running;
48 static sigset_t set;
49 static shim_pthread_spinlock_t spinlock;
50 
51 /*
52  *  stress_inode_flags_ioctl()
53  *	try and toggle an inode flag on/off
54  */
stress_inode_flags_ioctl(const stress_args_t * args,const int fd,const int flag)55 static void stress_inode_flags_ioctl(
56 	const stress_args_t *args,
57 	const int fd,
58 	const int flag)
59 {
60 	int ret, attr;
61 
62 	if (!(keep_running || keep_stressing(args)))
63 		return;
64 
65 	ret = ioctl(fd, FS_IOC_GETFLAGS, &attr);
66 	if (ret != 0)
67 		return;
68 
69 	attr |= flag;
70 	ret = ioctl(fd, FS_IOC_SETFLAGS, &attr);
71 	(void)ret;
72 
73 	attr &= ~flag;
74 	ret = ioctl(fd, FS_IOC_SETFLAGS, &attr);
75 	(void)ret;
76 }
77 
78 /*
79  *  stress_inode_flags_ioctl_sane()
80  *	set flags to a sane state so that file can be removed
81  */
stress_inode_flags_ioctl_sane(const int fd)82 static inline void stress_inode_flags_ioctl_sane(const int fd)
83 {
84 	int ret;
85 	const int flag = 0;
86 
87 	ret = ioctl(fd, FS_IOC_SETFLAGS, &flag);
88 	(void)ret;
89 }
90 
91 /*
92  *  stress_inode_flags_stressor()
93  *	exercise inode flags, see man ioctl_flags for
94  *	more details of these flags. Some are never going
95  *	to be implemented and some are just relevant to
96  *	specific file systems. We just want to try and
97  *	toggle these on and off to see if they break rather
98  *	than fail.
99  */
stress_inode_flags_stressor(const stress_args_t * args,stress_data_t * data)100 static int stress_inode_flags_stressor(
101 	const stress_args_t *args,
102 	stress_data_t *data)
103 {
104 	while (keep_running && keep_stressing(args)) {
105 		int ret;
106 
107 		stress_inode_flags_ioctl(args, data->dir_fd, 0);
108 #if defined(FS_DIRSYNC_FL)
109 		stress_inode_flags_ioctl(args, data->dir_fd, FS_DIRSYNC_FL);
110 #endif
111 #if defined(FS_PROJINHERIT_FL)
112 		stress_inode_flags_ioctl(args, data->dir_fd, FS_PROJINHERIT_FL);
113 #endif
114 #if defined(FS_SYNC_FL)
115 		stress_inode_flags_ioctl(args, data->dir_fd, FS_SYNC_FL);
116 #endif
117 #if defined(FS_TOPDIR_FL)
118 		stress_inode_flags_ioctl(args, data->dir_fd, FS_TOPDIR_FL);
119 #endif
120 #if defined(FS_APPEND_LF)
121 		stress_inode_flags_ioctl(args, data->file_fd, FS_APPEND_FL);
122 #endif
123 #if defined(FS_COMPR_FL)
124 		stress_inode_flags_ioctl(args, data->file_fd, FS_COMPR_FL);
125 #endif
126 #if defined(FS_IMMUTABLE_FL)
127 		stress_inode_flags_ioctl(args, data->file_fd, FS_IMMUTABLE_FL);
128 #endif
129 #if defined(FS_JOURNAL_DATA_FL)
130 		stress_inode_flags_ioctl(args, data->file_fd, FS_JOURNAL_DATA_FL);
131 #endif
132 #if defined(FS_NOCOW_FL)
133 		stress_inode_flags_ioctl(args, data->file_fd, FS_NOCOW_FL);
134 #endif
135 #if defined(FS_NODUMP_FL)
136 		stress_inode_flags_ioctl(args, data->file_fd, FS_NODUMP_FL);
137 #endif
138 #if defined(FS_NOTAIL_FL)
139 		stress_inode_flags_ioctl(args, data->file_fd, FS_NOTAIL_FL);
140 #endif
141 #if defined(FS_PROJINHERIT_FL)
142 		stress_inode_flags_ioctl(args, data->file_fd, FS_PROJINHERIT_FL);
143 #endif
144 #if defined(FS_SECRM_FL)
145 		stress_inode_flags_ioctl(args, data->file_fd, FS_SECRM_FL);
146 #endif
147 #if defined(FS_SYNC_FL)
148 		stress_inode_flags_ioctl(args, data->file_fd, FS_SYNC_FL);
149 #endif
150 #if defined(FS_UNRM_FL)
151 		stress_inode_flags_ioctl(args, data->file_fd, FS_UNRM_FL);
152 #endif
153 		ret = shim_pthread_spin_lock(&spinlock);
154 		if (!ret) {
155 			inc_counter(args);
156 			ret = shim_pthread_spin_unlock(&spinlock);
157 			(void)ret;
158 		}
159 		stress_inode_flags_ioctl_sane(data->file_fd);
160 	}
161 	stress_inode_flags_ioctl_sane(data->file_fd);
162 
163 	return 0;
164 }
165 
166 /*
167  *  stress_inode_flags()
168  *	exercise inode flags on a file
169  */
stress_inode_flags_thread(void * arg)170 static void *stress_inode_flags_thread(void *arg)
171 {
172 	static void *nowt = NULL;
173 	stress_pthread_args_t *pa = (stress_pthread_args_t *)arg;
174 
175 	/*
176 	 *  Block all signals, let controlling thread
177 	 *  handle these
178 	 */
179 	(void)sigprocmask(SIG_BLOCK, &set, NULL);
180 
181 	pa->pthread_ret = stress_inode_flags_stressor(pa->args, pa->data);
182 
183 	return &nowt;
184 }
185 
186 
187 /*
188  *  stress_inode_flags
189  *	stress reading all of /dev
190  */
stress_inode_flags(const stress_args_t * args)191 static int stress_inode_flags(const stress_args_t *args)
192 {
193 	size_t i;
194 	pthread_t pthreads[MAX_INODE_FLAG_THREADS];
195 	int rc, ret[MAX_INODE_FLAG_THREADS];
196 	stress_pthread_args_t pa[MAX_INODE_FLAG_THREADS];
197 	stress_data_t data;
198 	char tmp[PATH_MAX], file_name[PATH_MAX];
199 	char *dir_name;
200 
201 	rc = shim_pthread_spin_init(&spinlock, SHIM_PTHREAD_PROCESS_SHARED);
202 	if (rc) {
203 		pr_fail("%s: pthread_spin_init failed, errno = %d (%s)\n",
204 			args->name, rc, strerror(rc));
205 		return EXIT_FAILURE;
206 	}
207 
208 	rc = stress_temp_dir_mk_args(args);
209 	if (rc < 0)
210 		return exit_status(-rc);
211 	(void)stress_temp_filename_args(args,
212 		file_name, sizeof(file_name), stress_mwc32());
213 
214 	shim_strlcpy(tmp, file_name, sizeof(tmp));
215 	dir_name = dirname(tmp);
216 
217 	data.dir_fd = open(dir_name, O_RDONLY | O_DIRECTORY);
218 	if (data.dir_fd < 0) {
219 		pr_err("%s: cannot open %s: errno=%d (%s)\n",
220 			args->name, dir_name, errno, strerror(errno));
221 		rc = EXIT_NO_RESOURCE;
222 		goto tidy;
223 	}
224 	data.file_fd = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
225 	if (data.file_fd < 0) {
226 		pr_err("%s: cannot open %s: errno=%d (%s)\n",
227 			args->name, file_name, errno, strerror(errno));
228 		rc = EXIT_NO_RESOURCE;
229 		goto tidy_dir_fd;
230 	}
231 
232 	(void)memset(ret, 0, sizeof(ret));
233 	keep_running = true;
234 
235 	for (i = 0; i < MAX_INODE_FLAG_THREADS; i++) {
236 		pa[i].args = args;
237 		pa[i].data = (void *)&data;
238 		pa[i].pthread_ret = 0;
239 
240 		ret[i] = pthread_create(&pthreads[i], NULL,
241 				stress_inode_flags_thread, &pa[i]);
242 	}
243 
244 	stress_set_proc_state(args->name, STRESS_STATE_RUN);
245 
246 	do {
247 		stress_inode_flags_stressor(args, &data);
248 	} while (keep_stressing(args));
249 
250 	keep_running = false;
251 	rc = EXIT_SUCCESS;
252 
253 	for (i = 0; i < MAX_INODE_FLAG_THREADS; i++) {
254 		if (ret[i] == 0) {
255 			(void)pthread_join(pthreads[i], NULL);
256 			if (pa[i].pthread_ret < 0)
257 				rc = EXIT_FAILURE;
258 		}
259 	}
260 
261 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
262 	(void)close(data.file_fd);
263 tidy_dir_fd:
264 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
265 	(void)close(data.dir_fd);
266 tidy:
267 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
268 	(void)unlink(file_name);
269 	stress_temp_dir_rm_args(args);
270 	(void)shim_pthread_spin_destroy(&spinlock);
271 
272 	return rc;
273 }
274 
275 stressor_info_t stress_inode_flags_info = {
276 	.stressor = stress_inode_flags,
277 	.class = CLASS_OS | CLASS_FILESYSTEM,
278 	.help = help
279 };
280 #else
281 stressor_info_t stress_inode_flags_info = {
282 	.stressor = stress_not_implemented ,
283 	.class = CLASS_OS | CLASS_FILESYSTEM,
284 	.help = help
285 };
286 #endif
287