generic: verify ciphertext of IV_INO_LBLK_32 encryption policies
[xfstests-dev.git] / src / splice-test.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019 RedHat Inc.  All Rights Reserved.
4  * Author: Andreas Gruenbacher <agruenba@redhat.com>
5  *
6  * Make sure that reading and writing to a pipe via splice.
7  */
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <err.h>
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <stdbool.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #define SECTOR_SIZE 512
22 #define BUFFER_SIZE (150 * SECTOR_SIZE)
23
24 void read_from_pipe(int fd, const char *filename, size_t size)
25 {
26         char buffer[SECTOR_SIZE];
27         size_t sz;
28         ssize_t ret;
29
30         while (size) {
31                 sz = size;
32                 if (sz > sizeof buffer)
33                         sz = sizeof buffer;
34                 ret = read(fd, buffer, sz);
35                 if (ret < 0)
36                         err(1, "read: %s", filename);
37                 if (ret == 0) {
38                         fprintf(stderr, "read: %s: unexpected EOF\n", filename);
39                         exit(1);
40                 }
41                 size -= sz;
42         }
43 }
44
45 void do_splice1(int fd, const char *filename, size_t size)
46 {
47         bool retried = false;
48         int pipefd[2];
49
50         if (pipe(pipefd) == -1)
51                 err(1, "pipe");
52         while (size) {
53                 ssize_t spliced;
54
55                 spliced = splice(fd, NULL, pipefd[1], NULL, size, SPLICE_F_MOVE);
56                 if (spliced == -1) {
57                         if (errno == EAGAIN && !retried) {
58                                 retried = true;
59                                 fprintf(stderr, "retrying splice\n");
60                                 sleep(1);
61                                 continue;
62                         }
63                         err(1, "splice");
64                 }
65                 read_from_pipe(pipefd[0], filename, spliced);
66                 size -= spliced;
67         }
68         close(pipefd[0]);
69         close(pipefd[1]);
70 }
71
72 void do_splice2(int fd, const char *filename, size_t size)
73 {
74         bool retried = false;
75         int pipefd[2];
76         int pid;
77
78         if (pipe(pipefd) == -1)
79                 err(1, "pipe");
80
81         pid = fork();
82         if (pid == 0) {
83                 close(pipefd[1]);
84                 read_from_pipe(pipefd[0], filename, size);
85                 exit(0);
86         } else {
87                 close(pipefd[0]);
88                 while (size) {
89                         ssize_t spliced;
90
91                         spliced = splice(fd, NULL, pipefd[1], NULL, size, SPLICE_F_MOVE);
92                         if (spliced == -1) {
93                                 if (errno == EAGAIN && !retried) {
94                                         retried = true;
95                                         fprintf(stderr, "retrying splice\n");
96                                         sleep(1);
97                                         continue;
98                                 }
99                                 err(1, "splice");
100                         }
101                         size -= spliced;
102                 }
103                 close(pipefd[1]);
104                 waitpid(pid, NULL, 0);
105         }
106 }
107
108 void usage(const char *argv0)
109 {
110         fprintf(stderr, "USAGE: %s [-rd] {filename}\n", basename(argv0));
111         exit(2);
112 }
113
114 int main(int argc, char *argv[])
115 {
116         void (*do_splice)(int fd, const char *filename, size_t size);
117         const char *filename;
118         char *buffer;
119         int opt, open_flags, fd;
120         ssize_t ret;
121
122         do_splice = do_splice1;
123         open_flags = O_CREAT | O_TRUNC | O_RDWR | O_DIRECT;
124
125         while ((opt = getopt(argc, argv, "rd")) != -1) {
126                 switch(opt) {
127                 case 'r':
128                         do_splice = do_splice2;
129                         break;
130                 case 'd':
131                         open_flags &= ~O_DIRECT;
132                         break;
133                 default:  /* '?' */
134                         usage(argv[0]);
135                 }
136         }
137
138         if (optind >= argc)
139                 usage(argv[0]);
140         filename = argv[optind];
141
142         printf("%s reader %s O_DIRECT\n",
143                    do_splice == do_splice1 ? "sequential" : "concurrent",
144                    (open_flags & O_DIRECT) ? "with" : "without");
145
146         buffer = aligned_alloc(SECTOR_SIZE, BUFFER_SIZE);
147         if (buffer == NULL)
148                 err(1, "aligned_alloc");
149
150         fd = open(filename, open_flags, 0666);
151         if (fd == -1)
152                 err(1, "open: %s", filename);
153
154         memset(buffer, 'x', BUFFER_SIZE);
155         ret = write(fd, buffer, BUFFER_SIZE);
156         if (ret < 0)
157                 err(1, "write: %s", filename);
158         if (ret != BUFFER_SIZE) {
159                 fprintf(stderr, "%s: short write\n", filename);
160                 exit(1);
161         }
162
163         ret = lseek(fd, 0, SEEK_SET);
164         if (ret != 0)
165                 err(1, "lseek: %s", filename);
166
167         do_splice(fd, filename, BUFFER_SIZE);
168
169         if (unlink(filename) == -1)
170                 err(1, "unlink: %s", filename);
171
172         return 0;
173 }