13#define CHECK(condition) \
16 fprintf(stderr, "FILE-SYNC-CONTRACT: line=%d errno=%d\n", __LINE__, errno); \
21int main(
int argc,
char** argv) {
22 const char* directory = argc > 1 ? argv[1] :
"/tmp";
24 snprintf(path,
sizeof(path),
"%s/file-sync-%ld", directory, (
long)getpid());
25 const long page = sysconf(_SC_PAGESIZE);
26 const size_t length = 3 * (size_t)page;
27 int fd = -1, readonly = -1, writeonly = -1, pathfd = -1, pipes[2] = {-1, -1};
28 unsigned char* mapping = MAP_FAILED;
29 unsigned char resident[3] = {0};
30 unsigned char byte = 0;
34 fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
35 CHECK(fd >= 0 && ftruncate(fd, length) == 0);
36 readonly = open(path, O_RDONLY);
37 writeonly = open(path, O_WRONLY);
38 pathfd = open(path, O_PATH);
39 CHECK(readonly >= 0 && writeonly >= 0 && pathfd >= 0);
40 CHECK(lseek(fd, 19, SEEK_SET) == 19 && lseek(readonly, 23, SEEK_SET) == 23);
42 mapping = mmap(NULL, length, PROT_READ, MAP_PRIVATE, readonly, 0);
43 CHECK(mapping != MAP_FAILED);
44 CHECK(readahead(readonly, page + 7, 1) == 0);
45 CHECK(mincore(mapping, length, resident) == 0 && (resident[1] & 1));
47 CHECK(posix_fadvise(readonly, 2 * page + 11, 1, POSIX_FADV_WILLNEED) == 0);
49 CHECK(mincore(mapping, length, resident) == 0 && (resident[2] & 1));
50 CHECK(readahead(readonly, 0, 0) == 0);
51 CHECK(mincore(mapping, length, resident) == 0 && (resident[0] & 1));
52 CHECK(lseek(readonly, 0, SEEK_CUR) == 23);
53 CHECK(readahead(readonly, length + page, 1) == 0);
54 CHECK(posix_fadvise(writeonly, 0, 0, POSIX_FADV_WILLNEED) == 0);
55 CHECK(munmap(mapping, length) == 0);
58 mapping = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
59 CHECK(mapping != MAP_FAILED);
62 mapping[2 * page] = 63;
63 CHECK(sync_file_range(fd, page - 1, 2, SYNC_FILE_RANGE_WRITE) == 0);
64 CHECK(sync_file_range(
66 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER) == 0);
67 CHECK(sync_file_range(fd, 0, 0, 0) == 0);
68 CHECK(sync_file_range(readonly, 0, length, SYNC_FILE_RANGE_WAIT_AFTER) == 0);
69 CHECK(fdatasync(fd) == 0 && fdatasync(readonly) == 0);
70 CHECK(lseek(fd, 0, SEEK_CUR) == 19 && lseek(readonly, 0, SEEK_CUR) == 23);
71 CHECK(pread(readonly, &
byte, 1, 0) == 1 &&
byte == 31);
72 CHECK(pread(readonly, &
byte, 1, page) == 1 &&
byte == 47);
73 CHECK(pread(readonly, &
byte, 1, 2 * page) == 1 &&
byte == 63);
76 CHECK(fdatasync(-1) == -1 && errno == EBADF);
78 CHECK(fdatasync(pathfd) == -1 && errno == EBADF);
80 CHECK(readahead(writeonly, 0, 1) == -1 && errno == EBADF);
82 CHECK(readahead(pathfd, 0, 1) == -1 && errno == EBADF);
84 CHECK(readahead(readonly, -1, 1) == -1 && errno == EINVAL);
86 CHECK(readahead(readonly, 0, SIZE_MAX) == -1 && errno == EINVAL);
88 CHECK(posix_fadvise(-1, 0, 1, POSIX_FADV_WILLNEED) == EBADF && errno == EDOM);
89 CHECK(posix_fadvise(pathfd, 0, 1, POSIX_FADV_WILLNEED) == EBADF);
90 CHECK(posix_fadvise(readonly, -1, 1, POSIX_FADV_WILLNEED) == EINVAL);
91 CHECK(posix_fadvise(readonly, 0, -1, POSIX_FADV_WILLNEED) == EINVAL);
92 CHECK(posix_fadvise(readonly, 0, 1, 99) == EINVAL);
93 for (
int advice = POSIX_FADV_NORMAL; advice <= POSIX_FADV_NOREUSE; ++advice)
94 if (advice != POSIX_FADV_WILLNEED)
95 CHECK(posix_fadvise(readonly, 0, 1, advice) == EOPNOTSUPP);
97 CHECK(sync_file_range(fd, -1, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
99 CHECK(sync_file_range(fd, 0, -1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
101 CHECK(sync_file_range(fd, LLONG_MAX, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
103 CHECK(sync_file_range(fd, 0, 1, 8) == -1 && errno == EINVAL);
105 CHECK(sync_file_range(pathfd, 0, 1, 0) == -1 && errno == EBADF);
106 CHECK(pipe(pipes) == 0);
108 CHECK(fdatasync(pipes[0]) == -1 && errno == EINVAL);
110 CHECK(readahead(pipes[0], 0, 1) == -1 && errno == EINVAL);
111 CHECK(posix_fadvise(pipes[0], 0, 1, POSIX_FADV_WILLNEED) == ESPIPE);
113 CHECK(sync_file_range(pipes[1], 0, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == ESPIPE);
115 puts(
"FILE-SYNC-CONTRACT: PASS");
118 if (mapping != MAP_FAILED)
119 munmap(mapping, length);