11#include <asm/ioctls.h>
22#include <linux/io_uring/net.h>
3+ #include <linux/errqueue.h>
34#include <net/sock.h>
45
56#include "uring_cmd.h"
@@ -51,6 +52,85 @@ static inline int io_uring_cmd_setsockopt(struct socket *sock,
5152 optlen );
5253}
5354
55+ static bool io_process_timestamp_skb (struct io_uring_cmd * cmd , struct sock * sk ,
56+ struct sk_buff * skb , unsigned issue_flags )
57+ {
58+ struct sock_exterr_skb * serr = SKB_EXT_ERR (skb );
59+ struct io_uring_cqe cqe [2 ];
60+ struct io_timespec * iots ;
61+ struct timespec64 ts ;
62+ u32 tstype , tskey ;
63+ int ret ;
64+
65+ BUILD_BUG_ON (sizeof (struct io_uring_cqe ) != sizeof (struct io_timespec ));
66+
67+ ret = skb_get_tx_timestamp (skb , sk , & ts );
68+ if (ret < 0 )
69+ return false;
70+
71+ tskey = serr -> ee .ee_data ;
72+ tstype = serr -> ee .ee_info ;
73+
74+ cqe -> user_data = 0 ;
75+ cqe -> res = tskey ;
76+ cqe -> flags = IORING_CQE_F_MORE ;
77+ cqe -> flags |= tstype << IORING_TIMESTAMP_TYPE_SHIFT ;
78+ if (ret == SOF_TIMESTAMPING_TX_HARDWARE )
79+ cqe -> flags |= IORING_CQE_F_TSTAMP_HW ;
80+
81+ iots = (struct io_timespec * )& cqe [1 ];
82+ iots -> tv_sec = ts .tv_sec ;
83+ iots -> tv_nsec = ts .tv_nsec ;
84+ return io_uring_cmd_post_mshot_cqe32 (cmd , issue_flags , cqe );
85+ }
86+
87+ static int io_uring_cmd_timestamp (struct socket * sock ,
88+ struct io_uring_cmd * cmd ,
89+ unsigned int issue_flags )
90+ {
91+ struct sock * sk = sock -> sk ;
92+ struct sk_buff_head * q = & sk -> sk_error_queue ;
93+ struct sk_buff * skb , * tmp ;
94+ struct sk_buff_head list ;
95+ int ret ;
96+
97+ if (!(issue_flags & IO_URING_F_CQE32 ))
98+ return - EINVAL ;
99+ ret = io_cmd_poll_multishot (cmd , issue_flags , EPOLLERR );
100+ if (unlikely (ret ))
101+ return ret ;
102+
103+ if (skb_queue_empty_lockless (q ))
104+ return - EAGAIN ;
105+ __skb_queue_head_init (& list );
106+
107+ scoped_guard (spinlock_irq , & q -> lock ) {
108+ skb_queue_walk_safe (q , skb , tmp ) {
109+ /* don't support skbs with payload */
110+ if (!skb_has_tx_timestamp (skb , sk ) || skb -> len )
111+ continue ;
112+ __skb_unlink (skb , q );
113+ __skb_queue_tail (& list , skb );
114+ }
115+ }
116+
117+ while (1 ) {
118+ skb = skb_peek (& list );
119+ if (!skb )
120+ break ;
121+ if (!io_process_timestamp_skb (cmd , sk , skb , issue_flags ))
122+ break ;
123+ __skb_dequeue (& list );
124+ consume_skb (skb );
125+ }
126+
127+ if (!unlikely (skb_queue_empty (& list ))) {
128+ scoped_guard (spinlock_irqsave , & q -> lock )
129+ skb_queue_splice (q , & list );
130+ }
131+ return - EAGAIN ;
132+ }
133+
54134int io_uring_cmd_sock (struct io_uring_cmd * cmd , unsigned int issue_flags )
55135{
56136 struct socket * sock = cmd -> file -> private_data ;
@@ -76,6 +156,8 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
76156 return io_uring_cmd_getsockopt (sock , cmd , issue_flags );
77157 case SOCKET_URING_OP_SETSOCKOPT :
78158 return io_uring_cmd_setsockopt (sock , cmd , issue_flags );
159+ case SOCKET_URING_OP_TX_TIMESTAMP :
160+ return io_uring_cmd_timestamp (sock , cmd , issue_flags );
79161 default :
80162 return - EOPNOTSUPP ;
81163 }
0 commit comments