1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <linux/fiemap.h>
#include <setjmp.h>
#define fail() fprintf(stderr, "%s: failed at: %d\n", __func__, __LINE__)
static sigjmp_buf sj_env;
static int sig_count;
/* buf is global in order to avoid gcc memcpy optimization */
static void *buf;
static void sigbus_hdl(int sig, siginfo_t *siginfo, void *ptr)
{
fprintf(stderr, "** Received a SIGBUS **\n");
sig_count++;
siglongjmp(sj_env, 1);
}
static int test_dax_read_err(int fd)
{
void *base;
int rc = 0;
if (fd < 0) {
fail();
return -ENXIO;
}
if (posix_memalign(&buf, 4096, 4096) != 0)
return -ENOMEM;
base = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) {
perror("mmap");
rc = -ENXIO;
goto err_mmap;
}
if (sigsetjmp(sj_env, 1)) {
if (sig_count == 1) {
fprintf(stderr, "Failed to read from mapped file\n");
free(buf);
if (base) {
if (munmap(base, 4096) < 0) {
fail();
return 1;
}
}
return 1;
}
return sig_count;
}
/* read a page through DAX (should fail due to a bad block) */
memcpy(buf, base, 4096);
err_mmap:
free(buf);
return rc;
}
/* TODO: disabled till we get clear-on-write in the kernel */
#if 0
static int test_dax_write_clear(int fd)
{
void *buf;
int rc = 0;
if (fd < 0) {
fail();
return -ENXIO;
}
if (posix_memalign(&buf, 4096, 4096) != 0)
return -ENOMEM;
memset(buf, 0, 4096);
/*
* Attempt to write zeroes to the first page of the file using write()
* This should clear the pmem errors/bad blocks
*/
printf("Attempting to write\n");
if (write(fd, buf, 4096) < 0)
rc = errno;
free(buf);
return rc;
}
#endif
int main(int argc, char *argv[])
{
int fd, rc;
struct sigaction act;
if (argc < 1)
return -EINVAL;
memset(&act, 0, sizeof(act));
act.sa_sigaction = sigbus_hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGBUS, &act, 0)) {
fail();
return 1;
}
fd = open(argv[1], O_RDWR | O_DIRECT);
/* Start the test. First, we do an mmap-read, and expect it to fail */
rc = test_dax_read_err(fd);
if (rc == 0) {
fprintf(stderr, "Expected read to fail, but it succeeded\n");
rc = -ENXIO;
goto out;
}
if (rc > 1) {
fprintf(stderr, "Received a second SIGBUS, exiting.\n");
rc = -ENXIO;
goto out;
}
printf(" mmap-read failed as expected\n");
rc = 0;
/* Next, do a regular (O_DIRECT) write() */
/* TODO: Disable this till we have clear-on-write in the kernel
* rc = test_dax_write_clear(fd);
*
* if (rc)
* perror("write");
*/
out:
if (fd >= 0)
close(fd);
return rc;
}
|