Created
November 9, 2016 23:20
-
-
Save osandov/d08aabe5d4dec15517e9fde17012fd3b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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