1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. 4f08c3bdfSopenharmony_ci * Author: Alexey Kodanev <alexey.kodanev@oracle.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci#include <sys/types.h> 8f08c3bdfSopenharmony_ci#include <sys/stat.h> 9f08c3bdfSopenharmony_ci#include <unistd.h> 10f08c3bdfSopenharmony_ci#include <pthread.h> 11f08c3bdfSopenharmony_ci#include <sched.h> 12f08c3bdfSopenharmony_ci 13f08c3bdfSopenharmony_ci#include "fcntl_common.h" 14f08c3bdfSopenharmony_ci#include "tst_safe_pthread.h" 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_cistatic int thread_cnt; 17f08c3bdfSopenharmony_cistatic const int max_thread_cnt = 32; 18f08c3bdfSopenharmony_cistatic const char fname[] = "tst_ofd_locks"; 19f08c3bdfSopenharmony_ciconst int writes_num = 100; 20f08c3bdfSopenharmony_ciconst int write_size = 4096; 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_cistatic void setup(void) 23f08c3bdfSopenharmony_ci{ 24f08c3bdfSopenharmony_ci thread_cnt = tst_ncpus_conf() * 3; 25f08c3bdfSopenharmony_ci if (thread_cnt > max_thread_cnt) 26f08c3bdfSopenharmony_ci thread_cnt = max_thread_cnt; 27f08c3bdfSopenharmony_ci} 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_cistatic void spawn_threads(pthread_t *id, void *(*thread_fn)(void *)) 30f08c3bdfSopenharmony_ci{ 31f08c3bdfSopenharmony_ci intptr_t i; 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_ci tst_res(TINFO, "spawning '%d' threads", thread_cnt); 34f08c3bdfSopenharmony_ci for (i = 0; i < thread_cnt; ++i) 35f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(id + i, NULL, thread_fn, (void *)i); 36f08c3bdfSopenharmony_ci} 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic void wait_threads(pthread_t *id) 39f08c3bdfSopenharmony_ci{ 40f08c3bdfSopenharmony_ci int i; 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci tst_res(TINFO, "waiting for '%d' threads", thread_cnt); 43f08c3bdfSopenharmony_ci for (i = 0; i < thread_cnt; ++i) 44f08c3bdfSopenharmony_ci SAFE_PTHREAD_JOIN(id[i], NULL); 45f08c3bdfSopenharmony_ci} 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_civoid *thread_fn_01(void *arg) 48f08c3bdfSopenharmony_ci{ 49f08c3bdfSopenharmony_ci int i; 50f08c3bdfSopenharmony_ci unsigned char buf[write_size]; 51f08c3bdfSopenharmony_ci int fd = SAFE_OPEN(fname, O_RDWR); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci memset(buf, (intptr_t)arg, write_size); 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci struct flock lck = { 56f08c3bdfSopenharmony_ci .l_whence = SEEK_SET, 57f08c3bdfSopenharmony_ci .l_start = 0, 58f08c3bdfSopenharmony_ci .l_len = 1, 59f08c3bdfSopenharmony_ci }; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci for (i = 0; i < writes_num; ++i) { 62f08c3bdfSopenharmony_ci lck.l_type = F_WRLCK; 63f08c3bdfSopenharmony_ci FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_ci SAFE_LSEEK(fd, 0, SEEK_END); 66f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, write_size); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci lck.l_type = F_UNLCK; 69f08c3bdfSopenharmony_ci FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci sched_yield(); 72f08c3bdfSopenharmony_ci } 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci return NULL; 77f08c3bdfSopenharmony_ci} 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_cistatic void test01(void) 80f08c3bdfSopenharmony_ci{ 81f08c3bdfSopenharmony_ci intptr_t i; 82f08c3bdfSopenharmony_ci int k; 83f08c3bdfSopenharmony_ci pthread_t id[thread_cnt]; 84f08c3bdfSopenharmony_ci int res[thread_cnt]; 85f08c3bdfSopenharmony_ci unsigned char buf[write_size]; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci tst_res(TINFO, "write to a file inside threads with OFD locks"); 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci int fd = SAFE_OPEN(fname, O_CREAT | O_TRUNC | O_RDWR, 0600); 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci memset(res, 0, sizeof(res)); 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci spawn_threads(id, thread_fn_01); 94f08c3bdfSopenharmony_ci wait_threads(id); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci tst_res(TINFO, "verifying file's data"); 97f08c3bdfSopenharmony_ci SAFE_LSEEK(fd, 0, SEEK_SET); 98f08c3bdfSopenharmony_ci for (i = 0; i < writes_num * thread_cnt; ++i) { 99f08c3bdfSopenharmony_ci SAFE_READ(1, fd, buf, write_size); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci if (buf[0] >= thread_cnt) { 102f08c3bdfSopenharmony_ci tst_res(TFAIL, "unexpected data read"); 103f08c3bdfSopenharmony_ci return; 104f08c3bdfSopenharmony_ci } 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci ++res[buf[0]]; 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci for (k = 1; k < write_size; ++k) { 109f08c3bdfSopenharmony_ci if (buf[0] != buf[k]) { 110f08c3bdfSopenharmony_ci tst_res(TFAIL, "unexpected data read"); 111f08c3bdfSopenharmony_ci return; 112f08c3bdfSopenharmony_ci } 113f08c3bdfSopenharmony_ci } 114f08c3bdfSopenharmony_ci } 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci for (i = 0; i < thread_cnt; ++i) { 117f08c3bdfSopenharmony_ci if (res[i] != writes_num) { 118f08c3bdfSopenharmony_ci tst_res(TFAIL, "corrupted data found"); 119f08c3bdfSopenharmony_ci return; 120f08c3bdfSopenharmony_ci } 121f08c3bdfSopenharmony_ci } 122f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci tst_res(TPASS, "OFD locks synchronized access between threads"); 125f08c3bdfSopenharmony_ci} 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_cistatic struct tst_test test = { 128f08c3bdfSopenharmony_ci .min_kver = "3.15.0", 129f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 130f08c3bdfSopenharmony_ci .test_all = test01, 131f08c3bdfSopenharmony_ci .setup = setup 132f08c3bdfSopenharmony_ci}; 133