aboutsummaryrefslogtreecommitdiffstats
path: root/sys/linux/io_uring.txt
blob: 8b5bf999875983c3f1d1ff42d9332d2576c1b59d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

# See http://kernel.dk/io_uring.pdf

include <uapi/linux/io_uring.h>
# For EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL
include <uapi/linux/eventpoll.h>

resource fd_io_uring[fd]
resource ring_ptr[int64]
resource sqes_ptr[int64]
resource ioring_personality_id[int16]

# fs/io_uring.c
define IORING_MAX_ENTRIES	32768
define IORING_MAX_CQ_ENTRIES	(2 * IORING_MAX_ENTRIES)

# First does the setup calling io_uring_setup, than calls mmap to map the ring and
# the sqes. It is hard for the fuzzer to generate correct programs using mmap calls
# with fuzzer-provided mmap length. This wrapper ensures correct length computation.
syz_io_uring_setup(entries int32[1:IORING_MAX_ENTRIES], params ptr[inout, io_uring_params], addr_ring vma, addr_sqes vma, ring_ptr ptr[out, ring_ptr], sqes_ptr ptr[out, sqes_ptr]) fd_io_uring

io_uring_setup(entries int32[1:IORING_MAX_ENTRIES], params ptr[inout, io_uring_params]) fd_io_uring
io_uring_enter(fd fd_io_uring, to_submit int32[0:IORING_MAX_ENTRIES], min_complete int32[0:IORING_MAX_CQ_ENTRIES], flags flags[io_uring_enter_flags], sigmask ptr[in, sigset_t], size len[sigmask])
io_uring_register$IORING_REGISTER_BUFFERS(fd fd_io_uring, opcode const[IORING_REGISTER_BUFFERS], arg ptr[in, array[iovec_out]], nr_args len[arg])
io_uring_register$IORING_UNREGISTER_BUFFERS(fd fd_io_uring, opcode const[IORING_UNREGISTER_BUFFERS], arg const[0], nr_args const[0])
io_uring_register$IORING_REGISTER_FILES(fd fd_io_uring, opcode const[IORING_REGISTER_FILES], arg ptr[in, array[fd]], nr_args len[arg])
io_uring_register$IORING_UNREGISTER_FILES(fd fd_io_uring, opcode const[IORING_UNREGISTER_FILES], arg const[0], nr_args const[0])
io_uring_register$IORING_REGISTER_EVENTFD(fd fd_io_uring, opcode const[IORING_REGISTER_EVENTFD], arg ptr[in, fd_event], nr_args const[1])
io_uring_register$IORING_UNREGISTER_EVENTFD(fd fd_io_uring, opcode const[IORING_UNREGISTER_EVENTFD], arg const[0], nr_args const[0])
io_uring_register$IORING_REGISTER_FILES_UPDATE(fd fd_io_uring, opcode const[IORING_REGISTER_FILES_UPDATE], arg ptr[in, io_uring_files_update], nr_args len[arg:fds])
io_uring_register$IORING_REGISTER_EVENTFD_ASYNC(fd fd_io_uring, opcode const[IORING_REGISTER_EVENTFD_ASYNC], arg ptr[in, fd_event], nr_args const[1])
io_uring_register$IORING_REGISTER_PROBE(fd fd_io_uring, opcode const[IORING_REGISTER_PROBE], arg ptr[inout, io_uring_probe], nr_args len[arg:ops])
io_uring_register$IORING_REGISTER_PERSONALITY(fd fd_io_uring, opcode const[IORING_REGISTER_PERSONALITY], arg const[0], nr_args const[0]) ioring_personality_id
io_uring_register$IORING_UNREGISTER_PERSONALITY(fd fd_io_uring, opcode const[IORING_UNREGISTER_PERSONALITY], arg const[0], nr_args ioring_personality_id)

# The mmap'ed area for SQ and CQ rings are really the same -- the difference is
# accounted for with the usage of offsets.
mmap$IORING_OFF_SQ_RING(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd_io_uring, offset const[IORING_OFF_SQ_RING]) ring_ptr
mmap$IORING_OFF_CQ_RING(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd_io_uring, offset const[IORING_OFF_CQ_RING]) ring_ptr
mmap$IORING_OFF_SQES(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd_io_uring, offset const[IORING_OFF_SQES]) sqes_ptr

