@ -10,6 +10,7 @@
# include "qemu/osdep.h"
# include "qapi/error.h"
# include "hw/virtio/virtio-dmabuf.h"
# include "hw/virtio/vhost.h"
# include "hw/virtio/virtio-crypto.h"
# include "hw/virtio/vhost-user.h"
@ -21,6 +22,7 @@
# include "sysemu/kvm.h"
# include "qemu/error-report.h"
# include "qemu/main-loop.h"
# include "qemu/uuid.h"
# include "qemu/sockets.h"
# include "sysemu/runstate.h"
# include "sysemu/cryptodev.h"
@ -100,6 +102,7 @@ typedef enum VhostUserRequest {
VHOST_USER_REM_MEM_REG = 38 ,
VHOST_USER_SET_STATUS = 39 ,
VHOST_USER_GET_STATUS = 40 ,
VHOST_USER_GET_SHARED_OBJECT = 41 ,
VHOST_USER_MAX
} VhostUserRequest ;
@ -108,6 +111,9 @@ typedef enum VhostUserBackendRequest {
VHOST_USER_BACKEND_IOTLB_MSG = 1 ,
VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2 ,
VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3 ,
VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6 ,
VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7 ,
VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8 ,
VHOST_USER_BACKEND_MAX
} VhostUserBackendRequest ;
@ -181,6 +187,10 @@ typedef struct VhostUserInflight {
uint16_t queue_size ;
} VhostUserInflight ;
typedef struct VhostUserShared {
unsigned char uuid [ 16 ] ;
} VhostUserShared ;
typedef struct {
VhostUserRequest request ;
@ -205,6 +215,7 @@ typedef union {
VhostUserCryptoSession session ;
VhostUserVringArea area ;
VhostUserInflight inflight ;
VhostUserShared object ;
} VhostUserPayload ;
typedef struct VhostUserMsg {
@ -1580,6 +1591,139 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev,
return 0 ;
}
static int
vhost_user_backend_handle_shared_object_add ( struct vhost_dev * dev ,
VhostUserShared * object )
{
QemuUUID uuid ;
memcpy ( uuid . data , object - > uuid , sizeof ( object - > uuid ) ) ;
return virtio_add_vhost_device ( & uuid , dev ) ;
}
static int
vhost_user_backend_handle_shared_object_remove ( VhostUserShared * object )
{
QemuUUID uuid ;
memcpy ( uuid . data , object - > uuid , sizeof ( object - > uuid ) ) ;
return virtio_remove_resource ( & uuid ) ;
}
static bool vhost_user_send_resp ( QIOChannel * ioc , VhostUserHeader * hdr ,
VhostUserPayload * payload , Error * * errp )
{
struct iovec iov [ ] = {
{ . iov_base = hdr , . iov_len = VHOST_USER_HDR_SIZE } ,
{ . iov_base = payload , . iov_len = hdr - > size } ,
} ;
hdr - > flags & = ~ VHOST_USER_NEED_REPLY_MASK ;
hdr - > flags | = VHOST_USER_REPLY_MASK ;
return ! qio_channel_writev_all ( ioc , iov , ARRAY_SIZE ( iov ) , errp ) ;
}
static bool
vhost_user_backend_send_dmabuf_fd ( QIOChannel * ioc , VhostUserHeader * hdr ,
VhostUserPayload * payload , Error * * errp )
{
hdr - > size = sizeof ( payload - > u64 ) ;
return vhost_user_send_resp ( ioc , hdr , payload , errp ) ;
}
int vhost_user_get_shared_object ( struct vhost_dev * dev , unsigned char * uuid ,
int * dmabuf_fd )
{
struct vhost_user * u = dev - > opaque ;
CharBackend * chr = u - > user - > chr ;
int ret ;
VhostUserMsg msg = {
. hdr . request = VHOST_USER_GET_SHARED_OBJECT ,
. hdr . flags = VHOST_USER_VERSION ,
} ;
memcpy ( msg . payload . object . uuid , uuid , sizeof ( msg . payload . object . uuid ) ) ;
ret = vhost_user_write ( dev , & msg , NULL , 0 ) ;
if ( ret < 0 ) {
return ret ;
}
ret = vhost_user_read ( dev , & msg ) ;
if ( ret < 0 ) {
return ret ;
}
if ( msg . hdr . request ! = VHOST_USER_GET_SHARED_OBJECT ) {
error_report ( " Received unexpected msg type. "
" Expected %d received %d " ,
VHOST_USER_GET_SHARED_OBJECT , msg . hdr . request ) ;
return - EPROTO ;
}
* dmabuf_fd = qemu_chr_fe_get_msgfd ( chr ) ;
if ( * dmabuf_fd < 0 ) {
error_report ( " Failed to get dmabuf fd " ) ;
return - EIO ;
}
return 0 ;
}
static int
vhost_user_backend_handle_shared_object_lookup ( struct vhost_user * u ,
QIOChannel * ioc ,
VhostUserHeader * hdr ,
VhostUserPayload * payload )
{
QemuUUID uuid ;
CharBackend * chr = u - > user - > chr ;
Error * local_err = NULL ;
int dmabuf_fd = - 1 ;
int fd_num = 0 ;
memcpy ( uuid . data , payload - > object . uuid , sizeof ( payload - > object . uuid ) ) ;
payload - > u64 = 0 ;
switch ( virtio_object_type ( & uuid ) ) {
case TYPE_DMABUF :
dmabuf_fd = virtio_lookup_dmabuf ( & uuid ) ;
break ;
case TYPE_VHOST_DEV :
{
struct vhost_dev * dev = virtio_lookup_vhost_device ( & uuid ) ;
if ( dev = = NULL ) {
payload - > u64 = - EINVAL ;
break ;
}
int ret = vhost_user_get_shared_object ( dev , uuid . data , & dmabuf_fd ) ;
if ( ret < 0 ) {
payload - > u64 = ret ;
}
break ;
}
case TYPE_INVALID :
payload - > u64 = - EINVAL ;
break ;
}
if ( dmabuf_fd ! = - 1 ) {
fd_num + + ;
}
if ( qemu_chr_fe_set_msgfds ( chr , & dmabuf_fd , fd_num ) < 0 ) {
error_report ( " Failed to set msg fds. " ) ;
payload - > u64 = - EINVAL ;
}
if ( ! vhost_user_backend_send_dmabuf_fd ( ioc , hdr , payload , & local_err ) ) {
error_report_err ( local_err ) ;
return - EINVAL ;
}
return 0 ;
}
static void close_backend_channel ( struct vhost_user * u )
{
g_source_destroy ( u - > backend_src ) ;
@ -1637,6 +1781,16 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
ret = vhost_user_backend_handle_vring_host_notifier ( dev , & payload . area ,
fd ? fd [ 0 ] : - 1 ) ;
break ;
case VHOST_USER_BACKEND_SHARED_OBJECT_ADD :
ret = vhost_user_backend_handle_shared_object_add ( dev , & payload . object ) ;
break ;
case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE :
ret = vhost_user_backend_handle_shared_object_remove ( & payload . object ) ;
break ;
case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP :
ret = vhost_user_backend_handle_shared_object_lookup ( dev - > opaque , ioc ,
& hdr , & payload ) ;
break ;
default :
error_report ( " Received unexpected msg type: %d. " , hdr . request ) ;
ret = - EINVAL ;
@ -1647,21 +1801,10 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
* directly in their request handlers .
*/
if ( hdr . flags & VHOST_USER_NEED_REPLY_MASK ) {
struct iovec iovec [ 2 ] ;
hdr . flags & = ~ VHOST_USER_NEED_REPLY_MASK ;
hdr . flags | = VHOST_USER_REPLY_MASK ;
payload . u64 = ! ! ret ;
hdr . size = sizeof ( payload . u64 ) ;
iovec [ 0 ] . iov_base = & hdr ;
iovec [ 0 ] . iov_len = VHOST_USER_HDR_SIZE ;
iovec [ 1 ] . iov_base = & payload ;
iovec [ 1 ] . iov_len = hdr . size ;
if ( qio_channel_writev_all ( ioc , iovec , ARRAY_SIZE ( iovec ) , & local_err ) ) {
if ( ! vhost_user_send_resp ( ioc , & hdr , & payload , & local_err ) ) {
error_report_err ( local_err ) ;
goto err ;
}