@ -63,6 +63,20 @@ static size_t vub_iov_size(const struct iovec *iov,
return len ;
}
static size_t vub_iov_to_buf ( const struct iovec * iov ,
const unsigned int iov_cnt , void * buf )
{
size_t len ;
unsigned int i ;
len = 0 ;
for ( i = 0 ; i < iov_cnt ; i + + ) {
memcpy ( buf + len , iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
len + = iov [ i ] . iov_len ;
}
return len ;
}
static void vub_panic_cb ( VuDev * vu_dev , const char * buf )
{
VugDev * gdev ;
@ -161,6 +175,44 @@ vub_writev(VubReq *req, struct iovec *iov, uint32_t iovcnt)
return rc ;
}
static int
vub_discard_write_zeroes ( VubReq * req , struct iovec * iov , uint32_t iovcnt ,
uint32_t type )
{
struct virtio_blk_discard_write_zeroes * desc ;
ssize_t size ;
void * buf ;
size = vub_iov_size ( iov , iovcnt ) ;
if ( size ! = sizeof ( * desc ) ) {
fprintf ( stderr , " Invalid size %ld, expect %ld \n " , size , sizeof ( * desc ) ) ;
return - 1 ;
}
buf = g_new0 ( char , size ) ;
vub_iov_to_buf ( iov , iovcnt , buf ) ;
# if defined(__linux__) && defined(BLKDISCARD) && defined(BLKZEROOUT)
VubDev * vdev_blk = req - > vdev_blk ;
desc = ( struct virtio_blk_discard_write_zeroes * ) buf ;
uint64_t range [ 2 ] = { le64toh ( desc - > sector ) < < 9 ,
le32toh ( desc - > num_sectors ) < < 9 } ;
if ( type = = VIRTIO_BLK_T_DISCARD ) {
if ( ioctl ( vdev_blk - > blk_fd , BLKDISCARD , range ) = = 0 ) {
g_free ( buf ) ;
return 0 ;
}
} else if ( type = = VIRTIO_BLK_T_WRITE_ZEROES ) {
if ( ioctl ( vdev_blk - > blk_fd , BLKZEROOUT , range ) = = 0 ) {
g_free ( buf ) ;
return 0 ;
}
}
# endif
g_free ( buf ) ;
return - 1 ;
}
static void
vub_flush ( VubReq * req )
{
@ -216,44 +268,55 @@ static int vub_virtio_process_req(VubDev *vdev_blk,
in_num - - ;
type = le32toh ( req - > out - > type ) ;
switch ( type & ~ ( VIRTIO_BLK_T_OUT | VIRTIO_BLK_T_BARRIER ) ) {
case VIRTIO_BLK_T_IN : {
ssize_t ret = 0 ;
bool is_write = type & VIRTIO_BLK_T_OUT ;
req - > sector_num = le64toh ( req - > out - > sector ) ;
if ( is_write ) {
ret = vub_writev ( req , & elem - > out_sg [ 1 ] , out_num ) ;
} else {
ret = vub_readv ( req , & elem - > in_sg [ 0 ] , in_num ) ;
}
if ( ret > = 0 ) {
req - > in - > status = VIRTIO_BLK_S_OK ;
} else {
req - > in - > status = VIRTIO_BLK_S_IOERR ;
}
vub_req_complete ( req ) ;
break ;
switch ( type & ~ VIRTIO_BLK_T_BARRIER ) {
case VIRTIO_BLK_T_IN :
case VIRTIO_BLK_T_OUT : {
ssize_t ret = 0 ;
bool is_write = type & VIRTIO_BLK_T_OUT ;
req - > sector_num = le64toh ( req - > out - > sector ) ;
if ( is_write ) {
ret = vub_writev ( req , & elem - > out_sg [ 1 ] , out_num ) ;
} else {
ret = vub_readv ( req , & elem - > in_sg [ 0 ] , in_num ) ;
}
case VIRTIO_BLK_T_FLUSH : {
vub_flush ( req ) ;
if ( ret > = 0 ) {
req - > in - > status = VIRTIO_BLK_S_OK ;
vub_req_complete ( req ) ;
break ;
} else {
req - > in - > status = VIRTIO_BLK_S_IOERR ;
}
case VIRTIO_BLK_T_GET_ID : {
size_t size = MIN ( vub_iov_size ( & elem - > in_sg [ 0 ] , in_num ) ,
VIRTIO_BLK_ID_BYTES ) ;
snprintf ( elem - > in_sg [ 0 ] . iov_base , size , " %s " , " vhost_user_blk " ) ;
vub_req_complete ( req ) ;
break ;
}
case VIRTIO_BLK_T_FLUSH :
vub_flush ( req ) ;
req - > in - > status = VIRTIO_BLK_S_OK ;
vub_req_complete ( req ) ;
break ;
case VIRTIO_BLK_T_GET_ID : {
size_t size = MIN ( vub_iov_size ( & elem - > in_sg [ 0 ] , in_num ) ,
VIRTIO_BLK_ID_BYTES ) ;
snprintf ( elem - > in_sg [ 0 ] . iov_base , size , " %s " , " vhost_user_blk " ) ;
req - > in - > status = VIRTIO_BLK_S_OK ;
req - > size = elem - > in_sg [ 0 ] . iov_len ;
vub_req_complete ( req ) ;
break ;
}
case VIRTIO_BLK_T_DISCARD :
case VIRTIO_BLK_T_WRITE_ZEROES : {
int rc ;
rc = vub_discard_write_zeroes ( req , & elem - > out_sg [ 1 ] , out_num , type ) ;
if ( rc = = 0 ) {
req - > in - > status = VIRTIO_BLK_S_OK ;
req - > size = elem - > in_sg [ 0 ] . iov_len ;
vub_req_complete ( req ) ;
break ;
}
default : {
req - > in - > status = VIRTIO_BLK_S_UNSUPP ;
vub_req_complete ( req ) ;
break ;
} else {
req - > in - > status = VIRTIO_BLK_S_IOERR ;
}
vub_req_complete ( req ) ;
break ;
}
default :
req - > in - > status = VIRTIO_BLK_S_UNSUPP ;
vub_req_complete ( req ) ;
break ;
}
return 0 ;
@ -317,6 +380,10 @@ vub_get_features(VuDev *dev)
1ull < < VIRTIO_BLK_F_TOPOLOGY |
1ull < < VIRTIO_BLK_F_BLK_SIZE |
1ull < < VIRTIO_BLK_F_FLUSH |
# if defined(__linux__) && defined(BLKDISCARD) && defined(BLKZEROOUT)
1ull < < VIRTIO_BLK_F_DISCARD |
1ull < < VIRTIO_BLK_F_WRITE_ZEROES |
# endif
1ull < < VIRTIO_BLK_F_CONFIG_WCE |
1ull < < VIRTIO_F_VERSION_1 |
1ull < < VHOST_USER_F_PROTOCOL_FEATURES ;
@ -478,6 +545,13 @@ vub_initialize_config(int fd, struct virtio_blk_config *config)
config - > min_io_size = 1 ;
config - > opt_io_size = 1 ;
config - > num_queues = 1 ;
# if defined(__linux__) && defined(BLKDISCARD) && defined(BLKZEROOUT)
config - > max_discard_sectors = 32768 ;
config - > max_discard_seg = 1 ;
config - > discard_sector_alignment = config - > blk_size > > 9 ;
config - > max_write_zeroes_sectors = 32768 ;
config - > max_write_zeroes_seg = 1 ;
# endif
}
static VubDev *