1 /*
2 * Copyright 2024 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.channel.uring;
17
18 import io.netty.channel.IoOps;
19
20 /**
21 * {@link IoOps} for implementation for
22 * <a href="https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h">Io_uring</a>.
23 */
24 public final class IoUringIoOps implements IoOps {
25
26 private final byte opcode;
27 private final byte flags;
28 private final short ioPrio;
29 private final int fd;
30 private final long union1;
31 private final long union2;
32 private final int len;
33 private final int union3;
34 private final long data;
35 private final short personality;
36 private final short union4;
37 private final int union5;
38 private final long union6;
39
40 /**
41 * Create a new instance which represents the {@code io_uring_sqe} struct.
42 * @deprecated use
43 * {@link #IoUringIoOps(byte, byte, short, int, long, long, int, int, long, short, short, int, long)} instead.
44 */
45 @Deprecated
46 public IoUringIoOps(byte opcode, byte flags, short ioPrio, int fd, long union1, long union2, int len, int union3,
47 short data, short union4, short personality, int union5, long union6) {
48 this(opcode, flags, ioPrio, fd, union1, union2, len, union3, (long) data, union4, personality, union5, union6);
49 }
50
51 /**
52 * Create a new instance which represents the {@code io_uring_sqe} struct.
53 *
54 * <pre>{@code
55 * struct io_uring_sqe {
56 * __u8 opcode; // type of operation for this sqe
57 * __u8 flags; // IOSQE_ flags
58 * __u16 ioprio; // ioprio for the request
59 * __s32 fd; // file descriptor to do IO on
60 *
61 * union { // union1
62 * __u64 off; // offset into file
63 * __u64 addr2;
64 * struct {
65 * __u32 cmd_op;
66 * __u32 __pad1;
67 * };
68 * };
69 *
70 * union { // union2
71 * __u64 addr; // pointer to buffer or iovecs
72 * __u64 splice_off_in;
73 * struct {
74 * __u32 level;
75 * __u32 optname;
76 * };
77 * };
78 * __u32 len; // buffer size or number of iovecs
79 *
80 * union { // union3
81 * __kernel_rwf_t rw_flags;
82 * __u32 fsync_flags;
83 * __u16 poll_events; // compatibility
84 * __u32 poll32_events; // word-reversed for BE
85 * __u32 sync_range_flags;
86 * __u32 msg_flags;
87 * __u32 timeout_flags;
88 * __u32 accept_flags;
89 * __u32 cancel_flags;
90 * __u32 open_flags;
91 * __u32 statx_flags;
92 * __u32 fadvise_advice;
93 * __u32 splice_flags;
94 * __u32 rename_flags;
95 * __u32 unlink_flags;
96 * __u32 hardlink_flags;
97 * __u32 xeattr_flags;
98 * __u32 msg_ring_flags;
99 * __u32 uring_cmd_flags;
100 * __u32 waitid_flags;
101 * __u32 futex_flags;
102 * __u32 install_fd_flags;
103 * __u32 nop_flags;
104 * };
105 * __u64 user_data; // data to be passed back at completion time
106 * // pack this to avoid bogus arm OABI complaints
107 *
108 * union { // union4
109 *
110 * // index into fixed buffers, if used
111 * __u16 buf_index;
112 * // for grouped buffer selection
113 * __u16 buf_group;
114 * }__attribute__((packed));
115 * // personality to use, if used
116 * __u16 personality;
117 *
118 * union { // union5
119 *
120 * __s32 splice_fd_in;
121 * __u32 file_index;
122 * __u32 optlen;
123 * struct {
124 * __u16 addr_len;
125 * __u16 __pad3[ 1];
126 * };
127 * };
128 *
129 * union { // union6
130 *
131 * struct {
132 * __u64 addr3;
133 * __u64 __pad2[ 1];
134 * };
135 * __u64 optval;
136 * //
137 * // If the ring is initialized with IORING_SETUP_SQE128, then
138 * // this field is used for 80 bytes of arbitrary command data
139 * __u8 cmd[ 0];
140 * };
141 * };
142 * }
143 * </pre>
144 */
145 public IoUringIoOps(byte opcode, byte flags, short ioPrio, int fd, long union1, long union2, int len, int union3,
146 long data, short union4, short personality, int union5, long union6) {
147 this.opcode = opcode;
148 this.flags = flags;
149 this.ioPrio = ioPrio;
150 this.fd = fd;
151 this.union1 = union1;
152 this.union2 = union2;
153 this.len = len;
154 this.union3 = union3;
155 this.data = data;
156 this.union4 = union4;
157 this.personality = personality;
158 this.union5 = union5;
159 this.union6 = union6;
160 }
161
162 byte opcode() {
163 return opcode;
164 }
165
166 byte flags() {
167 return flags;
168 }
169
170 short ioPrio() {
171 return ioPrio;
172 }
173
174 int fd() {
175 return fd;
176 }
177
178 long union1() {
179 return union1;
180 }
181
182 long union2() {
183 return union2;
184 }
185
186 int len() {
187 return len;
188 }
189
190 int union3() {
191 return union3;
192 }
193
194 /**
195 * Returns the data that is passed as part of this {@link IoUringIoOps}.
196 *
197 * @return data.
198 * @deprecated use {@link #userData()} instead.
199 */
200 @Deprecated
201 short data() {
202 return (short) data;
203 }
204
205 long userData() {
206 return data;
207 }
208
209 short personality() {
210 return personality;
211 }
212
213 short union4() {
214 return union4;
215 }
216
217 int union5() {
218 return union5;
219 }
220
221 long union6() {
222 return union6;
223 }
224
225 @Override
226 public String toString() {
227 return "IOUringIoOps{" +
228 "opcode=" + opcode +
229 ", flags=" + flags +
230 ", ioPrio=" + ioPrio +
231 ", fd=" + fd +
232 ", union1=" + union1 +
233 ", union2=" + union2 +
234 ", len=" + len +
235 ", union3=" + union3 +
236 ", data=" + data +
237 ", union4=" + union4 +
238 ", personality=" + personality +
239 ", union5=" + union5 +
240 ", union6=" + union6 +
241 '}';
242 }
243
244 /**
245 * Returns a new {@code OP_ASYNC_CANCEL} {@link IoUringIoOps}.
246 *
247 * @param flags the flags.
248 * @param userData the user data that identify a previous submitted {@link IoUringIoOps} that should be cancelled.
249 * The value to use here is returned by {@link io.netty.channel.IoRegistration#submit(IoOps)}.
250 * @param data the data
251 * @return ops.
252 */
253 static IoUringIoOps newAsyncCancel(byte flags, long userData, short data) {
254 // Best effort to cancel the
255 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L679
256 return new IoUringIoOps(Native.IORING_OP_ASYNC_CANCEL, flags, (short) 0, -1, 0, userData, 0, 0,
257 data, (short) 0, (short) 0, 0, 0);
258 }
259
260 /**
261 * Returns a new {@code OP_CLOSE} {@link IoUringIoOps}.
262 *
263 * @param fd the filedescriptor
264 * @param flags the flags.
265 * @param data the data
266 * @return ops.
267 */
268 static IoUringIoOps newClose(int fd, byte flags, short data) {
269 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L764
270 return new IoUringIoOps(Native.IORING_OP_CLOSE, flags, (short) 0, fd, 0L, 0L, 0, 0, data,
271 (short) 0, (short) 0, 0, 0);
272 }
273
274 /**
275 * Returns a new {@code OP_POLL_ADD} {@link IoUringIoOps}.
276 *
277 * @param fd the filedescriptor
278 * @param flags the flags.
279 * @param mask the mask.
280 * @param len the len.
281 * @param data the data.
282 * @return ops.
283 */
284 static IoUringIoOps newPollAdd(int fd, byte flags, int mask, int len, short data) {
285 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L554
286 return new IoUringIoOps(Native.IORING_OP_POLL_ADD, flags, (short) 0, fd, 0L, 0L, len, mask, data,
287 (short) 0, (short) 0, 0, 0);
288 }
289
290 /**
291 * Returns a new {@code OP_SENDMSG} {@link IoUringIoOps}.
292 *
293 * @param fd the filedescriptor
294 * @param flags the flags.
295 * @param msgFlags the msg flags.
296 * @param data the data
297 * @return ops.
298 */
299 static IoUringIoOps newSendmsg(int fd, byte flags, int msgFlags, long address, short data) {
300 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L539
301 return new IoUringIoOps(Native.IORING_OP_SENDMSG, flags, (short) 0, fd, 0L, address, 1, msgFlags, data,
302 (short) 0, (short) 0, 0, 0);
303 }
304
305 /**
306 * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
307 *
308 * @param fd the filedescriptor
309 * @param flags the flags.
310 * @param remoteMemoryAddress the memory address of the sockaddr_storage.
311 * @param data the data
312 * @return ops.
313 */
314 static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, short data) {
315 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
316 return newConnect(
317 fd, flags,
318 remoteMemoryAddress, Native.SIZEOF_SOCKADDR_STORAGE,
319 data
320 );
321 }
322
323 /**
324 * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
325 *
326 * @param fd the filedescriptor
327 * @param flags the flags.
328 * @param remoteMemoryAddress the memory address of the sockaddr_storage.
329 * @param addrLen then remoteMemory storage length.
330 * @param data the data
331 * @return ops.
332 */
333 static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, int addrLen, short data) {
334 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
335 return new IoUringIoOps(Native.IORING_OP_CONNECT, flags, (short) 0, fd, addrLen,
336 remoteMemoryAddress, 0, 0, data, (short) 0, (short) 0, 0, 0);
337 }
338
339 /**
340 * Returns a new {@code OP_ACCEPT} {@link IoUringIoOps}.
341 *
342 * @param fd the filedescriptor
343 * @param flags the flags.
344 * @param acceptFlags the flags for ACCEPT itself
345 * @param ioPrio io_prio
346 * @param acceptedAddressMemoryAddress the memory address of the sockaddr_storage.
347 * @param acceptedAddressLengthMemoryAddress the memory address of the length that will be updated once a new
348 * connection was accepted.
349 * @param data the data
350 * @return ops.
351 */
352 static IoUringIoOps newAccept(int fd, byte flags, int acceptFlags, short ioPrio, long acceptedAddressMemoryAddress,
353 long acceptedAddressLengthMemoryAddress, short data) {
354 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L625
355 return new IoUringIoOps(Native.IORING_OP_ACCEPT, flags, ioPrio, fd, acceptedAddressLengthMemoryAddress,
356 acceptedAddressMemoryAddress, 0, acceptFlags, data, (short) 0, (short) 0, 0, 0);
357 }
358
359 /**
360 * Returns a new {@code OP_WRITEV} {@link IoUringIoOps}.
361 *
362 * @param fd the filedescriptor
363 * @param flags the flags.
364 * @param writevFlags the writev flags.
365 * @param memoryAddress the memory address of the io_vec array.
366 * @param length the length of the io_vec array.
367 * @param data the data
368 * @return ops.
369 */
370 static IoUringIoOps newWritev(int fd, byte flags, int writevFlags, long memoryAddress,
371 int length, short data) {
372 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L500
373 return new IoUringIoOps(Native.IORING_OP_WRITEV, flags, (short) 0, fd,
374 0, memoryAddress, length, writevFlags, data, (short) 0, (short) 0, 0, 0);
375 }
376
377 /**
378 * Returns a new {@code OP_WRITE} {@link IoUringIoOps}.
379 *
380 * @param fd the filedescriptor
381 * @param flags the flags.
382 * @param writeFlags the write flags.
383 * @param memoryAddress the memory address of the buffer
384 * @param length the length of the buffer.
385 * @param data the data
386 * @return ops.
387 */
388 static IoUringIoOps newWrite(
389 int fd, byte flags, int writeFlags, long memoryAddress, int length, short data) {
390 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L794
391 return new IoUringIoOps(Native.IORING_OP_WRITE, flags, (short) 0, fd,
392 0, memoryAddress, length, writeFlags, data, (short) 0, (short) 0, 0, 0);
393 }
394
395 /**
396 * Returns a new {@code OP_RECV} {@link IoUringIoOps}.
397 *
398 * @param fd the filedescriptor
399 * @param flags the flags.
400 * @param ioPrio the ioPrio.
401 * @param recvFlags the recv flags.
402 * @param memoryAddress the memory address of the buffer
403 * @param length the length of the buffer.
404 * @param data the data
405 * @return ops.
406 */
407 static IoUringIoOps newRecv(
408 int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data) {
409 return newRecv(fd, flags, ioPrio, recvFlags, memoryAddress, length, data, (short) 0);
410 }
411
412 static IoUringIoOps newRecv(
413 int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data, short bid) {
414 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L898
415 return new IoUringIoOps(Native.IORING_OP_RECV, flags, ioPrio, fd,
416 0, memoryAddress, length, recvFlags, data, bid, (short) 0, 0, 0);
417 }
418
419 static IoUringIoOps newSendZc(
420 int fd, long memoryAddress, int length,
421 int flags, short data, int zcFlags) {
422 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L867
423 return new IoUringIoOps(Native.IORING_OP_SEND_ZC, (byte) 0, (byte) zcFlags, fd,
424 0, memoryAddress, length, flags, data, (short) 0, (short) 0, 0, 0);
425 }
426
427 static IoUringIoOps newSendmsgZc(int fd, byte flags, int msgFlags, long address, short data) {
428 return new IoUringIoOps(Native.IORING_OP_SENDMSG_ZC, flags, (short) 0, fd, 0L, address, 1, msgFlags, data,
429 (short) 0, (short) 0, 0, 0);
430 }
431
432 /**
433 * Returns a new {@code OP_RECVMSG} {@link IoUringIoOps}.
434 *
435 * @param fd the filedescriptor
436 * @param flags the flags.
437 * @param msgFlags the recvmsg flags.
438 * @param memoryAddress the memory address of the msghdr struct
439 * @param data the data
440 * @return ops.
441 */
442 static IoUringIoOps newRecvmsg(int fd, byte flags, int msgFlags, long memoryAddress, short data) {
443 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L523
444 return new IoUringIoOps(
445 Native.IORING_OP_RECVMSG, flags, (short) 0, fd, 0L, memoryAddress, 1, msgFlags, data,
446 (short) 0, (short) 0, 0, 0);
447 }
448
449 /**
450 * Returns a new {@code OP_SEND} {@link IoUringIoOps}.
451 *
452 * @param fd the filedescriptor
453 * @param flags the flags.
454 * @param sendFlags the send flags.
455 * @param memoryAddress the memory address of the buffer.
456 * @param length the length of the buffer.
457 * @param data the data
458 * @return ops.
459 */
460 static IoUringIoOps newSend(
461 int fd, byte flags, int sendFlags, long memoryAddress, int length, short data) {
462 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L839
463 return new IoUringIoOps(Native.IORING_OP_SEND, flags, (short) 0, fd,
464 0, memoryAddress, length, sendFlags, data, (short) 0, (short) 0, 0, 0);
465 }
466
467 /**
468 * Returns a new {@code OP_SHUTDOWN} {@link IoUringIoOps}.
469 *
470 * @param fd the filedescriptor
471 * @param flags the flags.
472 * @param how how the shutdown will be done.
473 * @param data the data
474 * @return ops.
475 */
476 static IoUringIoOps newShutdown(int fd, byte flags, int how, short data) {
477 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L1023
478 return new IoUringIoOps(Native.IORING_OP_SHUTDOWN, flags, (short) 0, fd, 0, 0, how, 0, data,
479 (short) 0, (short) 0, 0, 0);
480 }
481
482 /**
483 *
484 * Returns a new {@code OP_SPLICE} {@link IoUringIoOps}.
485 *
486 * @param fd_in the filedescriptor
487 * @param off_in the filedescriptor offset
488 * @param fd_out the filedescriptor
489 * @param off_out the filedescriptor offset
490 * @param nbytes splice bytes
491 * @param splice_flags the flag
492 * @param data the data
493 * @return ops.
494 */
495 static IoUringIoOps newSplice(int fd_in, long off_in,
496 int fd_out, long off_out,
497 int nbytes,
498 int splice_flags,
499 short data) {
500 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L454
501 return new IoUringIoOps(
502 Native.IORING_OP_SPLICE, (byte) 0, (short) 0, fd_out, off_out, off_in,
503 nbytes, splice_flags, data, (short) 0, (short) 0, fd_in, 0
504 );
505 }
506 }