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/manipulate_user_buffer.c
48529 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* CDDL HEADER START
4
*
5
* The contents of this file are subject to the terms of the
6
* Common Development and Distribution License (the "License").
7
* You may not use this file except in compliance with the License.
8
*
9
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10
* or https://opensource.org/licenses/CDDL-1.0.
11
* See the License for the specific language governing permissions
12
* and limitations under the License.
13
*
14
* When distributing Covered Code, include this CDDL HEADER in each
15
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16
* If applicable, add the following below this CDDL HEADER, with the
17
* fields enclosed by brackets "[]" replaced with your own identifying
18
* information: Portions Copyright [yyyy] [name of copyright owner]
19
*
20
* CDDL HEADER END
21
*/
22
23
/*
24
* Copyright (c) 2024 by Triad National Security, LLC.
25
*/
26
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
#include <errno.h>
30
#include <fcntl.h>
31
#include <stdio.h>
32
#include <unistd.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <time.h>
36
#include <pthread.h>
37
#include <assert.h>
38
39
#ifndef MIN
40
#define MIN(a, b) ((a) < (b)) ? (a) : (b)
41
#endif
42
43
static char *filename = NULL;
44
static int blocksize = 131072; /* 128K */
45
static int err_expected = 0;
46
static int read_op = 0;
47
static int write_op = 0;
48
static int numblocks = 100;
49
static char *execname = NULL;
50
static int print_usage = 0;
51
static int randompattern = 0;
52
static int fd;
53
char *buf = NULL;
54
55
typedef struct {
56
int entire_file_completed;
57
} pthread_args_t;
58
59
static void
60
usage(void)
61
{
62
(void) fprintf(stderr,
63
"usage %s -f filename [-b blocksize] [-e wr_error_expected]\n"
64
" [-n numblocks] [-p randompattern] -r read_op \n"
65
" -w write_op [-h help]\n"
66
"\n"
67
"Testing whether checksum verify works correctly for O_DIRECT.\n"
68
"when manipulating the contents of a userspace buffer.\n"
69
"\n"
70
" filename: File to read or write to.\n"
71
" blocksize: Size of each block to write (must be at \n"
72
" least >= 512).\n"
73
" err_expected: Whether write() is expected to return EIO\n"
74
" while manipulating the contents of the\n"
75
" buffer.\n"
76
" numblocks: Total number of blocksized blocks to\n"
77
" write.\n"
78
" read_op: Perform reads to the filename file while\n"
79
" while manipulating the buffer contents\n"
80
" write_op: Perform writes to the filename file while\n"
81
" manipulating the buffer contents\n"
82
" randompattern: Fill data buffer with random data for \n"
83
" writes. Default behavior is to fill the \n"
84
" buffer with known data pattern (0xdeadbeef)\n"
85
" help: Print usage information and exit.\n"
86
"\n"
87
" Required parameters:\n"
88
" filename\n"
89
" read_op or write_op\n"
90
"\n"
91
" Default Values:\n"
92
" blocksize -> 131072\n"
93
" wr_err_expexted -> false\n"
94
" numblocks -> 100\n"
95
" randompattern -> false\n",
96
execname);
97
(void) exit(1);
98
}
99
100
static void
101
parse_options(int argc, char *argv[])
102
{
103
int c;
104
int errflag = 0;
105
extern char *optarg;
106
extern int optind, optopt;
107
execname = argv[0];
108
109
while ((c = getopt(argc, argv, "b:ef:hn:rw")) != -1) {
110
switch (c) {
111
case 'b':
112
blocksize = atoi(optarg);
113
break;
114
115
case 'e':
116
err_expected = 1;
117
break;
118
119
case 'f':
120
filename = optarg;
121
break;
122
123
124
case 'h':
125
print_usage = 1;
126
break;
127
128
case 'n':
129
numblocks = atoi(optarg);
130
break;
131
132
case 'r':
133
read_op = 1;
134
break;
135
136
case 'w':
137
write_op = 1;
138
break;
139
140
case ':':
141
(void) fprintf(stderr,
142
"Option -%c requires an opertand\n",
143
optopt);
144
errflag++;
145
break;
146
case '?':
147
default:
148
(void) fprintf(stderr,
149
"Unrecognized option: -%c\n", optopt);
150
errflag++;
151
break;
152
}
153
}
154
155
if (errflag || print_usage == 1)
156
(void) usage();
157
158
if (blocksize < 512 || filename == NULL || numblocks <= 0 ||
159
(read_op == 0 && write_op == 0)) {
160
(void) fprintf(stderr,
161
"Required paramater(s) missing or invalid.\n");
162
(void) usage();
163
}
164
}
165
166
/*
167
* Write blocksize * numblocks to the file using O_DIRECT.
168
*/
169
static void *
170
write_thread(void *arg)
171
{
172
size_t offset = 0;
173
int total_data = blocksize * numblocks;
174
int left = total_data;
175
ssize_t wrote = 0;
176
pthread_args_t *args = (pthread_args_t *)arg;
177
178
while (!args->entire_file_completed) {
179
wrote = pwrite(fd, buf, blocksize, offset);
180
if (wrote != blocksize) {
181
if (err_expected)
182
assert(errno == EIO);
183
else
184
exit(2);
185
}
186
187
offset = ((offset + blocksize) % total_data);
188
left -= blocksize;
189
190
if (left == 0)
191
args->entire_file_completed = 1;
192
}
193
194
pthread_exit(NULL);
195
}
196
197
/*
198
* Read blocksize * numblocks to the file using O_DIRECT.
199
*/
200
static void *
201
read_thread(void *arg)
202
{
203
size_t offset = 0;
204
int total_data = blocksize * numblocks;
205
int left = total_data;
206
ssize_t read = 0;
207
pthread_args_t *args = (pthread_args_t *)arg;
208
209
while (!args->entire_file_completed) {
210
read = pread(fd, buf, blocksize, offset);
211
if (read != blocksize) {
212
exit(2);
213
}
214
215
offset = ((offset + blocksize) % total_data);
216
left -= blocksize;
217
218
if (left == 0)
219
args->entire_file_completed = 1;
220
}
221
222
pthread_exit(NULL);
223
}
224
225
/*
226
* Update the buffers contents with random data.
227
*/
228
static void *
229
manipulate_buf_thread(void *arg)
230
{
231
size_t rand_offset;
232
char rand_char;
233
pthread_args_t *args = (pthread_args_t *)arg;
234
235
while (!args->entire_file_completed) {
236
rand_offset = (rand() % blocksize);
237
rand_char = (rand() % (126 - 33) + 33);
238
buf[rand_offset] = rand_char;
239
}
240
241
pthread_exit(NULL);
242
}
243
244
int
245
main(int argc, char *argv[])
246
{
247
const char *datapattern = "0xdeadbeef";
248
int fd_flags = O_DIRECT;
249
mode_t mode = S_IRUSR | S_IWUSR;
250
pthread_t io_thr;
251
pthread_t manipul_thr;
252
int left = blocksize;
253
int offset = 0;
254
int rc;
255
pthread_args_t args = { 0 };
256
257
parse_options(argc, argv);
258
259
if (write_op) {
260
fd_flags |= (O_WRONLY | O_CREAT);
261
} else {
262
fd_flags |= O_RDONLY;
263
}
264
265
fd = open(filename, fd_flags, mode);
266
if (fd == -1) {
267
(void) fprintf(stderr, "%s, %s\n", execname, filename);
268
perror("open");
269
exit(2);
270
}
271
272
int err = posix_memalign((void **)&buf, sysconf(_SC_PAGE_SIZE),
273
blocksize);
274
if (err != 0) {
275
(void) fprintf(stderr,
276
"%s: %s\n", execname, strerror(err));
277
exit(2);
278
}
279
280
if (write_op) {
281
if (!randompattern) {
282
/* Putting known data pattern in buffer */
283
while (left) {
284
size_t amt = MIN(strlen(datapattern), left);
285
memcpy(&buf[offset], datapattern, amt);
286
offset += amt;
287
left -= amt;
288
}
289
} else {
290
/* Putting random data in buffer */
291
for (int i = 0; i < blocksize; i++)
292
buf[i] = rand();
293
}
294
}
295
296
if ((rc = pthread_create(&manipul_thr, NULL, manipulate_buf_thread,
297
&args))) {
298
fprintf(stderr, "error: pthreads_create, manipul_thr, "
299
"rc: %d\n", rc);
300
exit(2);
301
}
302
303
if (write_op) {
304
/*
305
* Writing using O_DIRECT while manipulating the buffer contents
306
* until the entire file is written.
307
*/
308
if ((rc = pthread_create(&io_thr, NULL, write_thread, &args))) {
309
fprintf(stderr, "error: pthreads_create, io_thr, "
310
"rc: %d\n", rc);
311
exit(2);
312
}
313
} else {
314
/*
315
* Reading using O_DIRECT while manipulating the buffer contents
316
* until the entire file is read.
317
*/
318
if ((rc = pthread_create(&io_thr, NULL, read_thread, &args))) {
319
fprintf(stderr, "error: pthreads_create, io_thr, "
320
"rc: %d\n", rc);
321
exit(2);
322
}
323
}
324
325
pthread_join(io_thr, NULL);
326
pthread_join(manipul_thr, NULL);
327
328
assert(args.entire_file_completed == 1);
329
330
(void) close(fd);
331
332
free(buf);
333
334
return (0);
335
}
336
337