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