Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/clone_after_trunc.c
289328 views
1
// SPDX-License-Identifier: CDDL-1.0
2
3
#include <errno.h>
4
#include <fcntl.h>
5
#include <limits.h>
6
#include <pthread.h>
7
#include <string.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <unistd.h>
11
#include <sys/stat.h>
12
13
#if defined(_GNU_SOURCE) && defined(__linux__)
14
_Static_assert(sizeof (loff_t) == sizeof (off_t),
15
"loff_t and off_t must be the same size");
16
#endif
17
18
ssize_t
19
copy_file_range(int, off_t *, int, off_t *, size_t, unsigned int)
20
__attribute__((weak));
21
22
#define FILE_SIZE (1024 * 1024)
23
#define RECORD_SIZE (128 * 1024)
24
#define NUM_THREADS 64
25
26
const char *dir;
27
volatile int failed;
28
29
static void *
30
run_test(void *arg)
31
{
32
int thread_id = (int)(long)arg;
33
34
char src_path[PATH_MAX], dst_path[PATH_MAX];
35
snprintf(src_path, PATH_MAX, "%s/src-%d", dir, thread_id);
36
snprintf(dst_path, PATH_MAX, "%s/dst-%d", dir, thread_id);
37
38
unsigned char *write_buf = malloc(FILE_SIZE);
39
unsigned char *read_buf = malloc(FILE_SIZE);
40
41
// Write out expected data.
42
memset(write_buf, 0xAA, FILE_SIZE);
43
int src = open(src_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
44
if (write(src, write_buf, FILE_SIZE) != FILE_SIZE)
45
perror("write");
46
close(src);
47
48
// Create destination file so we exercise O_TRUNC.
49
int dst = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
50
if (write(dst, write_buf, FILE_SIZE) != FILE_SIZE)
51
perror("write");
52
fsync(dst);
53
close(dst);
54
55
// Open file with O_TRUNC and perform copy.
56
src = open(src_path, O_RDONLY);
57
dst = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
58
59
off_t off_in = 0, off_out = 0;
60
ssize_t ret =
61
copy_file_range(src, &off_in, dst, &off_out, FILE_SIZE, 0);
62
if (ret != FILE_SIZE)
63
perror("copy_file_range");
64
close(src);
65
close(dst);
66
67
// Read back
68
dst = open(dst_path, O_RDONLY);
69
if (read(dst, read_buf, FILE_SIZE) != FILE_SIZE)
70
perror("read");
71
close(dst);
72
73
// Bug check
74
if (memcmp(write_buf, read_buf, FILE_SIZE) != 0) {
75
failed = 1;
76
fprintf(stderr, "[%d]: FAIL\n", thread_id);
77
78
int all_zeros = 1;
79
for (int i = 0; i < RECORD_SIZE; i++) {
80
if (read_buf[i] != 0) {
81
all_zeros = 0;
82
break;
83
}
84
}
85
86
if (all_zeros) {
87
fprintf(stderr, "[%d]: ALL ZERO\n", thread_id);
88
}
89
}
90
91
unlink(src_path);
92
unlink(dst_path);
93
free(write_buf);
94
free(read_buf);
95
return (NULL);
96
}
97
98
int
99
main(int argc, const char **argv)
100
{
101
if (argc < 2) {
102
fprintf(stderr, "usage: %s <dir>\n", argv[0]);
103
return (1);
104
}
105
dir = argv[1];
106
107
pthread_t threads[NUM_THREADS];
108
109
for (int i = 0; i < NUM_THREADS; i++) {
110
pthread_create(&threads[i], NULL, run_test, (void *)(long)i);
111
}
112
for (int i = 0; i < NUM_THREADS; i++) {
113
pthread_join(threads[i], NULL);
114
}
115
116
return (failed);
117
}
118
119