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