blob: 455ca729a5dd690cda2e51a9343cbde3278dda54 [file] [log] [blame]
Jens Axboe357ca592019-01-08 15:41:14 -07001/*
2 * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-cp io_uring-cp.c -luring
3 */
4#include <stdio.h>
5#include <fcntl.h>
6#include <string.h>
7#include <stdlib.h>
8#include <unistd.h>
Jens Axboef7dac562019-03-05 20:13:57 -07009#include <assert.h>
10#include <errno.h>
Jens Axboeb7e86eb2019-01-17 18:14:21 -070011#include <inttypes.h>
Jens Axboe357ca592019-01-08 15:41:14 -070012#include <sys/types.h>
13#include <sys/stat.h>
Jens Axboef7dac562019-03-05 20:13:57 -070014#include <sys/ioctl.h>
Stefan Hajnoczic31c7ec2019-07-24 09:24:50 +010015#include "liburing.h"
Jens Axboe357ca592019-01-08 15:41:14 -070016
17#define QD 64
Jens Axboef7dac562019-03-05 20:13:57 -070018#define BS (32*1024)
Jens Axboe357ca592019-01-08 15:41:14 -070019
Jens Axboef7dac562019-03-05 20:13:57 -070020static int infd, outfd;
Jens Axboe357ca592019-01-08 15:41:14 -070021
Jens Axboe6cdce172019-01-10 09:32:41 -070022struct io_data {
Jens Axboef7dac562019-03-05 20:13:57 -070023 int read;
24 off_t first_offset, offset;
25 size_t first_len;
26 struct iovec iov;
Jens Axboe6cdce172019-01-10 09:32:41 -070027};
28
Jens Axboed5b4ae12019-01-10 14:28:10 -070029static int setup_context(unsigned entries, struct io_uring *ring)
Jens Axboe357ca592019-01-08 15:41:14 -070030{
Jens Axboe66a7d052019-01-08 15:59:09 -070031 int ret;
Jens Axboe357ca592019-01-08 15:41:14 -070032
Jens Axboea992ffa2019-01-10 15:11:07 -070033 ret = io_uring_queue_init(entries, ring, 0);
Jens Axboe66a7d052019-01-08 15:59:09 -070034 if (ret < 0) {
35 fprintf(stderr, "queue_init: %s\n", strerror(-ret));
Jens Axboe357ca592019-01-08 15:41:14 -070036 return -1;
37 }
38
Jens Axboe357ca592019-01-08 15:41:14 -070039 return 0;
40}
41
42static int get_file_size(int fd, off_t *size)
43{
44 struct stat st;
45
46 if (fstat(fd, &st) < 0)
47 return -1;
48 if (S_ISREG(st.st_mode)) {
49 *size = st.st_size;
50 return 0;
Jens Axboef7dac562019-03-05 20:13:57 -070051 } else if (S_ISBLK(st.st_mode)) {
52 unsigned long long bytes;
53
54 if (ioctl(fd, BLKGETSIZE64, &bytes) != 0)
55 return -1;
56
57 *size = bytes;
58 return 0;
Jens Axboe357ca592019-01-08 15:41:14 -070059 }
60
61 return -1;
62}
63
Jens Axboef7dac562019-03-05 20:13:57 -070064static void queue_prepped(struct io_uring *ring, struct io_data *data)
Jens Axboe357ca592019-01-08 15:41:14 -070065{
Jens Axboef7dac562019-03-05 20:13:57 -070066 struct io_uring_sqe *sqe;
67
68 sqe = io_uring_get_sqe(ring);
69 assert(sqe);
70
71 if (data->read)
72 io_uring_prep_readv(sqe, infd, &data->iov, 1, data->offset);
73 else
74 io_uring_prep_writev(sqe, outfd, &data->iov, 1, data->offset);
75
76 io_uring_sqe_set_data(sqe, data);
Jens Axboe357ca592019-01-08 15:41:14 -070077}
78
Jens Axboef7dac562019-03-05 20:13:57 -070079static int queue_read(struct io_uring *ring, off_t size, off_t offset)
Jens Axboe357ca592019-01-08 15:41:14 -070080{
Jens Axboe7bf7e8e2019-01-09 15:26:20 -070081 struct io_uring_sqe *sqe;
Jens Axboe6cdce172019-01-10 09:32:41 -070082 struct io_data *data;
Jens Axboe357ca592019-01-08 15:41:14 -070083
zhangliguang4d325562019-05-22 13:32:32 +080084 data = malloc(size + sizeof(*data));
85 if (!data)
Jens Axboe357ca592019-01-08 15:41:14 -070086 return 1;
87
zhangliguang4d325562019-05-22 13:32:32 +080088 sqe = io_uring_get_sqe(ring);
89 if (!sqe) {
90 free(data);
91 return 1;
92 }
93
Jens Axboef7dac562019-03-05 20:13:57 -070094 data->read = 1;
95 data->offset = data->first_offset = offset;
Jens Axboe6cdce172019-01-10 09:32:41 -070096
Jens Axboef7dac562019-03-05 20:13:57 -070097 data->iov.iov_base = data + 1;
98 data->iov.iov_len = size;
99 data->first_len = size;
100
101 io_uring_prep_readv(sqe, infd, &data->iov, 1, offset);
Jens Axboe5789a632019-01-17 18:12:22 -0700102 io_uring_sqe_set_data(sqe, data);
Jens Axboe357ca592019-01-08 15:41:14 -0700103 return 0;
104}
105
Jens Axboef7dac562019-03-05 20:13:57 -0700106static void queue_write(struct io_uring *ring, struct io_data *data)
Jens Axboe357ca592019-01-08 15:41:14 -0700107{
Jens Axboef7dac562019-03-05 20:13:57 -0700108 data->read = 0;
109 data->offset = data->first_offset;
Jens Axboe357ca592019-01-08 15:41:14 -0700110
Jens Axboef7dac562019-03-05 20:13:57 -0700111 data->iov.iov_base = data + 1;
112 data->iov.iov_len = data->first_len;
Jens Axboe357ca592019-01-08 15:41:14 -0700113
Jens Axboef7dac562019-03-05 20:13:57 -0700114 queue_prepped(ring, data);
115 io_uring_submit(ring);
116}
Jens Axboe357ca592019-01-08 15:41:14 -0700117
Jens Axboef7dac562019-03-05 20:13:57 -0700118static int copy_file(struct io_uring *ring, off_t insize)
119{
120 unsigned long reads, writes;
121 struct io_uring_cqe *cqe;
122 off_t write_left, offset;
123 int ret;
124
125 write_left = insize;
126 writes = reads = offset = 0;
127
128 while (insize || write_left) {
129 int had_reads, got_comp;
130
131 /*
132 * Queue up as many reads as we can
133 */
134 had_reads = reads;
135 while (insize) {
136 off_t this_size = insize;
137
138 if (reads + writes >= QD)
139 break;
140 if (this_size > BS)
141 this_size = BS;
142 else if (!this_size)
143 break;
144
145 if (queue_read(ring, this_size, offset))
146 break;
147
148 insize -= this_size;
149 offset += this_size;
150 reads++;
Jens Axboe357ca592019-01-08 15:41:14 -0700151 }
Jens Axboef7dac562019-03-05 20:13:57 -0700152
153 if (had_reads != reads) {
154 ret = io_uring_submit(ring);
155 if (ret < 0) {
156 fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret));
157 break;
158 }
Jens Axboe357ca592019-01-08 15:41:14 -0700159 }
Jens Axboef7dac562019-03-05 20:13:57 -0700160
161 /*
Jens Axboea231fdc2019-03-06 08:31:26 -0700162 * Queue is full at this point. Find at least one completion.
Jens Axboef7dac562019-03-05 20:13:57 -0700163 */
164 got_comp = 0;
165 while (write_left) {
166 struct io_data *data;
167
168 if (!got_comp) {
Jens Axboe39e0ebd2019-04-18 08:32:06 -0600169 ret = io_uring_wait_cqe(ring, &cqe);
Jens Axboef7dac562019-03-05 20:13:57 -0700170 got_comp = 1;
Jens Axboeb76db3f2019-08-30 11:09:46 -0600171 } else {
Jens Axboe39e0ebd2019-04-18 08:32:06 -0600172 ret = io_uring_peek_cqe(ring, &cqe);
Jens Axboeb76db3f2019-08-30 11:09:46 -0600173 if (ret == -EAGAIN) {
174 cqe = NULL;
175 ret = 0;
176 }
177 }
Jens Axboef7dac562019-03-05 20:13:57 -0700178 if (ret < 0) {
Jens Axboe39e0ebd2019-04-18 08:32:06 -0600179 fprintf(stderr, "io_uring_peek_cqe: %s\n",
Jens Axboef7dac562019-03-05 20:13:57 -0700180 strerror(-ret));
181 return 1;
182 }
183 if (!cqe)
184 break;
185
Jens Axboedb11f112019-04-07 18:36:43 -0600186 data = io_uring_cqe_get_data(cqe);
Jens Axboef7dac562019-03-05 20:13:57 -0700187 if (cqe->res < 0) {
188 if (cqe->res == -EAGAIN) {
189 queue_prepped(ring, data);
Jens Axboe76b61eb2019-04-17 09:25:32 -0600190 io_uring_cqe_seen(ring, cqe);
Jens Axboef7dac562019-03-05 20:13:57 -0700191 continue;
192 }
193 fprintf(stderr, "cqe failed: %s\n",
194 strerror(-cqe->res));
195 return 1;
196 } else if (cqe->res != data->iov.iov_len) {
Jens Axboea231fdc2019-03-06 08:31:26 -0700197 /* Short read/write, adjust and requeue */
Jens Axboef7dac562019-03-05 20:13:57 -0700198 data->iov.iov_base += cqe->res;
199 data->iov.iov_len -= cqe->res;
200 data->offset += cqe->res;
201 queue_prepped(ring, data);
Jens Axboe76b61eb2019-04-17 09:25:32 -0600202 io_uring_cqe_seen(ring, cqe);
Jens Axboef7dac562019-03-05 20:13:57 -0700203 continue;
204 }
205
206 /*
207 * All done. if write, nothing else to do. if read,
208 * queue up corresponding write.
209 */
210 if (data->read) {
211 queue_write(ring, data);
212 write_left -= data->first_len;
213 reads--;
214 writes++;
215 } else {
216 free(data);
217 writes--;
218 }
Jens Axboe76b61eb2019-04-17 09:25:32 -0600219 io_uring_cqe_seen(ring, cqe);
Jens Axboef7dac562019-03-05 20:13:57 -0700220 }
Jens Axboe357ca592019-01-08 15:41:14 -0700221 }
222
223 return 0;
224}
225
Jens Axboe357ca592019-01-08 15:41:14 -0700226int main(int argc, char *argv[])
227{
Jens Axboef7dac562019-03-05 20:13:57 -0700228 struct io_uring ring;
229 off_t insize;
230 int ret;
Jens Axboe357ca592019-01-08 15:41:14 -0700231
232 if (argc < 3) {
233 printf("%s: infile outfile\n", argv[0]);
234 return 1;
235 }
236
237 infd = open(argv[1], O_RDONLY);
238 if (infd < 0) {
239 perror("open infile");
240 return 1;
241 }
242 outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
243 if (outfd < 0) {
244 perror("open outfile");
245 return 1;
246 }
247
Jens Axboef7dac562019-03-05 20:13:57 -0700248 if (setup_context(QD, &ring))
Jens Axboe357ca592019-01-08 15:41:14 -0700249 return 1;
Jens Axboef7dac562019-03-05 20:13:57 -0700250 if (get_file_size(infd, &insize))
Jens Axboe357ca592019-01-08 15:41:14 -0700251 return 1;
252
Jens Axboef7dac562019-03-05 20:13:57 -0700253 ret = copy_file(&ring, insize);
Jens Axboe357ca592019-01-08 15:41:14 -0700254
255 close(infd);
256 close(outfd);
Jens Axboef7dac562019-03-05 20:13:57 -0700257 io_uring_queue_exit(&ring);
258 return ret;
Jens Axboe357ca592019-01-08 15:41:14 -0700259}