# If no flags are specified(0), the io_uring instance is setup for interrupt driven IO.
io_uring_setup_flags = 0, IORING_SETUP_IOPOLL, IORING_SETUP_SQPOLL, IORING_SETUP_SQ_AFF, IORING_SETUP_CQSIZE, IORING_SETUP_CLAMP, IORING_SETUP_ATTACH_WQ
io_uring_enter_flags = IORING_ENTER_GETEVENTS, IORING_ENTER_SQ_WAKEUP
_ = __NR_mmap2

# Once an io_uring is set up by calling io_uring_setup, the offsets to the member fields
# to be used on the mmap'ed area are set in structs io_sqring_offsets and io_cqring_offsets.
# Except io_sqring_offsets.array, the offsets are static while all depend on how struct io_rings
# is organized in code. The offsets can be marked as resources in syzkaller descriptions but
# this makes it difficult to generate correct programs by the fuzzer. Thus, the offsets are
# hard-coded here (and in the executor).
define SQ_HEAD_OFFSET	0
define SQ_TAIL_OFFSET	64
define SQ_RING_MASK_OFFSET	256
define SQ_RING_ENTRIES_OFFSET	264
define SQ_FLAGS_OFFSET	276
define SQ_DROPPED_OFFSET	272
define CQ_HEAD_OFFSET	128
define CQ_TAIL_OFFSET	192
define CQ_RING_MASK_OFFSET	260
define CQ_RING_ENTRIES_OFFSET	268
define CQ_RING_OVERFLOW_OFFSET	284
define CQ_FLAGS_OFFSET	280

# Notice all offsets are pointing to uint32 values. This is assumed for the
io_uring_offsets = SQ_HEAD_OFFSET, SQ_TAIL_OFFSET, SQ_RING_MASK_OFFSET, SQ_RING_ENTRIES_OFFSET, SQ_FLAGS_OFFSET, SQ_DROPPED_OFFSET, CQ_HEAD_OFFSET, CQ_TAIL_OFFSET, CQ_RING_MASK_OFFSET, CQ_RING_ENTRIES_OFFSET, CQ_RING_OVERFLOW_OFFSET, CQ_FLAGS_OFFSET

# Also, all values are int32, thus, set nbytes to 4.
syz_memcpy_off$IO_URING_METADATA_GENERIC(ring_ptr ring_ptr, off flags[io_uring_offsets], src ptr[in, int32], src_off const[0], nbytes const[4])

# The flags available are: IORING_SQ_NEED_WAKEUP (1) for sq, IORING_CQ_EVENTFD_DISABLED (1) for cq. Use int32[0:1] to represent possible values.
io_uring_flags_offsets = SQ_FLAGS_OFFSET, CQ_FLAGS_OFFSET
syz_memcpy_off$IO_URING_METADATA_FLAGS(ring_ptr ring_ptr, flag_off flags[io_uring_flags_offsets], src ptr[in, int32[0:1]], src_off const[0], nbytes const[4])

io_uring_probe {
	last_op	const[0, int8]
	ops_len	const[0, int8]
	resv	const[0, int16]
	resv2	array[const[0, int32], 3]
	ops	array[io_uring_probe_op, 0:IORING_OP_LAST]
}

io_uring_probe_op {
	op	const[0, int8]
	resv	const[0, int8]
	flags	const[0, int16]
	resv2	const[0, int32]
}

io_uring_files_update {
	offset	int32
	resv	const[0, int32]
	fds	ptr64[in, array[fd]]
}

io_uring_params {
	sq_entries	int32	(out)
	cq_entries	int32[0:IORING_MAX_CQ_ENTRIES]	(inout)
	flags		flags[io_uring_setup_flags, int32]	(in)
	sq_thread_cpu	int32[0:3]	(in)
	sq_thread_idle	int32[0:1000]	(in)
	features	int32	(out)
	wq_fd		fd_io_uring[opt]	(in)
	resv		array[const[0, int32], 3]
# We don't really use them (they are hard-coded). Thus, just pass some memory region of their size.
# TODO: Now that per-field directions is supported, can we avoid using hard-coded values for offsets?
	sq_off		array[int32, 10]	(out)
	cq_off		array[int32, 10]	(out)
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Descriptions for sq_ring and cq_ring manipulation # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Retrieve the cqe at the head of the cq_ring and advance the head. The only meaningful
# resource contained within a cqe is by the completion of openat or openat2 calls,
# which produce fd. If that is the case, returns the return value of those. Otherwise,
# for other operations, returns an invalid fd (-1).
syz_io_uring_complete(ring_ptr ring_ptr) fd

# Submit sqe into the sq_ring
syz_io_uring_submit(ring_ptr ring_ptr, sqes_ptr sqes_ptr, sqe ptr[in, io_uring_sqe_u], sqes_index int32)

io_uring_sqe_u [
	IORING_OP_NOP			io_uring_sqe$nop
	IORING_OP_READV			io_uring_sqe_readv
	IORING_OP_WRITEV		io_uring_sqe$writev
	IORING_OP_FSYNC			io_uring_sqe$fsync
	IORING_OP_READ_FIXED		io_uring_sqe$read_fixed
	IORING_OP_WRITE_FIXED		io_uring_sqe$write_fixed
	IORING_OP_POLL_ADD		io_uring_sqe$poll_add
	IORING_OP_POLL_REMOVE		io_uring_sqe$poll_remove
	IORING_OP_SYNC_FILE_RANGE	io_uring_sqe$sync_file_range
	IORING_OP_SENDMSG		io_uring_sqe$sendmsg
	IORING_OP_RECVMSG		io_uring_sqe$recvmsg
	IORING_OP_TIMEOUT		io_uring_sqe$timeout
	IORING_OP_TIMEOUT_REMOVE	io_uring_sqe$timeout_remove
	IORING_OP_ACCEPT		io_uring_sqe$accept
	IORING_OP_ASYNC_CANCEL		io_uring_sqe$async_cancel
	IORING_OP_LINK_TIMEOUT		io_uring_sqe$link_timeout
	IORING_OP_CONNECT		io_uring_sqe$connect
	IORING_OP_FALLOCATE		io_uring_sqe$fallocate
	IORING_OP_OPENAT		io_uring_sqe$openat
	IORING_OP_CLOSE			io_uring_sqe$close
	IORING_OP_FILES_UPDATE		io_uring_sqe$files_update
	IORING_OP_STATX			io_uring_sqe$statx
	IORING_OP_READ			io_uring_sqe_read
	IORING_OP_WRITE			io_uring_sqe$write
	IORING_OP_FADVISE		io_uring_sqe$fadvise
	IORING_OP_MADVISE		io_uring_sqe$madvise
	IORING_OP_SEND			io_uring_sqe$send
	IORING_OP_RECV			io_uring_sqe_recv
	IORING_OP_OPENAT2		io_uring_sqe$openat2
	IORING_OP_EPOLL_CTL		io_uring_sqe_epoll_ctl
	IORING_OP_SPLICE		io_uring_sqe$splice
	IORING_OP_PROVIDE_BUFFERS	io_uring_sqe$provide_buffers
	IORING_OP_REMOVE_BUFFERS	io_uring_sqe$remove_buffers
	IORING_OP_TEE			io_uring_sqe$tee
]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# io_uring submission queue entry (io_uring_sqe) descriptions # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

#
# sqe type template
#

type io_uring_sqe[OP, IOPRIO, FD, OFF, ADDR, LEN, MISC_FLAGS, USER_DATA, MISC] {
	opcode		const[OP, int8]
	flags		flags[iosqe_flags, int8]
	ioprio		IOPRIO
	fd		FD
	off		OFF
	addr		ADDR
	len		LEN
	misc_flags	MISC_FLAGS
	user_data	flags[USER_DATA, int64]
# This is a union of different possibilites with a padding at the end.
	misc		MISC
} [size[SIZEOF_IO_URING_SQE]]

define SIZEOF_IO_URING_SQE	64

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

#
# Instantiation of sqes for each op
#

type io_uring_sqe$nop io_uring_sqe[IORING_OP_NOP, const[0, int16], const[0, int32], const[0, int64], const[0, int64], const[0, int32], const[0, int32], zero_flag, array[const[0, int64], 3]]

io_uring_sqe_readv [
	pass_iovec		io_uring_sqe[IORING_OP_READV, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], ptr[in, array[iovec_out]], len[addr, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, personality_only_misc]
	use_registered_buffer	io_uring_sqe[IORING_OP_READV, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], const[0, int64], const[0, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, buf_index_personality_misc]
]

type io_uring_sqe$writev io_uring_sqe[IORING_OP_WRITEV, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], ptr[in, array[iovec_in]], len[addr, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, buf_index_personality_misc]
type io_uring_sqe$fsync io_uring_sqe[IORING_OP_FSYNC, const[0, int16], fd_or_fixed_fd_index, const[0, int64], const[0, int64], const[0, int32], flags[io_uring_fsync_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$read_fixed io_uring_sqe[IORING_OP_READ_FIXED, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], int64, int32, flags[rwf_flags, int32], sqe_user_data_not_openat, buf_index_personality_misc]
type io_uring_sqe$write_fixed io_uring_sqe[IORING_OP_WRITE_FIXED, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], int64, int32, flags[rwf_flags, int32], sqe_user_data_not_openat, buf_index_personality_misc]
type io_uring_sqe$poll_add io_uring_sqe[IORING_OP_POLL_ADD, const[0, int16], fd_or_fixed_fd_index, const[0, int64], const[0, int64], const[0, int32], io_uring_sqe_poll_add_misc_flags, sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$poll_remove io_uring_sqe[IORING_OP_POLL_REMOVE, const[0, int16], const[0, int32], const[0, int64], flags[sqe_user_data, int64], const[0, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$sync_file_range io_uring_sqe[IORING_OP_SYNC_FILE_RANGE, const[0, int16], fd_or_fixed_fd_index, fileoff[int64], const[0, int64], int32, flags[sync_file_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$sendmsg io_uring_sqe[IORING_OP_SENDMSG, const[0, int16], sock, const[0, int64], ptr[in, send_msghdr], const[0, int32], flags[send_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$recvmsg io_uring_sqe[IORING_OP_RECVMSG, const[0, int16], sock, const[0, int64], ptr[inout, recv_msghdr], const[0, int32], flags[recv_flags, int32], sqe_user_data_not_openat, buf_group_personality_misc]
type io_uring_sqe$timeout io_uring_sqe[IORING_OP_TIMEOUT, const[0, int16], const[0, int32], io_uring_timeout_completion_event_count, ptr[in, timespec], const[1, int32], flags[io_uring_timeout_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$timeout_remove io_uring_sqe[IORING_OP_TIMEOUT_REMOVE, const[0, int16], const[0, int32], const[0, int64], flags[sqe_user_data, int64], const[0, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$accept io_uring_sqe[IORING_OP_ACCEPT, const[0, int16], sock, ptr[inout, len[addr, int32]], ptr[out, sockaddr_storage, opt], const[0, int32], flags[accept_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$async_cancel io_uring_sqe[IORING_OP_ASYNC_CANCEL, const[0, int16], const[0, int32], const[0, int64], flags[sqe_user_data, int64], const[0, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$link_timeout io_uring_sqe[IORING_OP_LINK_TIMEOUT, const[0, int16], const[0, int32], const[0, int64], ptr[in, timespec], const[1, int32], flags[io_uring_timeout_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$connect io_uring_sqe[IORING_OP_CONNECT, const[0, int16], sock, len[addr, int32], ptr[in, sockaddr_storage], const[0, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$fallocate io_uring_sqe[IORING_OP_FALLOCATE, const[0, int16], fd_or_fixed_fd_index, fileoff[int64], const[0, int64], int32, const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$openat io_uring_sqe[IORING_OP_OPENAT, const[0, int16], fd_dir[opt], const[0, int64], ptr[in, filename], flags[open_mode, int32], flags[open_flags, int32], sqe_user_data_openat, personality_only_misc]
type io_uring_sqe$close io_uring_sqe[IORING_OP_CLOSE, const[0, int16], fd, const[0, int64], const[0, int64], const[0, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$files_update io_uring_sqe[IORING_OP_FILES_UPDATE, const[0, int16], const[0, int32], fileoff[int64], ptr[in, array[fd]], len[addr, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$statx io_uring_sqe[IORING_OP_STATX, const[0, int16], fd_dir[opt], ptr[out, statx], ptr[in, filename], flags[statx_mask, int32], flags[statx_flags, int32], sqe_user_data_not_openat, personality_only_misc]

io_uring_sqe_read [
	pass_buffer		io_uring_sqe[IORING_OP_READ, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], buffer[out], bytesize[addr, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, personality_only_misc]
	use_registered_buffer	io_uring_sqe[IORING_OP_READ, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], const[0, int64], const[0, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, buf_index_personality_misc]
]

type io_uring_sqe$write io_uring_sqe[IORING_OP_WRITE, flags[ioprio_priorities, int16], fd_or_fixed_fd_index, fileoff[int64], buffer[in], bytesize[addr, int32], flags[rwf_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$fadvise io_uring_sqe[IORING_OP_FADVISE, const[0, int16], fd_or_fixed_fd_index, fileoff[int64], const[0, int64], int32, flags[fadvise_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$madvise io_uring_sqe[IORING_OP_MADVISE, const[0, int16], const[0, int32], const[0, int64], vma, len[addr, int32], flags[madvise_flags, int32], sqe_user_data_not_openat, personality_only_misc]
type io_uring_sqe$send io_uring_sqe[IORING_OP_SEND, const[0, int16], sock, const[0, int64], buffer[in], len[addr, int32], flags[send_flags, int32], sqe_user_data_not_openat, personality_only_misc]

io_uring_sqe_recv [
	pass_buffer		io_uring_sqe[IORING_OP_RECV, const[0, int16], sock, const[0, int64], buffer[inout], len[addr, int32], flags[recv_flags, int32], sqe_user_data_not_openat, personality_only_misc]
	use_registered_buffer	io_uring_sqe[IORING_OP_RECV, const[0, int16], sock, const[0, int64], const[0, int64], const[0, int32], flags[recv_flags, int32], sqe_user_data_not_openat, buf_group_personality_misc]
]

type io_uring_sqe$openat2 io_uring_sqe[IORING_OP_OPENAT2, const[0, int16], fd_dir[opt], ptr[in, open_how], ptr[in, filename], bytesize[off, int32], const[0, int32], sqe_user_data_openat, personality_only_misc]
type io_uring_sqe$epoll_ctl_t[EPOLL_OP, EPOLL_EVENTS] io_uring_sqe[IORING_OP_EPOLL_CTL, const[0, int16], fd_epoll, EPOLL_EVENTS, fd, const[EPOLL_OP, int32], const[0, int32], sqe_user_data_not_openat, personality_only_misc]

io_uring_sqe_epoll_ctl [
	add	io_uring_sqe$epoll_ctl_t[EPOLL_CTL_ADD, ptr[in, epoll_event]]
	del	io_uring_sqe$epoll_ctl_t[EPOLL_CTL_DEL, const[0, int64]]
	mod	io_uring_sqe$epoll_ctl_t[EPOLL_CTL_MOD, ptr[in, epoll_event]]
]

type io_uring_sqe$splice io_uring_sqe[IORING_OP_SPLICE, const[0, int16], fd_or_fixed_fd_index, fileoff[int64], io_uring_sqe_splice_off_in, int32, flags[splice_flags, int32], sqe_user_data_not_openat, io_uring_sqe_splice_misc]
type io_uring_sqe$provide_buffers io_uring_sqe[IORING_OP_PROVIDE_BUFFERS, const[0, int16], int32, io_uring_bid[int64], buffer[in], int32, const[0, int32], sqe_user_data_not_openat, buf_group_personality_misc]
type io_uring_sqe$remove_buffers io_uring_sqe[IORING_OP_PROVIDE_BUFFERS, const[0, int16], int32, const[0, int64], const[0, int64], const[0, int32], const[0, int32], sqe_user_data_not_openat, buf_group_personality_misc]
type io_uring_sqe$tee io_uring_sqe[IORING_OP_TEE, const[0, int16], fd_or_fixed_fd_index, const[0, int64], const[0, int64], int32, flags[splice_flags, int32], sqe_user_data_not_openat, io_uring_sqe_tee_misc]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

#
# Flags, enumerations, and misc fields of sqe ops
#

iosqe_flags = IOSQE_IO_DRAIN_BIT, IOSQE_IO_LINK_BIT, IOSQE_IO_HARDLINK_BIT, IOSQE_ASYNC_BIT, IOSQE_BUFFER_SELECT_BIT, IOSQE_FIXED_FILE_BIT

fd_or_fixed_fd_index [
	fd		fd
# Use the registered files (io_uring_register$IORING_REGISTER_FILES) when IOSQE_FIXED_FILE_BIT is set in sqe.
# To ease collisions, limit the indices.
	fd_index	int32[0:10]
]

# 0 for normal file integrity sync, IORING_FSYNC_DATASYNC to provide data sync only semantics
io_uring_fsync_flags = 0, IORING_FSYNC_DATASYNC

# 0 for relative, IORING_TIMEOUT_ABS for absolute timeout value
io_uring_timeout_flags = 0, IORING_TIMEOUT_ABS

# The timeout condition is met when either the specific timeout expries, or the
# specified number of events have completed. If not set, defaults to 1. Use a
# limited range to allow utilization of this value to meet timeout condition besides
# the timeout expiration.
type io_uring_timeout_completion_event_count int64[0:10]

# An already issued request can be attempted to be cancelled using ASYNC_CANCEL
# operation. This operation identifies the operations using what's passed as
# with user_data in their sqe. To ease collisions of ASYNC_CANCEL operation with
# already submitted ones, use a limited range of values for user_data field.
# Among all operations that can be achieved by submitting to the io_uring, only
# openat and openat2 returns a useful resource (fd) that we can use for other
# systemcalls. The resulting fds are returned within io_uring_cqe.res. The only way
# to identify cqes for those operations is to keep track of their user data. Thus,
# use a seperate set of sqe_user_data range for openat and openat2.
sqe_user_data_not_openat = 0, 1
sqe_user_data_openat = 0x12345, 0x23456
sqe_user_data = 0, 1, 0x12345, 0x23456

# The buffer id (bid) and the buffer group id (bgid) are registered using
# IORING_OP_PROVIDE_BUFFERS. Use the ids in a limited range to ease collisions
# with other operations.
type io_uring_bid[T] T[0:3]
type io_uring_bgid[T] T[0:3]

zero_flag = 0

io_uring_sqe_poll_add_misc_flags {
	misc_flags		flags[pollfd_events, int16]
# 2 bytes of padding to fill what is left from the union of flags
	fill_flags_union	const[0, int16]
}

io_uring_sqe_splice_off_in {
	splice_off_in_unused	const[0, int32]
	splice_off_in		fd
}

# Descriptions for MISC field of io_uring_sqe. The content for most are common
# while there are a few specials.

personality_only_misc {
	buf_index_unused	const[0, int16]
	ioring_personality_id	ioring_personality_id[opt]
	pad_unused		array[const[0, int8], 20]
}

buf_index_personality_misc {
	buf_index		io_uring_bid[int16]
	ioring_personality_id	ioring_personality_id[opt]
	pad_unused		array[const[0, int8], 20]
}

buf_group_personality_misc {
	buf_group		io_uring_bgid[int16]
	ioring_personality_id	ioring_personality_id[opt]
	pad_unused		array[const[0, int8], 20]
}

io_uring_sqe_splice_misc {
	buf_unused		const[0, int16]
	ioring_personality_id	ioring_personality_id[opt]
	splice_fd_in		fd
	pad_unused		array[const[0, int64], 2]
}

io_uring_sqe_tee_misc {
	buf_unused		const[0, int16]
	ioring_personality_id	ioring_personality_id[opt]
	splice_fd_in		fd
	pad_unused		array[const[0, int64], 2]
}