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