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 (at) 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 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*/ 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*/ 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*/ 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 */ 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 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 */ 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 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