2019-06-04 11:11:15 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-07-28 17:36:33 +03:00
/*
* virtio transport for vsock
*
* Copyright ( C ) 2013 - 2015 Red Hat , Inc .
* Author : Asias He < asias @ redhat . com >
* Stefan Hajnoczi < stefanha @ redhat . com >
*
* Some of the code is take from Gerd Hoffmann < kraxel @ redhat . com > ' s
* early virtio - vsock proof - of - concept bits .
*/
# include <linux/spinlock.h>
# include <linux/module.h>
# include <linux/list.h>
# include <linux/atomic.h>
# include <linux/virtio.h>
# include <linux/virtio_ids.h>
# include <linux/virtio_config.h>
# include <linux/virtio_vsock.h>
# include <net/sock.h>
# include <linux/mutex.h>
# include <net/af_vsock.h>
static struct workqueue_struct * virtio_vsock_workqueue ;
2020-07-10 15:12:43 +03:00
static struct virtio_vsock __rcu * the_virtio_vsock ;
2016-07-28 17:36:33 +03:00
static DEFINE_MUTEX ( the_virtio_vsock_mutex ) ; /* protects the_virtio_vsock */
2022-03-11 05:00:16 +03:00
static struct virtio_transport virtio_transport ; /* forward declaration */
2016-07-28 17:36:33 +03:00
struct virtio_vsock {
struct virtio_device * vdev ;
struct virtqueue * vqs [ VSOCK_VQ_MAX ] ;
/* Virtqueue processing is deferred to a workqueue */
struct work_struct tx_work ;
struct work_struct rx_work ;
struct work_struct event_work ;
/* The following fields are protected by tx_lock. vqs[VSOCK_VQ_TX]
* must be accessed with tx_lock held .
*/
struct mutex tx_lock ;
2019-07-05 14:04:53 +03:00
bool tx_run ;
2016-07-28 17:36:33 +03:00
struct work_struct send_pkt_work ;
2023-01-14 01:21:37 +03:00
struct sk_buff_head send_pkt_queue ;
2016-07-28 17:36:33 +03:00
atomic_t queued_replies ;
/* The following fields are protected by rx_lock. vqs[VSOCK_VQ_RX]
* must be accessed with rx_lock held .
*/
struct mutex rx_lock ;
2019-07-05 14:04:53 +03:00
bool rx_run ;
2016-07-28 17:36:33 +03:00
int rx_buf_nr ;
int rx_buf_max_nr ;
/* The following fields are protected by event_lock.
* vqs [ VSOCK_VQ_EVENT ] must be accessed with event_lock held .
*/
struct mutex event_lock ;
2019-07-05 14:04:53 +03:00
bool event_run ;
2016-07-28 17:36:33 +03:00
struct virtio_vsock_event event_list [ 8 ] ;
u32 guest_cid ;
2021-06-11 14:13:22 +03:00
bool seqpacket_allow ;
2023-09-16 16:09:16 +03:00
/* These fields are used only in tx path in function
* ' virtio_transport_send_pkt_work ( ) ' , so to save
* stack space in it , place both of them here . Each
* pointer from ' out_sgs ' points to the corresponding
* element in ' out_bufs ' - this is initialized in
* ' virtio_vsock_probe ( ) ' . Both fields are protected
* by ' tx_lock ' . + 1 is needed for packet header .
*/
struct scatterlist * out_sgs [ MAX_SKB_FRAGS + 1 ] ;
struct scatterlist out_bufs [ MAX_SKB_FRAGS + 1 ] ;
2016-07-28 17:36:33 +03:00
} ;
static u32 virtio_transport_get_local_cid ( void )
{
2019-07-05 14:04:52 +03:00
struct virtio_vsock * vsock ;
u32 ret ;
2016-07-28 17:36:33 +03:00
2019-07-05 14:04:52 +03:00
rcu_read_lock ( ) ;
vsock = rcu_dereference ( the_virtio_vsock ) ;
if ( ! vsock ) {
ret = VMADDR_CID_ANY ;
goto out_rcu ;
}
2019-02-01 14:42:06 +03:00
2019-07-05 14:04:52 +03:00
ret = vsock - > guest_cid ;
out_rcu :
rcu_read_unlock ( ) ;
return ret ;
2016-07-28 17:36:33 +03:00
}
static void
virtio_transport_send_pkt_work ( struct work_struct * work )
{
struct virtio_vsock * vsock =
container_of ( work , struct virtio_vsock , send_pkt_work ) ;
struct virtqueue * vq ;
bool added = false ;
bool restart_rx = false ;
mutex_lock ( & vsock - > tx_lock ) ;
2019-07-05 14:04:53 +03:00
if ( ! vsock - > tx_run )
goto out ;
2016-07-28 17:36:33 +03:00
vq = vsock - > vqs [ VSOCK_VQ_TX ] ;
for ( ; ; ) {
int ret , in_sg = 0 , out_sg = 0 ;
2023-09-16 16:09:16 +03:00
struct scatterlist * * sgs ;
2023-01-14 01:21:37 +03:00
struct sk_buff * skb ;
2016-07-28 17:36:33 +03:00
bool reply ;
2023-01-14 01:21:37 +03:00
skb = virtio_vsock_skb_dequeue ( & vsock - > send_pkt_queue ) ;
if ( ! skb )
2016-07-28 17:36:33 +03:00
break ;
2023-01-14 01:21:37 +03:00
virtio_transport_deliver_tap_pkt ( skb ) ;
reply = virtio_vsock_skb_reply ( skb ) ;
2023-09-16 16:09:16 +03:00
sgs = vsock - > out_sgs ;
sg_init_one ( sgs [ out_sg ] , virtio_vsock_hdr ( skb ) ,
sizeof ( * virtio_vsock_hdr ( skb ) ) ) ;
out_sg + + ;
if ( ! skb_is_nonlinear ( skb ) ) {
if ( skb - > len > 0 ) {
sg_init_one ( sgs [ out_sg ] , skb - > data , skb - > len ) ;
out_sg + + ;
}
} else {
struct skb_shared_info * si ;
int i ;
/* If skb is nonlinear, then its buffer must contain
* only header and nothing more . Data is stored in
* the fragged part .
*/
WARN_ON_ONCE ( skb_headroom ( skb ) ! = sizeof ( * virtio_vsock_hdr ( skb ) ) ) ;
si = skb_shinfo ( skb ) ;
for ( i = 0 ; i < si - > nr_frags ; i + + ) {
skb_frag_t * skb_frag = & si - > frags [ i ] ;
void * va ;
/* We will use 'page_to_virt()' for the userspace page
* here , because virtio or dma - mapping layers will call
* ' virt_to_phys ( ) ' later to fill the buffer descriptor .
* We don ' t touch memory at " virtual " address of this page .
*/
va = page_to_virt ( skb_frag - > bv_page ) ;
sg_init_one ( sgs [ out_sg ] ,
va + skb_frag - > bv_offset ,
skb_frag - > bv_len ) ;
out_sg + + ;
}
2016-07-28 17:36:33 +03:00
}
2023-01-14 01:21:37 +03:00
ret = virtqueue_add_sgs ( vq , sgs , out_sg , in_sg , skb , GFP_KERNEL ) ;
2016-08-10 18:24:34 +03:00
/* Usually this means that there is no more space available in
* the vq
*/
2016-07-28 17:36:33 +03:00
if ( ret < 0 ) {
2023-01-14 01:21:37 +03:00
virtio_vsock_skb_queue_head ( & vsock - > send_pkt_queue , skb ) ;
2016-07-28 17:36:33 +03:00
break ;
}
if ( reply ) {
struct virtqueue * rx_vq = vsock - > vqs [ VSOCK_VQ_RX ] ;
int val ;
val = atomic_dec_return ( & vsock - > queued_replies ) ;
/* Do we now have resources to resume rx processing? */
if ( val + 1 = = virtqueue_get_vring_size ( rx_vq ) )
restart_rx = true ;
}
added = true ;
}
if ( added )
virtqueue_kick ( vq ) ;
2019-07-05 14:04:53 +03:00
out :
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > tx_lock ) ;
if ( restart_rx )
queue_work ( virtio_vsock_workqueue , & vsock - > rx_work ) ;
}
static int
2023-01-14 01:21:37 +03:00
virtio_transport_send_pkt ( struct sk_buff * skb )
2016-07-28 17:36:33 +03:00
{
2023-01-14 01:21:37 +03:00
struct virtio_vsock_hdr * hdr ;
2016-07-28 17:36:33 +03:00
struct virtio_vsock * vsock ;
2023-01-14 01:21:37 +03:00
int len = skb - > len ;
hdr = virtio_vsock_hdr ( skb ) ;
2016-07-28 17:36:33 +03:00
2019-07-05 14:04:52 +03:00
rcu_read_lock ( ) ;
vsock = rcu_dereference ( the_virtio_vsock ) ;
2016-07-28 17:36:33 +03:00
if ( ! vsock ) {
2023-01-14 01:21:37 +03:00
kfree_skb ( skb ) ;
2019-07-05 14:04:52 +03:00
len = - ENODEV ;
goto out_rcu ;
2016-07-28 17:36:33 +03:00
}
2023-01-14 01:21:37 +03:00
if ( le64_to_cpu ( hdr - > dst_cid ) = = vsock - > guest_cid ) {
kfree_skb ( skb ) ;
2019-12-10 13:43:07 +03:00
len = - ENODEV ;
2019-07-05 14:04:52 +03:00
goto out_rcu ;
}
2016-11-21 16:56:31 +03:00
2023-01-14 01:21:37 +03:00
if ( virtio_vsock_skb_reply ( skb ) )
2016-07-28 17:36:33 +03:00
atomic_inc ( & vsock - > queued_replies ) ;
2023-01-14 01:21:37 +03:00
virtio_vsock_skb_queue_tail ( & vsock - > send_pkt_queue , skb ) ;
2016-07-28 17:36:33 +03:00
queue_work ( virtio_vsock_workqueue , & vsock - > send_pkt_work ) ;
2019-07-05 14:04:52 +03:00
out_rcu :
rcu_read_unlock ( ) ;
2016-07-28 17:36:33 +03:00
return len ;
}
2017-03-15 04:32:16 +03:00
static int
virtio_transport_cancel_pkt ( struct vsock_sock * vsk )
{
struct virtio_vsock * vsock ;
2019-07-05 14:04:52 +03:00
int cnt = 0 , ret ;
2017-03-15 04:32:16 +03:00
2019-07-05 14:04:52 +03:00
rcu_read_lock ( ) ;
vsock = rcu_dereference ( the_virtio_vsock ) ;
2017-03-15 04:32:16 +03:00
if ( ! vsock ) {
2019-07-05 14:04:52 +03:00
ret = - ENODEV ;
goto out_rcu ;
2017-03-15 04:32:16 +03:00
}
2023-01-14 01:21:37 +03:00
cnt = virtio_transport_purge_skbs ( vsk , & vsock - > send_pkt_queue ) ;
2017-03-15 04:32:16 +03:00
if ( cnt ) {
struct virtqueue * rx_vq = vsock - > vqs [ VSOCK_VQ_RX ] ;
int new_cnt ;
new_cnt = atomic_sub_return ( cnt , & vsock - > queued_replies ) ;
if ( new_cnt + cnt > = virtqueue_get_vring_size ( rx_vq ) & &
new_cnt < virtqueue_get_vring_size ( rx_vq ) )
queue_work ( virtio_vsock_workqueue , & vsock - > rx_work ) ;
}
2019-07-05 14:04:52 +03:00
ret = 0 ;
out_rcu :
rcu_read_unlock ( ) ;
return ret ;
2017-03-15 04:32:16 +03:00
}
2016-07-28 17:36:33 +03:00
static void virtio_vsock_rx_fill ( struct virtio_vsock * vsock )
{
2023-01-14 01:21:37 +03:00
int total_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM ;
struct scatterlist pkt , * p ;
2016-07-28 17:36:33 +03:00
struct virtqueue * vq ;
2023-01-14 01:21:37 +03:00
struct sk_buff * skb ;
2016-07-28 17:36:33 +03:00
int ret ;
vq = vsock - > vqs [ VSOCK_VQ_RX ] ;
do {
2023-01-14 01:21:37 +03:00
skb = virtio_vsock_alloc_skb ( total_len , GFP_KERNEL ) ;
if ( ! skb )
2016-07-28 17:36:33 +03:00
break ;
2023-01-14 01:21:37 +03:00
memset ( skb - > head , 0 , VIRTIO_VSOCK_SKB_HEADROOM ) ;
sg_init_one ( & pkt , virtio_vsock_hdr ( skb ) , total_len ) ;
p = & pkt ;
ret = virtqueue_add_sgs ( vq , & p , 0 , 1 , skb , GFP_KERNEL ) ;
if ( ret < 0 ) {
kfree_skb ( skb ) ;
2016-07-28 17:36:33 +03:00
break ;
}
vsock - > rx_buf_nr + + ;
} while ( vq - > num_free ) ;
if ( vsock - > rx_buf_nr > vsock - > rx_buf_max_nr )
vsock - > rx_buf_max_nr = vsock - > rx_buf_nr ;
virtqueue_kick ( vq ) ;
}
static void virtio_transport_tx_work ( struct work_struct * work )
{
struct virtio_vsock * vsock =
container_of ( work , struct virtio_vsock , tx_work ) ;
struct virtqueue * vq ;
bool added = false ;
vq = vsock - > vqs [ VSOCK_VQ_TX ] ;
mutex_lock ( & vsock - > tx_lock ) ;
2019-07-05 14:04:53 +03:00
if ( ! vsock - > tx_run )
goto out ;
2016-07-28 17:36:33 +03:00
do {
2023-01-14 01:21:37 +03:00
struct sk_buff * skb ;
2016-07-28 17:36:33 +03:00
unsigned int len ;
virtqueue_disable_cb ( vq ) ;
2023-01-14 01:21:37 +03:00
while ( ( skb = virtqueue_get_buf ( vq , & len ) ) ! = NULL ) {
consume_skb ( skb ) ;
2016-07-28 17:36:33 +03:00
added = true ;
}
} while ( ! virtqueue_enable_cb ( vq ) ) ;
2019-07-05 14:04:53 +03:00
out :
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > tx_lock ) ;
if ( added )
queue_work ( virtio_vsock_workqueue , & vsock - > send_pkt_work ) ;
}
/* Is there space left for replies to rx packets? */
static bool virtio_transport_more_replies ( struct virtio_vsock * vsock )
{
struct virtqueue * vq = vsock - > vqs [ VSOCK_VQ_RX ] ;
int val ;
smp_rmb ( ) ; /* paired with atomic_inc() and atomic_dec_return() */
val = atomic_read ( & vsock - > queued_replies ) ;
return val < virtqueue_get_vring_size ( vq ) ;
}
/* event_lock must be held */
static int virtio_vsock_event_fill_one ( struct virtio_vsock * vsock ,
struct virtio_vsock_event * event )
{
struct scatterlist sg ;
struct virtqueue * vq ;
vq = vsock - > vqs [ VSOCK_VQ_EVENT ] ;
sg_init_one ( & sg , event , sizeof ( * event ) ) ;
return virtqueue_add_inbuf ( vq , & sg , 1 , event , GFP_KERNEL ) ;
}
/* event_lock must be held */
static void virtio_vsock_event_fill ( struct virtio_vsock * vsock )
{
size_t i ;
for ( i = 0 ; i < ARRAY_SIZE ( vsock - > event_list ) ; i + + ) {
struct virtio_vsock_event * event = & vsock - > event_list [ i ] ;
virtio_vsock_event_fill_one ( vsock , event ) ;
}
virtqueue_kick ( vsock - > vqs [ VSOCK_VQ_EVENT ] ) ;
}
static void virtio_vsock_reset_sock ( struct sock * sk )
{
2021-08-12 08:30:56 +03:00
/* vmci_transport.c doesn't take sk_lock here either. At least we're
* under vsock_table_lock so the sock cannot disappear while we ' re
* executing .
*/
2017-10-05 23:46:52 +03:00
sk - > sk_state = TCP_CLOSE ;
2016-07-28 17:36:33 +03:00
sk - > sk_err = ECONNRESET ;
2021-06-28 01:48:21 +03:00
sk_error_report ( sk ) ;
2016-07-28 17:36:33 +03:00
}
static void virtio_vsock_update_guest_cid ( struct virtio_vsock * vsock )
{
struct virtio_device * vdev = vsock - > vdev ;
2016-12-06 07:03:34 +03:00
__le64 guest_cid ;
2016-07-28 17:36:33 +03:00
vdev - > config - > get ( vdev , offsetof ( struct virtio_vsock_config , guest_cid ) ,
& guest_cid , sizeof ( guest_cid ) ) ;
vsock - > guest_cid = le64_to_cpu ( guest_cid ) ;
}
/* event_lock must be held */
static void virtio_vsock_event_handle ( struct virtio_vsock * vsock ,
struct virtio_vsock_event * event )
{
switch ( le32_to_cpu ( event - > id ) ) {
case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET :
virtio_vsock_update_guest_cid ( vsock ) ;
2022-03-11 05:00:16 +03:00
vsock_for_each_connected_socket ( & virtio_transport . transport ,
virtio_vsock_reset_sock ) ;
2016-07-28 17:36:33 +03:00
break ;
}
}
static void virtio_transport_event_work ( struct work_struct * work )
{
struct virtio_vsock * vsock =
container_of ( work , struct virtio_vsock , event_work ) ;
struct virtqueue * vq ;
vq = vsock - > vqs [ VSOCK_VQ_EVENT ] ;
mutex_lock ( & vsock - > event_lock ) ;
2019-07-05 14:04:53 +03:00
if ( ! vsock - > event_run )
goto out ;
2016-07-28 17:36:33 +03:00
do {
struct virtio_vsock_event * event ;
unsigned int len ;
virtqueue_disable_cb ( vq ) ;
while ( ( event = virtqueue_get_buf ( vq , & len ) ) ! = NULL ) {
if ( len = = sizeof ( * event ) )
virtio_vsock_event_handle ( vsock , event ) ;
virtio_vsock_event_fill_one ( vsock , event ) ;
}
} while ( ! virtqueue_enable_cb ( vq ) ) ;
virtqueue_kick ( vsock - > vqs [ VSOCK_VQ_EVENT ] ) ;
2019-07-05 14:04:53 +03:00
out :
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > event_lock ) ;
}
static void virtio_vsock_event_done ( struct virtqueue * vq )
{
struct virtio_vsock * vsock = vq - > vdev - > priv ;
if ( ! vsock )
return ;
queue_work ( virtio_vsock_workqueue , & vsock - > event_work ) ;
}
static void virtio_vsock_tx_done ( struct virtqueue * vq )
{
struct virtio_vsock * vsock = vq - > vdev - > priv ;
if ( ! vsock )
return ;
queue_work ( virtio_vsock_workqueue , & vsock - > tx_work ) ;
}
static void virtio_vsock_rx_done ( struct virtqueue * vq )
{
struct virtio_vsock * vsock = vq - > vdev - > priv ;
if ( ! vsock )
return ;
queue_work ( virtio_vsock_workqueue , & vsock - > rx_work ) ;
}
2021-06-11 14:13:22 +03:00
static bool virtio_transport_seqpacket_allow ( u32 remote_cid ) ;
2016-07-28 17:36:33 +03:00
static struct virtio_transport virtio_transport = {
. transport = {
2019-11-14 12:57:48 +03:00
. module = THIS_MODULE ,
2016-07-28 17:36:33 +03:00
. get_local_cid = virtio_transport_get_local_cid ,
. init = virtio_transport_do_socket_init ,
. destruct = virtio_transport_destruct ,
. release = virtio_transport_release ,
. connect = virtio_transport_connect ,
. shutdown = virtio_transport_shutdown ,
2017-03-15 04:32:16 +03:00
. cancel_pkt = virtio_transport_cancel_pkt ,
2016-07-28 17:36:33 +03:00
. dgram_bind = virtio_transport_dgram_bind ,
. dgram_dequeue = virtio_transport_dgram_dequeue ,
. dgram_enqueue = virtio_transport_dgram_enqueue ,
. dgram_allow = virtio_transport_dgram_allow ,
. stream_dequeue = virtio_transport_stream_dequeue ,
. stream_enqueue = virtio_transport_stream_enqueue ,
. stream_has_data = virtio_transport_stream_has_data ,
. stream_has_space = virtio_transport_stream_has_space ,
. stream_rcvhiwat = virtio_transport_stream_rcvhiwat ,
. stream_is_active = virtio_transport_stream_is_active ,
. stream_allow = virtio_transport_stream_allow ,
2021-06-11 14:13:22 +03:00
. seqpacket_dequeue = virtio_transport_seqpacket_dequeue ,
. seqpacket_enqueue = virtio_transport_seqpacket_enqueue ,
. seqpacket_allow = virtio_transport_seqpacket_allow ,
. seqpacket_has_data = virtio_transport_seqpacket_has_data ,
2016-07-28 17:36:33 +03:00
. notify_poll_in = virtio_transport_notify_poll_in ,
. notify_poll_out = virtio_transport_notify_poll_out ,
. notify_recv_init = virtio_transport_notify_recv_init ,
. notify_recv_pre_block = virtio_transport_notify_recv_pre_block ,
. notify_recv_pre_dequeue = virtio_transport_notify_recv_pre_dequeue ,
. notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue ,
. notify_send_init = virtio_transport_notify_send_init ,
. notify_send_pre_block = virtio_transport_notify_send_pre_block ,
. notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue ,
. notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue ,
2019-11-14 12:57:42 +03:00
. notify_buffer_size = virtio_transport_notify_buffer_size ,
2023-03-27 22:11:51 +03:00
. read_skb = virtio_transport_read_skb ,
2016-07-28 17:36:33 +03:00
} ,
. send_pkt = virtio_transport_send_pkt ,
} ;
2021-06-11 14:13:22 +03:00
static bool virtio_transport_seqpacket_allow ( u32 remote_cid )
{
struct virtio_vsock * vsock ;
bool seqpacket_allow ;
2021-06-21 17:53:48 +03:00
seqpacket_allow = false ;
2021-06-11 14:13:22 +03:00
rcu_read_lock ( ) ;
vsock = rcu_dereference ( the_virtio_vsock ) ;
2021-06-21 17:53:48 +03:00
if ( vsock )
seqpacket_allow = vsock - > seqpacket_allow ;
2021-06-11 14:13:22 +03:00
rcu_read_unlock ( ) ;
return seqpacket_allow ;
}
2019-11-14 12:57:40 +03:00
static void virtio_transport_rx_work ( struct work_struct * work )
{
struct virtio_vsock * vsock =
container_of ( work , struct virtio_vsock , rx_work ) ;
struct virtqueue * vq ;
vq = vsock - > vqs [ VSOCK_VQ_RX ] ;
mutex_lock ( & vsock - > rx_lock ) ;
if ( ! vsock - > rx_run )
goto out ;
do {
virtqueue_disable_cb ( vq ) ;
for ( ; ; ) {
2023-01-14 01:21:37 +03:00
struct sk_buff * skb ;
2019-11-14 12:57:40 +03:00
unsigned int len ;
if ( ! virtio_transport_more_replies ( vsock ) ) {
/* Stop rx until the device processes already
* pending replies . Leave rx virtqueue
* callbacks disabled .
*/
goto out ;
}
2023-01-14 01:21:37 +03:00
skb = virtqueue_get_buf ( vq , & len ) ;
if ( ! skb )
2019-11-14 12:57:40 +03:00
break ;
vsock - > rx_buf_nr - - ;
/* Drop short/long packets */
2023-01-14 01:21:37 +03:00
if ( unlikely ( len < sizeof ( struct virtio_vsock_hdr ) | |
len > virtio_vsock_skb_len ( skb ) ) ) {
kfree_skb ( skb ) ;
2019-11-14 12:57:40 +03:00
continue ;
}
2023-01-14 01:21:37 +03:00
virtio_vsock_skb_rx_put ( skb ) ;
virtio_transport_deliver_tap_pkt ( skb ) ;
virtio_transport_recv_pkt ( & virtio_transport , skb ) ;
2019-11-14 12:57:40 +03:00
}
} while ( ! virtqueue_enable_cb ( vq ) ) ;
out :
if ( vsock - > rx_buf_nr < vsock - > rx_buf_max_nr / 2 )
virtio_vsock_rx_fill ( vsock ) ;
mutex_unlock ( & vsock - > rx_lock ) ;
}
2022-04-28 16:22:40 +03:00
static int virtio_vsock_vqs_init ( struct virtio_vsock * vsock )
2016-07-28 17:36:33 +03:00
{
2022-04-28 16:22:40 +03:00
struct virtio_device * vdev = vsock - > vdev ;
2016-07-28 17:36:33 +03:00
static const char * const names [ ] = {
" rx " ,
" tx " ,
" event " ,
} ;
2022-04-28 16:22:40 +03:00
vq_callback_t * callbacks [ ] = {
virtio_vsock_rx_done ,
virtio_vsock_tx_done ,
virtio_vsock_event_done ,
} ;
2016-07-28 17:36:33 +03:00
int ret ;
2022-04-28 16:22:40 +03:00
ret = virtio_find_vqs ( vdev , VSOCK_VQ_MAX , vsock - > vqs , callbacks , names ,
2017-03-06 19:19:39 +03:00
NULL ) ;
2016-07-28 17:36:33 +03:00
if ( ret < 0 )
2022-04-28 16:22:40 +03:00
return ret ;
2016-07-28 17:36:33 +03:00
virtio_vsock_update_guest_cid ( vsock ) ;
2022-03-23 20:36:25 +03:00
virtio_device_ready ( vdev ) ;
2019-07-05 14:04:53 +03:00
mutex_lock ( & vsock - > tx_lock ) ;
vsock - > tx_run = true ;
mutex_unlock ( & vsock - > tx_lock ) ;
2016-07-28 17:36:33 +03:00
mutex_lock ( & vsock - > rx_lock ) ;
virtio_vsock_rx_fill ( vsock ) ;
2019-07-05 14:04:53 +03:00
vsock - > rx_run = true ;
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > rx_lock ) ;
mutex_lock ( & vsock - > event_lock ) ;
virtio_vsock_event_fill ( vsock ) ;
2019-07-05 14:04:53 +03:00
vsock - > event_run = true ;
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > event_lock ) ;
return 0 ;
}
2022-04-28 16:22:40 +03:00
static void virtio_vsock_vqs_del ( struct virtio_vsock * vsock )
2016-07-28 17:36:33 +03:00
{
2022-04-28 16:22:40 +03:00
struct virtio_device * vdev = vsock - > vdev ;
2023-01-14 01:21:37 +03:00
struct sk_buff * skb ;
2016-07-28 17:36:33 +03:00
2022-04-28 16:22:40 +03:00
/* Reset all connected sockets when the VQs disappear */
2022-03-11 05:00:16 +03:00
vsock_for_each_connected_socket ( & virtio_transport . transport ,
virtio_vsock_reset_sock ) ;
2019-02-01 14:42:07 +03:00
2019-07-05 14:04:53 +03:00
/* Stop all work handlers to make sure no one is accessing the device,
2021-10-13 13:55:44 +03:00
* so we can safely call virtio_reset_device ( ) .
2019-07-05 14:04:53 +03:00
*/
mutex_lock ( & vsock - > rx_lock ) ;
vsock - > rx_run = false ;
mutex_unlock ( & vsock - > rx_lock ) ;
mutex_lock ( & vsock - > tx_lock ) ;
vsock - > tx_run = false ;
mutex_unlock ( & vsock - > tx_lock ) ;
mutex_lock ( & vsock - > event_lock ) ;
vsock - > event_run = false ;
mutex_unlock ( & vsock - > event_lock ) ;
/* Flush all device writes and interrupts, device will not use any
* more buffers .
*/
2021-10-13 13:55:44 +03:00
virtio_reset_device ( vdev ) ;
2016-07-28 17:36:33 +03:00
mutex_lock ( & vsock - > rx_lock ) ;
2023-01-14 01:21:37 +03:00
while ( ( skb = virtqueue_detach_unused_buf ( vsock - > vqs [ VSOCK_VQ_RX ] ) ) )
kfree_skb ( skb ) ;
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > rx_lock ) ;
mutex_lock ( & vsock - > tx_lock ) ;
2023-01-14 01:21:37 +03:00
while ( ( skb = virtqueue_detach_unused_buf ( vsock - > vqs [ VSOCK_VQ_TX ] ) ) )
kfree_skb ( skb ) ;
2016-07-28 17:36:33 +03:00
mutex_unlock ( & vsock - > tx_lock ) ;
2023-01-14 01:21:37 +03:00
virtio_vsock_skb_queue_purge ( & vsock - > send_pkt_queue ) ;
2016-07-28 17:36:33 +03:00
2019-07-05 14:04:53 +03:00
/* Delete virtqueues and flush outstanding callbacks if any */
2016-07-28 17:36:33 +03:00
vdev - > config - > del_vqs ( vdev ) ;
2022-04-28 16:22:40 +03:00
}
static int virtio_vsock_probe ( struct virtio_device * vdev )
{
struct virtio_vsock * vsock = NULL ;
int ret ;
2023-09-16 16:09:16 +03:00
int i ;
2022-04-28 16:22:40 +03:00
ret = mutex_lock_interruptible ( & the_virtio_vsock_mutex ) ;
if ( ret )
return ret ;
/* Only one virtio-vsock device per guest is supported */
if ( rcu_dereference_protected ( the_virtio_vsock ,
lockdep_is_held ( & the_virtio_vsock_mutex ) ) ) {
ret = - EBUSY ;
goto out ;
}
vsock = kzalloc ( sizeof ( * vsock ) , GFP_KERNEL ) ;
if ( ! vsock ) {
ret = - ENOMEM ;
goto out ;
}
vsock - > vdev = vdev ;
vsock - > rx_buf_nr = 0 ;
vsock - > rx_buf_max_nr = 0 ;
atomic_set ( & vsock - > queued_replies , 0 ) ;
mutex_init ( & vsock - > tx_lock ) ;
mutex_init ( & vsock - > rx_lock ) ;
mutex_init ( & vsock - > event_lock ) ;
2023-01-14 01:21:37 +03:00
skb_queue_head_init ( & vsock - > send_pkt_queue ) ;
2022-04-28 16:22:40 +03:00
INIT_WORK ( & vsock - > rx_work , virtio_transport_rx_work ) ;
INIT_WORK ( & vsock - > tx_work , virtio_transport_tx_work ) ;
INIT_WORK ( & vsock - > event_work , virtio_transport_event_work ) ;
INIT_WORK ( & vsock - > send_pkt_work , virtio_transport_send_pkt_work ) ;
if ( virtio_has_feature ( vdev , VIRTIO_VSOCK_F_SEQPACKET ) )
vsock - > seqpacket_allow = true ;
vdev - > priv = vsock ;
ret = virtio_vsock_vqs_init ( vsock ) ;
if ( ret < 0 )
goto out ;
2023-09-16 16:09:16 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( vsock - > out_sgs ) ; i + + )
vsock - > out_sgs [ i ] = & vsock - > out_bufs [ i ] ;
2022-04-28 16:22:40 +03:00
rcu_assign_pointer ( the_virtio_vsock , vsock ) ;
mutex_unlock ( & the_virtio_vsock_mutex ) ;
return 0 ;
out :
kfree ( vsock ) ;
mutex_unlock ( & the_virtio_vsock_mutex ) ;
return ret ;
}
static void virtio_vsock_remove ( struct virtio_device * vdev )
{
struct virtio_vsock * vsock = vdev - > priv ;
mutex_lock ( & the_virtio_vsock_mutex ) ;
vdev - > priv = NULL ;
rcu_assign_pointer ( the_virtio_vsock , NULL ) ;
synchronize_rcu ( ) ;
virtio_vsock_vqs_del ( vsock ) ;
2016-07-28 17:36:33 +03:00
2019-07-05 14:04:54 +03:00
/* Other works can be queued before 'config->del_vqs()', so we flush
* all works before to free the vsock object to avoid use after free .
*/
flush_work ( & vsock - > rx_work ) ;
flush_work ( & vsock - > tx_work ) ;
flush_work ( & vsock - > event_work ) ;
flush_work ( & vsock - > send_pkt_work ) ;
2019-07-05 14:04:52 +03:00
mutex_unlock ( & the_virtio_vsock_mutex ) ;
2016-07-28 17:36:33 +03:00
kfree ( vsock ) ;
}
2022-04-28 16:22:41 +03:00
# ifdef CONFIG_PM_SLEEP
static int virtio_vsock_freeze ( struct virtio_device * vdev )
{
struct virtio_vsock * vsock = vdev - > priv ;
mutex_lock ( & the_virtio_vsock_mutex ) ;
rcu_assign_pointer ( the_virtio_vsock , NULL ) ;
synchronize_rcu ( ) ;
virtio_vsock_vqs_del ( vsock ) ;
mutex_unlock ( & the_virtio_vsock_mutex ) ;
return 0 ;
}
static int virtio_vsock_restore ( struct virtio_device * vdev )
{
struct virtio_vsock * vsock = vdev - > priv ;
int ret ;
mutex_lock ( & the_virtio_vsock_mutex ) ;
/* Only one virtio-vsock device per guest is supported */
if ( rcu_dereference_protected ( the_virtio_vsock ,
lockdep_is_held ( & the_virtio_vsock_mutex ) ) ) {
ret = - EBUSY ;
goto out ;
}
ret = virtio_vsock_vqs_init ( vsock ) ;
if ( ret < 0 )
goto out ;
rcu_assign_pointer ( the_virtio_vsock , vsock ) ;
out :
mutex_unlock ( & the_virtio_vsock_mutex ) ;
return ret ;
}
# endif /* CONFIG_PM_SLEEP */
2016-07-28 17:36:33 +03:00
static struct virtio_device_id id_table [ ] = {
{ VIRTIO_ID_VSOCK , VIRTIO_DEV_ANY_ID } ,
{ 0 } ,
} ;
static unsigned int features [ ] = {
2021-06-11 14:13:22 +03:00
VIRTIO_VSOCK_F_SEQPACKET
2016-07-28 17:36:33 +03:00
} ;
static struct virtio_driver virtio_vsock_driver = {
. feature_table = features ,
. feature_table_size = ARRAY_SIZE ( features ) ,
. driver . name = KBUILD_MODNAME ,
. driver . owner = THIS_MODULE ,
. id_table = id_table ,
. probe = virtio_vsock_probe ,
. remove = virtio_vsock_remove ,
2022-04-28 16:22:41 +03:00
# ifdef CONFIG_PM_SLEEP
. freeze = virtio_vsock_freeze ,
. restore = virtio_vsock_restore ,
# endif
2016-07-28 17:36:33 +03:00
} ;
static int __init virtio_vsock_init ( void )
{
int ret ;
virtio_vsock_workqueue = alloc_workqueue ( " virtio_vsock " , 0 , 0 ) ;
if ( ! virtio_vsock_workqueue )
return - ENOMEM ;
2019-02-01 14:42:06 +03:00
2019-11-14 12:57:46 +03:00
ret = vsock_core_register ( & virtio_transport . transport ,
VSOCK_TRANSPORT_F_G2H ) ;
2016-07-28 17:36:33 +03:00
if ( ret )
2019-02-01 14:42:06 +03:00
goto out_wq ;
2019-05-16 23:51:07 +03:00
ret = register_virtio_driver ( & virtio_vsock_driver ) ;
2019-02-01 14:42:06 +03:00
if ( ret )
2019-05-16 23:51:07 +03:00
goto out_vci ;
2019-02-01 14:42:06 +03:00
return 0 ;
2019-05-16 23:51:07 +03:00
out_vci :
2019-11-14 12:57:46 +03:00
vsock_core_unregister ( & virtio_transport . transport ) ;
2019-02-01 14:42:06 +03:00
out_wq :
destroy_workqueue ( virtio_vsock_workqueue ) ;
2016-07-28 17:36:33 +03:00
return ret ;
}
static void __exit virtio_vsock_exit ( void )
{
unregister_virtio_driver ( & virtio_vsock_driver ) ;
2019-11-14 12:57:46 +03:00
vsock_core_unregister ( & virtio_transport . transport ) ;
2016-07-28 17:36:33 +03:00
destroy_workqueue ( virtio_vsock_workqueue ) ;
}
module_init ( virtio_vsock_init ) ;
module_exit ( virtio_vsock_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Asias He " ) ;
MODULE_DESCRIPTION ( " virtio transport for vsock " ) ;
MODULE_DEVICE_TABLE ( virtio , id_table ) ;