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 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*/ 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*/ 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*/ 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 */ 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 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 */ 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 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