// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2021 Red Hat, Inc. All Rights Reserved. * Written by Andreas Gruenbacher (agruenba@redhat.com) */ /* Trigger page faults in the same file during read and write. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE /* to get definition of O_DIRECT flag. */ #endif #include #include #include #include #include #include #include #include #include #include char *filename; unsigned int page_size; void *page; char *addr; int fd; ssize_t ret; /* * Leave a hole at the beginning of the test file and initialize a block of * @page_size bytes at offset @page_size to @c. Then, reopen the file and * mmap the first two pages. */ void init(char c, int flags) { fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_DIRECT, 0666); if (fd == -1) goto fail; memset(page, c, page_size); ret = pwrite(fd, page, page_size, page_size); if (ret != page_size) goto fail; if (close(fd)) goto fail; fd = open(filename, flags); if (fd == -1) goto fail; addr = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) err(1, NULL); return; fail: err(1, "%s", filename); } static ssize_t do_write(int fd, const void *buf, size_t count, off_t offset) { ssize_t count2 = 0, ret; do { ret = pwrite(fd, buf, count, offset); if (ret == -1) { if (errno == EINTR) continue; break; } if (ret == 0) break; count2 += ret; buf += ret; count -= ret; } while (count); return count2; } int main(int argc, char *argv[]) { if (argc != 2) errx(1, "no test filename argument given"); filename = argv[1]; page_size = ret = sysconf(_SC_PAGE_SIZE); if (ret == -1) err(1, NULL); ret = posix_memalign(&page, page_size, page_size); if (ret) { errno = ENOMEM; err(1, NULL); } init('d', O_RDWR | O_DIRECT); ret = do_write(fd, addr + page_size, page_size, 0); if (ret != page_size) err(1, "pwrite %s (O_DIRECT): %ld != %u", filename, ret, page_size); if (memcmp(addr, page, page_size)) errx(1, "pwrite (O_DIRECT) is broken"); if (fsync(fd)) errx(1, "fsync"); if (close(fd)) errx(1, "close"); if (unlink(filename)) err(1, "unlink %s", filename); return 0; }