@ -136,6 +136,7 @@ vu_request_to_string(unsigned int req)
REQ ( VHOST_USER_GET_INFLIGHT_FD ) ,
REQ ( VHOST_USER_SET_INFLIGHT_FD ) ,
REQ ( VHOST_USER_GPU_SET_SOCKET ) ,
REQ ( VHOST_USER_VRING_KICK ) ,
REQ ( VHOST_USER_MAX ) ,
} ;
# undef REQ
@ -163,7 +164,10 @@ vu_panic(VuDev *dev, const char *msg, ...)
dev - > panic ( dev , buf ) ;
free ( buf ) ;
/* FIXME: find a way to call virtio_error? */
/*
* FIXME :
* find a way to call virtio_error , or perhaps close the connection ?
*/
}
/* Translate guest physical address to our virtual address. */
@ -1203,6 +1207,14 @@ vu_set_vring_err_exec(VuDev *dev, VhostUserMsg *vmsg)
static bool
vu_get_protocol_features_exec ( VuDev * dev , VhostUserMsg * vmsg )
{
/*
* Note that we support , but intentionally do not set ,
* VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS . This means that
* a device implementation can return it in its callback
* ( get_protocol_features ) if it wants to use this for
* simulation , but it is otherwise not desirable ( if even
* implemented by the master . )
*/
uint64_t features = 1ULL < < VHOST_USER_PROTOCOL_F_MQ |
1ULL < < VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1ULL < < VHOST_USER_PROTOCOL_F_SLAVE_REQ |
@ -1235,6 +1247,25 @@ vu_set_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
dev - > protocol_features = vmsg - > payload . u64 ;
if ( vu_has_protocol_feature ( dev ,
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS ) & &
( ! vu_has_protocol_feature ( dev , VHOST_USER_PROTOCOL_F_SLAVE_REQ ) | |
! vu_has_protocol_feature ( dev , VHOST_USER_PROTOCOL_F_REPLY_ACK ) ) ) {
/*
* The use case for using messages for kick / call is simulation , to make
* the kick and call synchronous . To actually get that behaviour , both
* of the other features are required .
* Theoretically , one could use only kick messages , or do them without
* having F_REPLY_ACK , but too many ( possibly pending ) messages on the
* socket will eventually cause the master to hang , to avoid this in
* scenarios where not desired enforce that the settings are in a way
* that actually enables the simulation case .
*/
vu_panic ( dev ,
" F_IN_BAND_NOTIFICATIONS requires F_SLAVE_REQ && F_REPLY_ACK " ) ;
return false ;
}
if ( dev - > iface - > set_protocol_features ) {
dev - > iface - > set_protocol_features ( dev , features ) ;
}
@ -1495,6 +1526,34 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
return false ;
}
static bool
vu_handle_vring_kick ( VuDev * dev , VhostUserMsg * vmsg )
{
unsigned int index = vmsg - > payload . state . index ;
if ( index > = dev - > max_queues ) {
vu_panic ( dev , " Invalid queue index: %u " , index ) ;
return false ;
}
DPRINT ( " Got kick message: handler:%p idx:%d \n " ,
dev - > vq [ index ] . handler , index ) ;
if ( ! dev - > vq [ index ] . started ) {
dev - > vq [ index ] . started = true ;
if ( dev - > iface - > queue_set_started ) {
dev - > iface - > queue_set_started ( dev , index , true ) ;
}
}
if ( dev - > vq [ index ] . handler ) {
dev - > vq [ index ] . handler ( dev , index ) ;
}
return false ;
}
static bool
vu_process_message ( VuDev * dev , VhostUserMsg * vmsg )
{
@ -1577,6 +1636,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
return vu_get_inflight_fd ( dev , vmsg ) ;
case VHOST_USER_SET_INFLIGHT_FD :
return vu_set_inflight_fd ( dev , vmsg ) ;
case VHOST_USER_VRING_KICK :
return vu_handle_vring_kick ( dev , vmsg ) ;
default :
vmsg_close_fds ( vmsg ) ;
vu_panic ( dev , " Unhandled request: %d " , vmsg - > request ) ;
@ -2038,8 +2099,7 @@ vring_notify(VuDev *dev, VuVirtq *vq)
return ! v | | vring_need_event ( vring_get_used_event ( vq ) , new , old ) ;
}
void
vu_queue_notify ( VuDev * dev , VuVirtq * vq )
static void _vu_queue_notify ( VuDev * dev , VuVirtq * vq , bool sync )
{
if ( unlikely ( dev - > broken ) | |
unlikely ( ! vq - > vring . avail ) ) {
@ -2051,11 +2111,48 @@ vu_queue_notify(VuDev *dev, VuVirtq *vq)
return ;
}
if ( vq - > call_fd < 0 & &
vu_has_protocol_feature ( dev ,
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS ) & &
vu_has_protocol_feature ( dev , VHOST_USER_PROTOCOL_F_SLAVE_REQ ) ) {
VhostUserMsg vmsg = {
. request = VHOST_USER_SLAVE_VRING_CALL ,
. flags = VHOST_USER_VERSION ,
. size = sizeof ( vmsg . payload . state ) ,
. payload . state = {
. index = vq - dev - > vq ,
} ,
} ;
bool ack = sync & &
vu_has_protocol_feature ( dev ,
VHOST_USER_PROTOCOL_F_REPLY_ACK ) ;
if ( ack ) {
vmsg . flags | = VHOST_USER_NEED_REPLY_MASK ;
}
vu_message_write ( dev , dev - > slave_fd , & vmsg ) ;
if ( ack ) {
vu_message_read ( dev , dev - > slave_fd , & vmsg ) ;
}
return ;
}
if ( eventfd_write ( vq - > call_fd , 1 ) < 0 ) {
vu_panic ( dev , " Error writing eventfd: %s " , strerror ( errno ) ) ;
}
}
void vu_queue_notify ( VuDev * dev , VuVirtq * vq )
{
_vu_queue_notify ( dev , vq , false ) ;
}
void vu_queue_notify_sync ( VuDev * dev , VuVirtq * vq )
{
_vu_queue_notify ( dev , vq , true ) ;
}
static inline void
vring_used_flags_set_bit ( VuVirtq * vq , int mask )
{