/pread_eexist_repro.c
Created Nov 9, 2016
| #define _GNU_SOURCE | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <pthread.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <linux/fs.h> | |
| #define SECTORSIZE 4096 | |
| #define NUM_EXTENTS 128 | |
| static pthread_barrier_t barrier; | |
| static int create_test_file(const char *path) | |
| { | |
| int fd; | |
| int ret; | |
| off_t off; | |
| long flags; | |
| fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); | |
| if (fd == -1) { | |
| perror("open"); | |
| return -1; | |
| } | |
| if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) { | |
| perror("ioctl"); | |
| close(fd); | |
| return -1; | |
| } | |
| flags |= FS_NOCOW_FL; | |
| if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) { | |
| perror("ioctl"); | |
| close(fd); | |
| return -1; | |
| } | |
| for (off = 0; off < 2 * SECTORSIZE * NUM_EXTENTS; off += SECTORSIZE * 2) { | |
| ret = fallocate(fd, 0, off, 2 * SECTORSIZE); | |
| if (ret == -1) { | |
| perror("fallocate"); | |
| close(fd); | |
| return -1; | |
| } | |
| } | |
| close(fd); | |
| return 0; | |
| } | |
| struct race_thread_data { | |
| int fd; | |
| int thread_id; | |
| }; | |
| static void *race_thread(void *arg) | |
| { | |
| struct race_thread_data *data = arg; | |
| off_t off; | |
| ssize_t ret; | |
| void *buf; | |
| if ((errno = posix_memalign(&buf, SECTORSIZE, SECTORSIZE))) { | |
| perror("malloc"); | |
| return NULL; | |
| } | |
| memset(buf, 0, SECTORSIZE); | |
| for (off = (NUM_EXTENTS - 2) * SECTORSIZE; off >= 0; off -= SECTORSIZE * 2) { | |
| pthread_barrier_wait(&barrier); | |
| ret = pread(data->fd, buf, SECTORSIZE, | |
| off + SECTORSIZE * data->thread_id); | |
| if (ret == -1) | |
| perror("pread"); | |
| } | |
| free(buf); | |
| return NULL; | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| struct race_thread_data data[2]; | |
| pthread_t thread; | |
| int fd; | |
| if (argc != 2) { | |
| fprintf(stderr, "usage: %s PATH\n", argv[0]); | |
| return EXIT_FAILURE; | |
| } | |
| errno = pthread_barrier_init(&barrier, NULL, 2); | |
| if (errno) { | |
| perror("pthread_barrier_init"); | |
| return EXIT_FAILURE; | |
| } | |
| if (create_test_file(argv[1]) == -1) | |
| return EXIT_FAILURE; | |
| sync(); | |
| system("echo 3 > /proc/sys/vm/drop_caches"); | |
| fd = open(argv[1], O_RDONLY | O_DIRECT); | |
| if (fd == -1) { | |
| perror("open"); | |
| return EXIT_FAILURE; | |
| } | |
| data[0].fd = fd; | |
| data[0].thread_id = 0; | |
| errno = pthread_create(&thread, NULL, race_thread, &data[0]); | |
| if (errno) { | |
| perror("pthread_create"); | |
| close(fd); | |
| return EXIT_FAILURE; | |
| } | |
| data[1].fd = fd; | |
| data[1].thread_id = 1; | |
| race_thread(&data[1]); | |
| pthread_join(thread, NULL); | |
| close(fd); | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment