Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/io_uring/cmd_net.c
29264 views
1
#include <asm/ioctls.h>
2
#include <linux/io_uring/net.h>
3
#include <linux/errqueue.h>
4
#include <net/sock.h>
5
6
#include "uring_cmd.h"
7
#include "io_uring.h"
8
9
static inline int io_uring_cmd_getsockopt(struct socket *sock,
10
struct io_uring_cmd *cmd,
11
unsigned int issue_flags)
12
{
13
const struct io_uring_sqe *sqe = cmd->sqe;
14
bool compat = !!(issue_flags & IO_URING_F_COMPAT);
15
int optlen, optname, level, err;
16
void __user *optval;
17
18
level = READ_ONCE(sqe->level);
19
if (level != SOL_SOCKET)
20
return -EOPNOTSUPP;
21
22
optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
23
optname = READ_ONCE(sqe->optname);
24
optlen = READ_ONCE(sqe->optlen);
25
26
err = do_sock_getsockopt(sock, compat, level, optname,
27
USER_SOCKPTR(optval),
28
KERNEL_SOCKPTR(&optlen));
29
if (err)
30
return err;
31
32
/* On success, return optlen */
33
return optlen;
34
}
35
36
static inline int io_uring_cmd_setsockopt(struct socket *sock,
37
struct io_uring_cmd *cmd,
38
unsigned int issue_flags)
39
{
40
const struct io_uring_sqe *sqe = cmd->sqe;
41
bool compat = !!(issue_flags & IO_URING_F_COMPAT);
42
int optname, optlen, level;
43
void __user *optval;
44
sockptr_t optval_s;
45
46
optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
47
optname = READ_ONCE(sqe->optname);
48
optlen = READ_ONCE(sqe->optlen);
49
level = READ_ONCE(sqe->level);
50
optval_s = USER_SOCKPTR(optval);
51
52
return do_sock_setsockopt(sock, compat, level, optname, optval_s,
53
optlen);
54
}
55
56
static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk,
57
struct sk_buff *skb, unsigned issue_flags)
58
{
59
struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
60
struct io_uring_cqe cqe[2];
61
struct io_timespec *iots;
62
struct timespec64 ts;
63
u32 tstype, tskey;
64
int ret;
65
66
BUILD_BUG_ON(sizeof(struct io_uring_cqe) != sizeof(struct io_timespec));
67
68
ret = skb_get_tx_timestamp(skb, sk, &ts);
69
if (ret < 0)
70
return false;
71
72
tskey = serr->ee.ee_data;
73
tstype = serr->ee.ee_info;
74
75
cqe->user_data = 0;
76
cqe->res = tskey;
77
cqe->flags = IORING_CQE_F_MORE | ctx_cqe32_flags(cmd_to_io_kiocb(cmd)->ctx);
78
cqe->flags |= tstype << IORING_TIMESTAMP_TYPE_SHIFT;
79
if (ret == SOF_TIMESTAMPING_TX_HARDWARE)
80
cqe->flags |= IORING_CQE_F_TSTAMP_HW;
81
82
iots = (struct io_timespec *)&cqe[1];
83
iots->tv_sec = ts.tv_sec;
84
iots->tv_nsec = ts.tv_nsec;
85
return io_uring_cmd_post_mshot_cqe32(cmd, issue_flags, cqe);
86
}
87
88
static int io_uring_cmd_timestamp(struct socket *sock,
89
struct io_uring_cmd *cmd,
90
unsigned int issue_flags)
91
{
92
struct sock *sk = sock->sk;
93
struct sk_buff_head *q = &sk->sk_error_queue;
94
struct sk_buff *skb, *tmp;
95
struct sk_buff_head list;
96
int ret;
97
98
if (!(issue_flags & IO_URING_F_CQE32))
99
return -EINVAL;
100
ret = io_cmd_poll_multishot(cmd, issue_flags, EPOLLERR);
101
if (unlikely(ret))
102
return ret;
103
104
if (skb_queue_empty_lockless(q))
105
return -EAGAIN;
106
__skb_queue_head_init(&list);
107
108
scoped_guard(spinlock_irq, &q->lock) {
109
skb_queue_walk_safe(q, skb, tmp) {
110
/* don't support skbs with payload */
111
if (!skb_has_tx_timestamp(skb, sk) || skb->len)
112
continue;
113
__skb_unlink(skb, q);
114
__skb_queue_tail(&list, skb);
115
}
116
}
117
118
while (1) {
119
skb = skb_peek(&list);
120
if (!skb)
121
break;
122
if (!io_process_timestamp_skb(cmd, sk, skb, issue_flags))
123
break;
124
__skb_dequeue(&list);
125
consume_skb(skb);
126
}
127
128
if (!unlikely(skb_queue_empty(&list))) {
129
scoped_guard(spinlock_irqsave, &q->lock)
130
skb_queue_splice(q, &list);
131
}
132
return -EAGAIN;
133
}
134
135
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
136
{
137
struct socket *sock = cmd->file->private_data;
138
struct sock *sk = sock->sk;
139
struct proto *prot = READ_ONCE(sk->sk_prot);
140
int ret, arg = 0;
141
142
if (!prot || !prot->ioctl)
143
return -EOPNOTSUPP;
144
145
switch (cmd->cmd_op) {
146
case SOCKET_URING_OP_SIOCINQ:
147
ret = prot->ioctl(sk, SIOCINQ, &arg);
148
if (ret)
149
return ret;
150
return arg;
151
case SOCKET_URING_OP_SIOCOUTQ:
152
ret = prot->ioctl(sk, SIOCOUTQ, &arg);
153
if (ret)
154
return ret;
155
return arg;
156
case SOCKET_URING_OP_GETSOCKOPT:
157
return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
158
case SOCKET_URING_OP_SETSOCKOPT:
159
return io_uring_cmd_setsockopt(sock, cmd, issue_flags);
160
case SOCKET_URING_OP_TX_TIMESTAMP:
161
return io_uring_cmd_timestamp(sock, cmd, issue_flags);
162
default:
163
return -EOPNOTSUPP;
164
}
165
}
166
EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
167
168