• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 Red Hat Inc. All Rights Reserved.
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 as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it would 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  * Author: Xiong Zhou <xzhou@redhat.com>
18  *
19  * This is testing OFD locks racing with POSIX locks:
20  *
21  *	OFD read  lock   vs   OFD   write lock
22  *	OFD read  lock   vs   POSIX write lock
23  *	OFD write lock   vs   POSIX write lock
24  *	OFD write lock   vs   POSIX read  lock
25  *	OFD write lock   vs   OFD   write lock
26  *
27  *	OFD   r/w locks vs POSIX write locks
28  *	OFD   r/w locks vs POSIX read locks
29  *
30  * For example:
31  *
32  *	Init an file with preset values.
33  *
34  *	Threads acquire OFD READ  locks to read  a 4k section start from 0;
35  *		checking data read back, there should not be any surprise
36  *		values and data should be consistent in a 1k block.
37  *
38  *	Threads acquire OFD WRITE locks to write a 4k section start from 1k,
39  *		writing different values in different threads.
40  *
41  *	Check file data after racing, there should not be any surprise values
42  *		and data should be consistent in a 1k block.
43  *
44  *
45  */
46 
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <unistd.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <fcntl.h>
53 #include <pthread.h>
54 #include <sched.h>
55 #include <errno.h>
56 
57 #include "lapi/fcntl.h"
58 #include "tst_safe_pthread.h"
59 #include "tst_test.h"
60 #include "fcntl_common.h"
61 
62 static int thread_cnt;
63 static int fail_flag = 0;
64 static volatile int loop_flag = 1;
65 static const int max_thread_cnt = 32;
66 static const char fname[] = "tst_ofd_posix_locks";
67 static const long write_size = 4096;
68 static pthread_barrier_t barrier;
69 
70 struct param {
71 	long offset;
72 	long length;
73 	long cnt;
74 };
75 
setup(void)76 static void setup(void)
77 {
78 	thread_cnt = tst_ncpus_conf() * 3;
79 	if (thread_cnt > max_thread_cnt)
80 		thread_cnt = max_thread_cnt;
81 }
82 
83 /* OFD write lock writing data*/
fn_ofd_w(void * arg)84 static void *fn_ofd_w(void *arg)
85 {
86 	struct param *pa = arg;
87 	unsigned char buf[pa->length];
88 	int fd = SAFE_OPEN(fname, O_RDWR);
89 	long wt = pa->cnt;
90 
91 	struct flock64 lck = {
92 		.l_whence = SEEK_SET,
93 		.l_start  = pa->offset,
94 		.l_len    = pa->length,
95 		.l_pid    = 0,
96 	};
97 
98 	while (loop_flag) {
99 
100 		memset(buf, wt, pa->length);
101 
102 		lck.l_type = F_WRLCK;
103 		my_fcntl(fd, F_OFD_SETLKW, &lck);
104 
105 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
106 		SAFE_WRITE(1, fd, buf, pa->length);
107 
108 		lck.l_type = F_UNLCK;
109 		my_fcntl(fd, F_OFD_SETLKW, &lck);
110 
111 		wt++;
112 		if (wt >= 255)
113 			wt = pa->cnt;
114 
115 		sched_yield();
116 	}
117 
118 	pthread_barrier_wait(&barrier);
119 	SAFE_CLOSE(fd);
120 	return NULL;
121 }
122 
123 /* POSIX write lock writing data*/
fn_posix_w(void * arg)124 static void *fn_posix_w(void *arg)
125 {
126 	struct param *pa = arg;
127 	unsigned char buf[pa->length];
128 	int fd = SAFE_OPEN(fname, O_RDWR);
129 	long wt = pa->cnt;
130 
131 	struct flock lck = {
132 		.l_whence = SEEK_SET,
133 		.l_start  = pa->offset,
134 		.l_len    = pa->length,
135 	};
136 
137 	while (loop_flag) {
138 
139 		memset(buf, wt, pa->length);
140 
141 		lck.l_type = F_WRLCK;
142 		SAFE_FCNTL(fd, F_SETLKW, &lck);
143 
144 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
145 		SAFE_WRITE(1, fd, buf, pa->length);
146 
147 		lck.l_type = F_UNLCK;
148 		SAFE_FCNTL(fd, F_SETLKW, &lck);
149 
150 		wt++;
151 		if (wt >= 255)
152 			wt = pa->cnt;
153 
154 		sched_yield();
155 	}
156 
157 	pthread_barrier_wait(&barrier);
158 	SAFE_CLOSE(fd);
159 	return NULL;
160 }
161 
162 /* OFD read lock reading data*/
fn_ofd_r(void * arg)163 static void *fn_ofd_r(void *arg)
164 {
165 	struct param *pa = arg;
166 	unsigned char buf[pa->length];
167 	int i;
168 	int fd = SAFE_OPEN(fname, O_RDWR);
169 
170 	struct flock64 lck = {
171 		.l_whence = SEEK_SET,
172 		.l_start  = pa->offset,
173 		.l_len    = pa->length,
174 		.l_pid    = 0,
175 	};
176 
177 	while (loop_flag) {
178 
179 		memset(buf, 0, pa->length);
180 
181 		lck.l_type = F_RDLCK;
182 		my_fcntl(fd, F_OFD_SETLKW, &lck);
183 
184 		/* rlock acquired */
185 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
186 		SAFE_READ(1, fd, buf, pa->length);
187 
188 		/* Verifying data read */
189 		for (i = 0; i < pa->length; i++) {
190 
191 			if (buf[i] < 1 || buf[i] > 254) {
192 
193 				tst_res(TFAIL, "Unexpected data "
194 					"offset %ld value %d",
195 					pa->offset + i, buf[i]);
196 				fail_flag = 1;
197 				break;
198 			}
199 
200 			int j = (i / (pa->length/4)) * pa->length/4;
201 
202 			if (buf[i] != buf[j]) {
203 
204 				tst_res(TFAIL, "Unexpected data "
205 					"offset %ld value %d",
206 					pa->offset + i, buf[i]);
207 				fail_flag = 1;
208 				break;
209 			}
210 		}
211 
212 		lck.l_type = F_UNLCK;
213 		my_fcntl(fd, F_OFD_SETLK, &lck);
214 
215 		sched_yield();
216 	}
217 
218 	pthread_barrier_wait(&barrier);
219 	SAFE_CLOSE(fd);
220 	return NULL;
221 }
222 
223 /* POSIX read lock reading data */
fn_posix_r(void * arg)224 static void *fn_posix_r(void *arg)
225 {
226 	struct param *pa = arg;
227 	unsigned char buf[pa->length];
228 	int i;
229 	int fd = SAFE_OPEN(fname, O_RDWR);
230 
231 	struct flock lck = {
232 		.l_whence = SEEK_SET,
233 		.l_start  = pa->offset,
234 		.l_len    = pa->length,
235 	};
236 
237 	while (loop_flag) {
238 
239 		memset(buf, 0, pa->length);
240 
241 		lck.l_type = F_RDLCK;
242 		SAFE_FCNTL(fd, F_SETLKW, &lck);
243 
244 		/* rlock acquired */
245 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
246 		SAFE_READ(1, fd, buf, pa->length);
247 
248 		/* Verifying data read */
249 		for (i = 0; i < pa->length; i++) {
250 
251 			if (buf[i] < 1 || buf[i] > 254) {
252 
253 				tst_res(TFAIL, "Unexpected data "
254 					"offset %ld value %d",
255 					pa->offset + i, buf[i]);
256 				fail_flag = 1;
257 				break;
258 			}
259 
260 			int j = (i / (pa->length/4)) * pa->length/4;
261 
262 			if (buf[i] != buf[j]) {
263 
264 				tst_res(TFAIL, "Unexpected data "
265 					"offset %ld value %d",
266 					pa->offset + i, buf[i]);
267 				fail_flag = 1;
268 				break;
269 			}
270 		}
271 
272 		lck.l_type = F_UNLCK;
273 		SAFE_FCNTL(fd, F_SETLK, &lck);
274 
275 		sched_yield();
276 	}
277 
278 	pthread_barrier_wait(&barrier);
279 	SAFE_CLOSE(fd);
280 	return NULL;
281 }
282 
fn_dummy(void * arg)283 static void *fn_dummy(void *arg)
284 {
285 	arg = NULL;
286 
287 	pthread_barrier_wait(&barrier);
288 	return arg;
289 }
290 
291 /* Test different functions and verify data */
test_fn(void * f0 (void *),void * f1 (void *),void * f2 (void *),const char * msg)292 static void test_fn(void *f0(void *), void *f1(void *),
293 		    void *f2(void *), const char *msg)
294 {
295 	int i, k, fd;
296 	pthread_t id0[thread_cnt];
297 	pthread_t id1[thread_cnt];
298 	pthread_t id2[thread_cnt];
299 	struct param p0[thread_cnt];
300 	struct param p1[thread_cnt];
301 	struct param p2[thread_cnt];
302 	unsigned char buf[write_size];
303 
304 	tst_res(TINFO, "%s", msg);
305 
306 	if (tst_fill_file(fname, 1, write_size, thread_cnt + 1))
307 		tst_brk(TBROK, "Failed to create tst file");
308 
309 	if (pthread_barrier_init(&barrier, NULL, thread_cnt*3) != 0)
310 		tst_brk(TBROK, "Failed to init pthread barrier");
311 
312 	for (i = 0; i < thread_cnt; i++) {
313 
314 		p0[i].offset = i * write_size;
315 		p0[i].length = write_size;
316 		p0[i].cnt = i + 2;
317 
318 		p1[i].offset = i * write_size + write_size / 4;
319 		p1[i].length = write_size;
320 		p1[i].cnt = i + 2;
321 
322 		p2[i].offset = i * write_size + write_size / 2;
323 		p2[i].length = write_size;
324 		p2[i].cnt = i + 2;
325 	}
326 
327 	fail_flag = 0;
328 	loop_flag = 1;
329 
330 	for (i = 0; i < thread_cnt; i++) {
331 
332 		SAFE_PTHREAD_CREATE(id0 + i, NULL, f0, (void *)&p0[i]);
333 		SAFE_PTHREAD_CREATE(id1 + i, NULL, f1, (void *)&p1[i]);
334 		SAFE_PTHREAD_CREATE(id2 + i, NULL, f2, (void *)&p2[i]);
335 	}
336 
337 	sleep(1);
338 	loop_flag = 0;
339 
340 	for (i = 0; i < thread_cnt; i++) {
341 
342 		SAFE_PTHREAD_JOIN(id0[i], NULL);
343 		SAFE_PTHREAD_JOIN(id1[i], NULL);
344 		SAFE_PTHREAD_JOIN(id2[i], NULL);
345 	}
346 
347 	fd = SAFE_OPEN(fname, O_RDONLY);
348 
349 	for (i = 0; i < thread_cnt * 4; i++) {
350 
351 		SAFE_READ(1, fd, buf, write_size/4);
352 
353 		for (k = 0; k < write_size/4; k++) {
354 
355 			if (buf[k] < 2 || buf[k] > 254) {
356 
357 				if (i < 3 && buf[k] == 1)
358 					continue;
359 				tst_res(TFAIL, "Unexpected data "
360 					"offset %ld value %d",
361 					i * write_size / 4 + k, buf[k]);
362 				SAFE_CLOSE(fd);
363 				return;
364 			}
365 		}
366 
367 		for (k = 1; k < write_size/4; k++) {
368 
369 			if (buf[k] != buf[0]) {
370 				tst_res(TFAIL, "Unexpected block read");
371 				SAFE_CLOSE(fd);
372 				return;
373 			}
374 		}
375 	}
376 
377 	if (pthread_barrier_destroy(&barrier) != 0)
378 		tst_brk(TBROK, "Failed to destroy pthread barrier");
379 
380 	SAFE_CLOSE(fd);
381 	if (fail_flag == 0)
382 		tst_res(TPASS, "Access between threads synchronized");
383 }
384 
385 static struct tcase {
386 	void *(*fn0)(void *);
387 	void *(*fn1)(void *);
388 	void *(*fn2)(void *);
389 	const char *desc;
390 } tcases[] = {
391 	{fn_ofd_r, fn_ofd_w, fn_dummy, "OFD read lock vs OFD write lock"},
392 	{fn_ofd_w, fn_posix_w, fn_dummy, "OFD write lock vs POSIX write lock"},
393 	{fn_ofd_r, fn_posix_w, fn_dummy, "OFD read lock vs POSIX write lock"},
394 	{fn_ofd_w, fn_posix_r, fn_dummy, "OFD write lock vs POSIX read lock"},
395 	{fn_ofd_w, fn_ofd_w, fn_dummy, "OFD write lock vs OFD write lock"},
396 	{fn_ofd_r, fn_ofd_w, fn_posix_w, "OFD r/w lock vs POSIX write lock"},
397 	{fn_ofd_r, fn_ofd_w, fn_posix_r, "OFD r/w lock vs POSIX read lock"},
398 };
399 
tests(unsigned int i)400 static void tests(unsigned int i)
401 {
402 	test_fn(tcases[i].fn0, tcases[i].fn1, tcases[i].fn2, tcases[i].desc);
403 }
404 
405 static struct tst_test test = {
406 	.min_kver = "3.15",
407 	.needs_tmpdir = 1,
408 	.test = tests,
409 	.tcnt = ARRAY_SIZE(tcases),
410 	.setup = setup
411 };
412