@ -1624,6 +1624,81 @@ static void raw_close(BlockDriverState *bs)
}
}
static int raw_regular_truncate ( int fd , int64_t offset , PreallocMode prealloc ,
Error * * errp )
{
int result = 0 ;
char * buf ;
switch ( prealloc ) {
# ifdef CONFIG_POSIX_FALLOCATE
case PREALLOC_MODE_FALLOC :
/*
* Truncating before posix_fallocate ( ) makes it about twice slower on
* file systems that do not support fallocate ( ) , trying to check if a
* block is allocated before allocating it , so don ' t do that here .
*/
result = - posix_fallocate ( fd , 0 , offset ) ;
if ( result ! = 0 ) {
/* posix_fallocate() doesn't set errno. */
error_setg_errno ( errp , - result ,
" Could not preallocate data for the new file " ) ;
}
return result ;
# endif
case PREALLOC_MODE_FULL :
{
int64_t num = 0 , left = offset ;
/*
* Knowing the final size from the beginning could allow the file
* system driver to do less allocations and possibly avoid
* fragmentation of the file .
*/
if ( ftruncate ( fd , offset ) ! = 0 ) {
result = - errno ;
error_setg_errno ( errp , - result , " Could not resize file " ) ;
return result ;
}
buf = g_malloc0 ( 65536 ) ;
while ( left > 0 ) {
num = MIN ( left , 65536 ) ;
result = write ( fd , buf , num ) ;
if ( result < 0 ) {
result = - errno ;
error_setg_errno ( errp , - result ,
" Could not write to the new file " ) ;
break ;
}
left - = result ;
}
if ( result > = 0 ) {
result = fsync ( fd ) ;
if ( result < 0 ) {
result = - errno ;
error_setg_errno ( errp , - result ,
" Could not flush new file to disk " ) ;
}
}
g_free ( buf ) ;
return result ;
}
case PREALLOC_MODE_OFF :
if ( ftruncate ( fd , offset ) ! = 0 ) {
result = - errno ;
error_setg_errno ( errp , - result , " Could not resize file " ) ;
}
return result ;
default :
result = - ENOTSUP ;
error_setg ( errp , " Unsupported preallocation mode: %s " ,
PreallocMode_lookup [ prealloc ] ) ;
return result ;
}
}
static int raw_truncate ( BlockDriverState * bs , int64_t offset ,
PreallocMode prealloc , Error * * errp )
{
@ -1892,72 +1967,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
# endif
}
switch ( prealloc ) {
# ifdef CONFIG_POSIX_FALLOCATE
case PREALLOC_MODE_FALLOC :
/*
* Truncating before posix_fallocate ( ) makes it about twice slower on
* file systems that do not support fallocate ( ) , trying to check if a
* block is allocated before allocating it , so don ' t do that here .
*/
result = - posix_fallocate ( fd , 0 , total_size ) ;
if ( result ! = 0 ) {
/* posix_fallocate() doesn't set errno. */
error_setg_errno ( errp , - result ,
" Could not preallocate data for the new file " ) ;
}
break ;
# endif
case PREALLOC_MODE_FULL :
{
int64_t num = 0 , left = total_size ;
/*
* Knowing the final size from the beginning could allow the file
* system driver to do less allocations and possibly avoid
* fragmentation of the file .
*/
if ( ftruncate ( fd , total_size ) ! = 0 ) {
result = - errno ;
error_setg_errno ( errp , - result , " Could not resize file " ) ;
goto out_close ;
}
buf = g_malloc0 ( 65536 ) ;
while ( left > 0 ) {
num = MIN ( left , 65536 ) ;
result = write ( fd , buf , num ) ;
if ( result < 0 ) {
result = - errno ;
error_setg_errno ( errp , - result ,
" Could not write to the new file " ) ;
break ;
}
left - = result ;
}
if ( result > = 0 ) {
result = fsync ( fd ) ;
if ( result < 0 ) {
result = - errno ;
error_setg_errno ( errp , - result ,
" Could not flush new file to disk " ) ;
}
}
g_free ( buf ) ;
break ;
}
case PREALLOC_MODE_OFF :
if ( ftruncate ( fd , total_size ) ! = 0 ) {
result = - errno ;
error_setg_errno ( errp , - result , " Could not resize file " ) ;
}
break ;
default :
result = - ENOTSUP ;
error_setg ( errp , " Unsupported preallocation mode: %s " ,
PreallocMode_lookup [ prealloc ] ) ;
break ;
result = raw_regular_truncate ( fd , total_size , prealloc , errp ) ;
if ( result < 0 ) {
goto out_close ;
}
out_close :