• 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 
61 static int thread_cnt;
62 static int fail_flag = 0;
63 static volatile int loop_flag = 1;
64 static const int max_thread_cnt = 32;
65 static const char fname[] = "tst_ofd_posix_locks";
66 static const long write_size = 4096;
67 static pthread_barrier_t barrier;
68 
69 struct param {
70 	long offset;
71 	long length;
72 	long cnt;
73 };
74 
setup(void)75 static void setup(void)
76 {
77 	thread_cnt = tst_ncpus_conf() * 3;
78 	if (thread_cnt > max_thread_cnt)
79 		thread_cnt = max_thread_cnt;
80 }
81 
82 /* OFD write lock writing data*/
fn_ofd_w(void * arg)83 static void *fn_ofd_w(void *arg)
84 {
85 	struct param *pa = arg;
86 	unsigned char buf[pa->length];
87 	int fd = SAFE_OPEN(fname, O_RDWR);
88 	long wt = pa->cnt;
89 
90 	struct flock64 lck = {
91 		.l_whence = SEEK_SET,
92 		.l_start  = pa->offset,
93 		.l_len    = pa->length,
94 		.l_pid    = 0,
95 	};
96 
97 	while (loop_flag) {
98 
99 		memset(buf, wt, pa->length);
100 
101 		lck.l_type = F_WRLCK;
102 		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
103 
104 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
105 		SAFE_WRITE(1, fd, buf, pa->length);
106 
107 		lck.l_type = F_UNLCK;
108 		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
109 
110 		wt++;
111 		if (wt >= 255)
112 			wt = pa->cnt;
113 
114 		sched_yield();
115 	}
116 
117 	pthread_barrier_wait(&barrier);
118 	SAFE_CLOSE(fd);
119 	return NULL;
120 }
121 
122 /* POSIX write lock writing data*/
fn_posix_w(void * arg)123 static void *fn_posix_w(void *arg)
124 {
125 	struct param *pa = arg;
126 	unsigned char buf[pa->length];
127 	int fd = SAFE_OPEN(fname, O_RDWR);
128 	long wt = pa->cnt;
129 
130 	struct flock64 lck = {
131 		.l_whence = SEEK_SET,
132 		.l_start  = pa->offset,
133 		.l_len    = pa->length,
134 	};
135 
136 	while (loop_flag) {
137 
138 		memset(buf, wt, pa->length);
139 
140 		lck.l_type = F_WRLCK;
141 		SAFE_FCNTL(fd, F_SETLKW, &lck);
142 
143 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
144 		SAFE_WRITE(1, fd, buf, pa->length);
145 
146 		lck.l_type = F_UNLCK;
147 		SAFE_FCNTL(fd, F_SETLKW, &lck);
148 
149 		wt++;
150 		if (wt >= 255)
151 			wt = pa->cnt;
152 
153 		sched_yield();
154 	}
155 
156 	pthread_barrier_wait(&barrier);
157 	SAFE_CLOSE(fd);
158 	return NULL;
159 }
160 
161 /* OFD read lock reading data*/
fn_ofd_r(void * arg)162 static void *fn_ofd_r(void *arg)
163 {
164 	struct param *pa = arg;
165 	unsigned char buf[pa->length];
166 	int i;
167 	int fd = SAFE_OPEN(fname, O_RDWR);
168 
169 	struct flock64 lck = {
170 		.l_whence = SEEK_SET,
171 		.l_start  = pa->offset,
172 		.l_len    = pa->length,
173 		.l_pid    = 0,
174 	};
175 
176 	while (loop_flag) {
177 
178 		memset(buf, 0, pa->length);
179 
180 		lck.l_type = F_RDLCK;
181 		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
182 
183 		/* rlock acquired */
184 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
185 		SAFE_READ(1, fd, buf, pa->length);
186 
187 		/* Verifying data read */
188 		for (i = 0; i < pa->length; i++) {
189 
190 			if (buf[i] < 1 || buf[i] > 254) {
191 
192 				tst_res(TFAIL, "Unexpected data "
193 					"offset %ld value %d",
194 					pa->offset + i, buf[i]);
195 				fail_flag = 1;
196 				break;
197 			}
198 
199 			int j = (i / (pa->length/4)) * pa->length/4;
200 
201 			if (buf[i] != buf[j]) {
202 
203 				tst_res(TFAIL, "Unexpected data "
204 					"offset %ld value %d",
205 					pa->offset + i, buf[i]);
206 				fail_flag = 1;
207 				break;
208 			}
209 		}
210 
211 		lck.l_type = F_UNLCK;
212 		SAFE_FCNTL(fd, F_OFD_SETLK, &lck);
213 
214 		sched_yield();
215 	}
216 
217 	pthread_barrier_wait(&barrier);
218 	SAFE_CLOSE(fd);
219 	return NULL;
220 }
221 
222 /* POSIX read lock reading data */
fn_posix_r(void * arg)223 static void *fn_posix_r(void *arg)
224 {
225 	struct param *pa = arg;
226 	unsigned char buf[pa->length];
227 	int i;
228 	int fd = SAFE_OPEN(fname, O_RDWR);
229 
230 	struct flock64 lck = {
231 		.l_whence = SEEK_SET,
232 		.l_start  = pa->offset,
233 		.l_len    = pa->length,
234 	};
235 
236 	while (loop_flag) {
237 
238 		memset(buf, 0, pa->length);
239 
240 		lck.l_type = F_RDLCK;
241 		SAFE_FCNTL(fd, F_SETLKW, &lck);
242 
243 		/* rlock acquired */
244 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
245 		SAFE_READ(1, fd, buf, pa->length);
246 
247 		/* Verifying data read */
248 		for (i = 0; i < pa->length; i++) {
249 
250 			if (buf[i] < 1 || buf[i] > 254) {
251 
252 				tst_res(TFAIL, "Unexpected data "
253 					"offset %ld value %d",
254 					pa->offset + i, buf[i]);
255 				fail_flag = 1;
256 				break;
257 			}
258 
259 			int j = (i / (pa->length/4)) * pa->length/4;
260 
261 			if (buf[i] != buf[j]) {
262 
263 				tst_res(TFAIL, "Unexpected data "
264 					"offset %ld value %d",
265 					pa->offset + i, buf[i]);
266 				fail_flag = 1;
267 				break;
268 			}
269 		}
270 
271 		lck.l_type = F_UNLCK;
272 		SAFE_FCNTL(fd, F_SETLK, &lck);
273 
274 		sched_yield();
275 	}
276 
277 	pthread_barrier_wait(&barrier);
278 	SAFE_CLOSE(fd);
279 	return NULL;
280 }
281 
fn_dummy(void * arg)282 static void *fn_dummy(void *arg)
283 {
284 	arg = NULL;
285 
286 	pthread_barrier_wait(&barrier);
287 	return arg;
288 }
289 
290 /* Test different functions and verify data */
test_fn(void * f0 (void *),void * f1 (void *),void * f2 (void *),const char * msg)291 static void test_fn(void *f0(void *), void *f1(void *),
292 		    void *f2(void *), const char *msg)
293 {
294 	int i, k, fd;
295 	pthread_t id0[thread_cnt];
296 	pthread_t id1[thread_cnt];
297 	pthread_t id2[thread_cnt];
298 	struct param p0[thread_cnt];
299 	struct param p1[thread_cnt];
300 	struct param p2[thread_cnt];
301 	unsigned char buf[write_size];
302 
303 	tst_res(TINFO, "%s", msg);
304 
305 	if (tst_fill_file(fname, 1, write_size, thread_cnt + 1))
306 		tst_brk(TBROK, "Failed to create tst file");
307 
308 	if (pthread_barrier_init(&barrier, NULL, thread_cnt*3) != 0)
309 		tst_brk(TBROK, "Failed to init pthread barrier");
310 
311 	for (i = 0; i < thread_cnt; i++) {
312 
313 		p0[i].offset = i * write_size;
314 		p0[i].length = write_size;
315 		p0[i].cnt = i + 2;
316 
317 		p1[i].offset = i * write_size + write_size / 4;
318 		p1[i].length = write_size;
319 		p1[i].cnt = i + 2;
320 
321 		p2[i].offset = i * write_size + write_size / 2;
322 		p2[i].length = write_size;
323 		p2[i].cnt = i + 2;
324 	}
325 
326 	fail_flag = 0;
327 	loop_flag = 1;
328 
329 	for (i = 0; i < thread_cnt; i++) {
330 
331 		SAFE_PTHREAD_CREATE(id0 + i, NULL, f0, (void *)&p0[i]);
332 		SAFE_PTHREAD_CREATE(id1 + i, NULL, f1, (void *)&p1[i]);
333 		SAFE_PTHREAD_CREATE(id2 + i, NULL, f2, (void *)&p2[i]);
334 	}
335 
336 	sleep(1);
337 	loop_flag = 0;
338 
339 	for (i = 0; i < thread_cnt; i++) {
340 
341 		SAFE_PTHREAD_JOIN(id0[i], NULL);
342 		SAFE_PTHREAD_JOIN(id1[i], NULL);
343 		SAFE_PTHREAD_JOIN(id2[i], NULL);
344 	}
345 
346 	fd = SAFE_OPEN(fname, O_RDONLY);
347 
348 	for (i = 0; i < thread_cnt * 4; i++) {
349 
350 		SAFE_READ(1, fd, buf, write_size/4);
351 
352 		for (k = 0; k < write_size/4; k++) {
353 
354 			if (buf[k] < 2 || buf[k] > 254) {
355 
356 				if (i < 3 && buf[k] == 1)
357 					continue;
358 				tst_res(TFAIL, "Unexpected data "
359 					"offset %ld value %d",
360 					i * write_size / 4 + k, buf[k]);
361 				SAFE_CLOSE(fd);
362 				return;
363 			}
364 		}
365 
366 		for (k = 1; k < write_size/4; k++) {
367 
368 			if (buf[k] != buf[0]) {
369 				tst_res(TFAIL, "Unexpected block read");
370 				SAFE_CLOSE(fd);
371 				return;
372 			}
373 		}
374 	}
375 
376 	if (pthread_barrier_destroy(&barrier) != 0)
377 		tst_brk(TBROK, "Failed to destroy pthread barrier");
378 
379 	SAFE_CLOSE(fd);
380 	if (fail_flag == 0)
381 		tst_res(TPASS, "Access between threads synchronized");
382 }
383 
384 static struct tcase {
385 	void *(*fn0)(void *);
386 	void *(*fn1)(void *);
387 	void *(*fn2)(void *);
388 	const char *desc;
389 } tcases[] = {
390 	{fn_ofd_r, fn_ofd_w, fn_dummy, "OFD read lock vs OFD write lock"},
391 	{fn_ofd_w, fn_posix_w, fn_dummy, "OFD write lock vs POSIX write lock"},
392 	{fn_ofd_r, fn_posix_w, fn_dummy, "OFD read lock vs POSIX write lock"},
393 	{fn_ofd_w, fn_posix_r, fn_dummy, "OFD write lock vs POSIX read lock"},
394 	{fn_ofd_w, fn_ofd_w, fn_dummy, "OFD write lock vs OFD write lock"},
395 	{fn_ofd_r, fn_ofd_w, fn_posix_w, "OFD r/w lock vs POSIX write lock"},
396 	{fn_ofd_r, fn_ofd_w, fn_posix_r, "OFD r/w lock vs POSIX read lock"},
397 };
398 
tests(unsigned int i)399 static void tests(unsigned int i)
400 {
401 	test_fn(tcases[i].fn0, tcases[i].fn1, tcases[i].fn2, tcases[i].desc);
402 }
403 
404 static struct tst_test test = {
405 	.min_kver = "3.15",
406 	.needs_tmpdir = 1,
407 	.test = tests,
408 	.tcnt = ARRAY_SIZE(tcases),
409 	.setup = setup
410 };
411