4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2024 by Triad National Security, LLC.
26 #include <sys/types.h>
39 #define MIN(a, b) ((a) < (b)) ? (a) : (b)
42 static char *filename
= NULL
;
43 static int blocksize
= 131072; /* 128K */
44 static int err_expected
= 0;
45 static int read_op
= 0;
46 static int write_op
= 0;
47 static int numblocks
= 100;
48 static char *execname
= NULL
;
49 static int print_usage
= 0;
50 static int randompattern
= 0;
55 int entire_file_completed
;
61 (void) fprintf(stderr
,
62 "usage %s -f filename [-b blocksize] [-e wr_error_expected]\n"
63 " [-n numblocks] [-p randompattern] -r read_op \n"
64 " -w write_op [-h help]\n"
66 "Testing whether checksum verify works correctly for O_DIRECT.\n"
67 "when manipulating the contents of a userspace buffer.\n"
69 " filename: File to read or write to.\n"
70 " blocksize: Size of each block to write (must be at \n"
72 " err_expected: Whether write() is expected to return EIO\n"
73 " while manipulating the contents of the\n"
75 " numblocks: Total number of blocksized blocks to\n"
77 " read_op: Perform reads to the filename file while\n"
78 " while manipulating the buffer contents\n"
79 " write_op: Perform writes to the filename file while\n"
80 " manipulating the buffer contents\n"
81 " randompattern: Fill data buffer with random data for \n"
82 " writes. Default behavior is to fill the \n"
83 " buffer with known data pattern (0xdeadbeef)\n"
84 " help: Print usage information and exit.\n"
86 " Required parameters:\n"
88 " read_op or write_op\n"
91 " blocksize -> 131072\n"
92 " wr_err_expexted -> false\n"
94 " randompattern -> false\n",
100 parse_options(int argc
, char *argv
[])
105 extern int optind
, optopt
;
108 while ((c
= getopt(argc
, argv
, "b:ef:hn:rw")) != -1) {
111 blocksize
= atoi(optarg
);
128 numblocks
= atoi(optarg
);
140 (void) fprintf(stderr
,
141 "Option -%c requires an opertand\n",
147 (void) fprintf(stderr
,
148 "Unrecognized option: -%c\n", optopt
);
154 if (errflag
|| print_usage
== 1)
157 if (blocksize
< 512 || filename
== NULL
|| numblocks
<= 0 ||
158 (read_op
== 0 && write_op
== 0)) {
159 (void) fprintf(stderr
,
160 "Required paramater(s) missing or invalid.\n");
166 * Write blocksize * numblocks to the file using O_DIRECT.
169 write_thread(void *arg
)
172 int total_data
= blocksize
* numblocks
;
173 int left
= total_data
;
175 pthread_args_t
*args
= (pthread_args_t
*)arg
;
177 while (!args
->entire_file_completed
) {
178 wrote
= pwrite(fd
, buf
, blocksize
, offset
);
179 if (wrote
!= blocksize
) {
181 assert(errno
== EIO
);
186 offset
= ((offset
+ blocksize
) % total_data
);
190 args
->entire_file_completed
= 1;
197 * Read blocksize * numblocks to the file using O_DIRECT.
200 read_thread(void *arg
)
203 int total_data
= blocksize
* numblocks
;
204 int left
= total_data
;
206 pthread_args_t
*args
= (pthread_args_t
*)arg
;
208 while (!args
->entire_file_completed
) {
209 read
= pread(fd
, buf
, blocksize
, offset
);
210 if (read
!= blocksize
) {
214 offset
= ((offset
+ blocksize
) % total_data
);
218 args
->entire_file_completed
= 1;
225 * Update the buffers contents with random data.
228 manipulate_buf_thread(void *arg
)
232 pthread_args_t
*args
= (pthread_args_t
*)arg
;
234 while (!args
->entire_file_completed
) {
235 rand_offset
= (rand() % blocksize
);
236 rand_char
= (rand() % (126 - 33) + 33);
237 buf
[rand_offset
] = rand_char
;
244 main(int argc
, char *argv
[])
246 const char *datapattern
= "0xdeadbeef";
247 int fd_flags
= O_DIRECT
;
248 mode_t mode
= S_IRUSR
| S_IWUSR
;
250 pthread_t manipul_thr
;
251 int left
= blocksize
;
254 pthread_args_t args
= { 0 };
256 parse_options(argc
, argv
);
259 fd_flags
|= (O_WRONLY
| O_CREAT
);
261 fd_flags
|= O_RDONLY
;
264 fd
= open(filename
, fd_flags
, mode
);
266 (void) fprintf(stderr
, "%s, %s\n", execname
, filename
);
271 int err
= posix_memalign((void **)&buf
, sysconf(_SC_PAGE_SIZE
),
274 (void) fprintf(stderr
,
275 "%s: %s\n", execname
, strerror(err
));
280 if (!randompattern
) {
281 /* Putting known data pattern in buffer */
283 size_t amt
= MIN(strlen(datapattern
), left
);
284 memcpy(&buf
[offset
], datapattern
, amt
);
289 /* Putting random data in buffer */
290 for (int i
= 0; i
< blocksize
; i
++)
295 if ((rc
= pthread_create(&manipul_thr
, NULL
, manipulate_buf_thread
,
297 fprintf(stderr
, "error: pthreads_create, manipul_thr, "
304 * Writing using O_DIRECT while manipulating the buffer contents
305 * until the entire file is written.
307 if ((rc
= pthread_create(&io_thr
, NULL
, write_thread
, &args
))) {
308 fprintf(stderr
, "error: pthreads_create, io_thr, "
314 * Reading using O_DIRECT while manipulating the buffer contents
315 * until the entire file is read.
317 if ((rc
= pthread_create(&io_thr
, NULL
, read_thread
, &args
))) {
318 fprintf(stderr
, "error: pthreads_create, io_thr, "
324 pthread_join(io_thr
, NULL
);
325 pthread_join(manipul_thr
, NULL
);
327 assert(args
.entire_file_completed
== 1);