@ -488,223 +488,178 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
}
# endif
typedef struct QCowAIOCB {
BlockDriverState * bs ;
int64_t sector_num ;
QEMUIOVector * qiov ;
uint8_t * buf ;
void * orig_buf ;
int nb_sectors ;
} QCowAIOCB ;
static QCowAIOCB * qcow_aio_setup ( BlockDriverState * bs ,
int64_t sector_num , QEMUIOVector * qiov , int nb_sectors ,
int is_write , QCowAIOCB * acb )
{
acb - > bs = bs ;
acb - > sector_num = sector_num ;
acb - > qiov = qiov ;
if ( qiov - > niov > 1 ) {
acb - > buf = acb - > orig_buf = qemu_blockalign ( bs , qiov - > size ) ;
if ( is_write )
qemu_iovec_to_buffer ( qiov , acb - > buf ) ;
} else {
acb - > orig_buf = NULL ;
acb - > buf = ( uint8_t * ) qiov - > iov - > iov_base ;
}
acb - > nb_sectors = nb_sectors ;
return acb ;
}
static int qcow_aio_read_cb ( QCowAIOCB * acb )
static int qcow_co_readv ( BlockDriverState * bs , int64_t sector_num ,
int nb_sectors , QEMUIOVector * qiov )
{
BlockDriverState * bs = acb - > bs ;
BDRVQcowState * s = bs - > opaque ;
int index_in_cluster ;
int ret , n ;
int ret = 0 , n ;
uint64_t cluster_offset ;
struct iovec hd_iov ;
QEMUIOVector hd_qiov ;
uint8_t * buf ;
void * orig_buf ;
redo :
if ( acb - > nb_sectors = = 0 ) {
/* request completed */
return 0 ;
if ( qiov - > niov > 1 ) {
buf = orig_buf = qemu_blockalign ( bs , qiov - > size ) ;
} else {
orig_buf = NULL ;
buf = ( uint8_t * ) qiov - > iov - > iov_base ;
}
/* prepare next request */
cluster_offset = get_cluster_offset ( bs , acb - > sector_num < < 9 ,
0 , 0 , 0 , 0 ) ;
index_in_cluster = acb - > sector_num & ( s - > cluster_sectors - 1 ) ;
n = s - > cluster_sectors - index_in_cluster ;
if ( n > acb - > nb_sectors ) {
n = acb - > nb_sectors ;
}
qemu_co_mutex_lock ( & s - > lock ) ;
while ( nb_sectors ! = 0 ) {
/* prepare next request */
cluster_offset = get_cluster_offset ( bs , sector_num < < 9 ,
0 , 0 , 0 , 0 ) ;
index_in_cluster = sector_num & ( s - > cluster_sectors - 1 ) ;
n = s - > cluster_sectors - index_in_cluster ;
if ( n > nb_sectors ) {
n = nb_sectors ;
}
if ( ! cluster_offset ) {
if ( bs - > backing_hd ) {
/* read from the base image */
hd_iov . iov_base = ( void * ) acb - > buf ;
if ( ! cluster_offset ) {
if ( bs - > backing_hd ) {
/* read from the base image */
hd_iov . iov_base = ( void * ) buf ;
hd_iov . iov_len = n * 512 ;
qemu_iovec_init_external ( & hd_qiov , & hd_iov , 1 ) ;
qemu_co_mutex_unlock ( & s - > lock ) ;
ret = bdrv_co_readv ( bs - > backing_hd , sector_num ,
n , & hd_qiov ) ;
qemu_co_mutex_lock ( & s - > lock ) ;
if ( ret < 0 ) {
goto fail ;
}
} else {
/* Note: in this case, no need to wait */
memset ( buf , 0 , 512 * n ) ;
}
} else if ( cluster_offset & QCOW_OFLAG_COMPRESSED ) {
/* add AIO support for compressed blocks ? */
if ( decompress_cluster ( bs , cluster_offset ) < 0 ) {
goto fail ;
}
memcpy ( buf ,
s - > cluster_cache + index_in_cluster * 512 , 512 * n ) ;
} else {
if ( ( cluster_offset & 511 ) ! = 0 ) {
goto fail ;
}
hd_iov . iov_base = ( void * ) buf ;
hd_iov . iov_len = n * 512 ;
qemu_iovec_init_external ( & hd_qiov , & hd_iov , 1 ) ;
qemu_co_mutex_unlock ( & s - > lock ) ;
ret = bdrv_co_readv ( bs - > backing_hd , acb - > sector_num ,
ret = bdrv_co_readv ( bs - > file ,
( cluster_offset > > 9 ) + index_in_cluster ,
n , & hd_qiov ) ;
qemu_co_mutex_lock ( & s - > lock ) ;
if ( ret < 0 ) {
return - EIO ;
break ;
}
if ( s - > crypt_method ) {
encrypt_sectors ( s , sector_num , buf , buf ,
n , 0 ,
& s - > aes_decrypt_key ) ;
}
} else {
/* Note: in this case, no need to wait */
memset ( acb - > buf , 0 , 512 * n ) ;
}
} else if ( cluster_offset & QCOW_OFLAG_COMPRESSED ) {
/* add AIO support for compressed blocks ? */
if ( decompress_cluster ( bs , cluster_offset ) < 0 ) {
return - EIO ;
}
memcpy ( acb - > buf ,
s - > cluster_cache + index_in_cluster * 512 , 512 * n ) ;
} else {
if ( ( cluster_offset & 511 ) ! = 0 ) {
return - EIO ;
}
hd_iov . iov_base = ( void * ) acb - > buf ;
hd_iov . iov_len = n * 512 ;
qemu_iovec_init_external ( & hd_qiov , & hd_iov , 1 ) ;
qemu_co_mutex_unlock ( & s - > lock ) ;
ret = bdrv_co_readv ( bs - > file ,
( cluster_offset > > 9 ) + index_in_cluster ,
n , & hd_qiov ) ;
qemu_co_mutex_lock ( & s - > lock ) ;
if ( ret < 0 ) {
return ret ;
}
}
ret = 0 ;
/* post process the read buffer */
if ( ! cluster_offset ) {
/* nothing to do */
} else if ( cluster_offset & QCOW_OFLAG_COMPRESSED ) {
/* nothing to do */
} else {
if ( s - > crypt_method ) {
encrypt_sectors ( s , acb - > sector_num , acb - > buf , acb - > buf ,
n , 0 ,
& s - > aes_decrypt_key ) ;
}
nb_sectors - = n ;
sector_num + = n ;
buf + = n * 512 ;
}
acb - > nb_sectors - = n ;
acb - > sector_num + = n ;
acb - > buf + = n * 512 ;
goto redo ;
}
static int qcow_co_readv ( BlockDriverState * bs , int64_t sector_num ,
int nb_sectors , QEMUIOVector * qiov )
{
BDRVQcowState * s = bs - > opaque ;
QCowAIOCB acb ;
int ret ;
qcow_aio_setup ( bs , sector_num , qiov , nb_sectors , 0 , & acb ) ;
qemu_co_mutex_lock ( & s - > lock ) ;
ret = qcow_aio_read_cb ( & acb ) ;
done :
qemu_co_mutex_unlock ( & s - > lock ) ;
if ( acb . qiov - > niov > 1 ) {
qemu_iovec_from_buffer ( acb . qiov , acb . orig_buf , acb . qiov - > size ) ;
qemu_vfree ( acb . orig_buf ) ;
if ( qiov - > niov > 1 ) {
qemu_iovec_from_buffer ( qiov , orig_buf , qiov - > size ) ;
qemu_vfree ( orig_buf ) ;
}
return ret ;
fail :
ret = - EIO ;
goto done ;
}
static int qcow_aio_write_cb ( QCowAIOCB * acb )
static int qcow_co_writev ( BlockDriverState * bs , int64_t sector_num ,
int nb_sectors , QEMUIOVector * qiov )
{
BlockDriverState * bs = acb - > bs ;
BDRVQcowState * s = bs - > opaque ;
int index_in_cluster ;
uint64_t cluster_offset ;
const uint8_t * src_buf ;
int ret , n ;
int ret = 0 , n ;
uint8_t * cluster_data = NULL ;
struct iovec hd_iov ;
QEMUIOVector hd_qiov ;
uint8_t * buf ;
void * orig_buf ;
redo :
if ( acb - > nb_sectors = = 0 ) {
/* request completed */
return 0 ;
}
s - > cluster_cache_offset = - 1 ; /* disable compressed cache */
index_in_cluster = acb - > sector_num & ( s - > cluster_sectors - 1 ) ;
n = s - > cluster_sectors - index_in_cluster ;
if ( n > acb - > nb_sectors ) {
n = acb - > nb_sectors ;
}
cluster_offset = get_cluster_offset ( bs , acb - > sector_num < < 9 , 1 , 0 ,
index_in_cluster ,
index_in_cluster + n ) ;
if ( ! cluster_offset | | ( cluster_offset & 511 ) ! = 0 ) {
return - EIO ;
}
if ( s - > crypt_method ) {
if ( ! cluster_data ) {
cluster_data = g_malloc0 ( s - > cluster_size ) ;
}
encrypt_sectors ( s , acb - > sector_num , cluster_data , acb - > buf ,
n , 1 , & s - > aes_encrypt_key ) ;
src_buf = cluster_data ;
if ( qiov - > niov > 1 ) {
buf = orig_buf = qemu_blockalign ( bs , qiov - > size ) ;
qemu_iovec_to_buffer ( qiov , buf ) ;
} else {
src_buf = acb - > buf ;
orig_buf = NULL ;
buf = ( uint8_t * ) qiov - > iov - > iov_base ;
}
hd_iov . iov_base = ( void * ) src_buf ;
hd_iov . iov_len = n * 512 ;
qemu_iovec_init_external ( & hd_qiov , & hd_iov , 1 ) ;
qemu_co_mutex_unlock ( & s - > lock ) ;
ret = bdrv_co_writev ( bs - > file ,
( cluster_offset > > 9 ) + index_in_cluster ,
n , & hd_qiov ) ;
if ( cluster_data ) {
free ( cluster_data ) ;
cluster_data = NULL ;
}
qemu_co_mutex_lock ( & s - > lock ) ;
if ( ret < 0 ) {
return ret ;
}
acb - > nb_sectors - = n ;
acb - > sector_num + = n ;
acb - > buf + = n * 512 ;
goto redo ;
}
while ( nb_sectors ! = 0 ) {
static int qcow_co_writev ( BlockDriverState * bs , int64_t sector_num ,
int nb_sectors , QEMUIOVector * qiov )
{
BDRVQcowState * s = bs - > opaque ;
QCowAIOCB acb ;
int ret ;
s - > cluster_cache_offset = - 1 ; /* disable compressed cache */
index_in_cluster = sector_num & ( s - > cluster_sectors - 1 ) ;
n = s - > cluster_sectors - index_in_cluster ;
if ( n > nb_sectors ) {
n = nb_sectors ;
}
cluster_offset = get_cluster_offset ( bs , sector_num < < 9 , 1 , 0 ,
index_in_cluster ,
index_in_cluster + n ) ;
if ( ! cluster_offset | | ( cluster_offset & 511 ) ! = 0 ) {
ret = - EIO ;
break ;
}
if ( s - > crypt_method ) {
if ( ! cluster_data ) {
cluster_data = g_malloc0 ( s - > cluster_size ) ;
}
encrypt_sectors ( s , sector_num , cluster_data , buf ,
n , 1 , & s - > aes_encrypt_key ) ;
src_buf = cluster_data ;
} else {
src_buf = buf ;
}
qcow_aio_setup ( bs , sector_num , qiov , nb_sectors , 1 , & acb ) ;
hd_iov . iov_base = ( void * ) src_buf ;
hd_iov . iov_len = n * 512 ;
qemu_iovec_init_external ( & hd_qiov , & hd_iov , 1 ) ;
qemu_co_mutex_unlock ( & s - > lock ) ;
ret = bdrv_co_writev ( bs - > file ,
( cluster_offset > > 9 ) + index_in_cluster ,
n , & hd_qiov ) ;
qemu_co_mutex_lock ( & s - > lock ) ;
if ( ret < 0 ) {
break ;
}
ret = 0 ;
qemu_co_mutex_lock ( & s - > lock ) ;
ret = qcow_aio_write_cb ( & acb ) ;
nb_sectors - = n ;
sector_num + = n ;
buf + = n * 512 ;
}
qemu_co_mutex_unlock ( & s - > lock ) ;
if ( acb . qiov - > niov > 1 ) {
qemu_vfree ( acb . orig_buf ) ;
if ( qiov - > niov > 1 ) {
qemu_vfree ( orig_buf ) ;
}
free ( cluster_data ) ;
return ret ;
}