@ -69,6 +69,7 @@ enum {
OPTION_SIZE = 264 ,
OPTION_PREALLOCATION = 265 ,
OPTION_SHRINK = 266 ,
OPTION_SALVAGE = 267 ,
} ;
typedef enum OutputFormat {
@ -1581,6 +1582,7 @@ typedef struct ImgConvertState {
int64_t target_backing_sectors ; /* negative if unknown */
bool wr_in_order ;
bool copy_range ;
bool salvage ;
bool quiet ;
int min_sparse ;
int alignment ;
@ -1628,25 +1630,44 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
}
if ( s - > sector_next_status < = sector_num ) {
int64_t count = n * BDRV_SECTOR_SIZE ;
uint64_t offset = ( sector_num - src_cur_offset ) * BDRV_SECTOR_SIZE ;
int64_t count ;
if ( s - > target_has_backing ) {
do {
count = n * BDRV_SECTOR_SIZE ;
if ( s - > target_has_backing ) {
ret = bdrv_block_status ( blk_bs ( s - > src [ src_cur ] ) , offset ,
count , & count , NULL , NULL ) ;
} else {
ret = bdrv_block_status_above ( blk_bs ( s - > src [ src_cur ] ) , NULL ,
offset , count , & count , NULL ,
NULL ) ;
}
if ( ret < 0 ) {
if ( s - > salvage ) {
if ( n = = 1 ) {
if ( ! s - > quiet ) {
warn_report ( " error while reading block status at "
" offset % " PRIu64 " : %s " , offset ,
strerror ( - ret ) ) ;
}
/* Just try to read the data, then */
ret = BDRV_BLOCK_DATA ;
count = BDRV_SECTOR_SIZE ;
} else {
/* Retry on a shorter range */
n = DIV_ROUND_UP ( n , 4 ) ;
}
} else {
error_report ( " error while reading block status at offset "
" % " PRIu64 " : %s " , offset , strerror ( - ret ) ) ;
return ret ;
}
}
} while ( ret < 0 ) ;
ret = bdrv_block_status ( blk_bs ( s - > src [ src_cur ] ) ,
( sector_num - src_cur_offset ) *
BDRV_SECTOR_SIZE ,
count , & count , NULL , NULL ) ;
} else {
ret = bdrv_block_status_above ( blk_bs ( s - > src [ src_cur ] ) , NULL ,
( sector_num - src_cur_offset ) *
BDRV_SECTOR_SIZE ,
count , & count , NULL , NULL ) ;
}
if ( ret < 0 ) {
error_report ( " error while reading block status of sector % " PRId64
" : %s " , sector_num , strerror ( - ret ) ) ;
return ret ;
}
n = DIV_ROUND_UP ( count , BDRV_SECTOR_SIZE ) ;
if ( ret & BDRV_BLOCK_ZERO ) {
@ -1683,6 +1704,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
static int coroutine_fn convert_co_read ( ImgConvertState * s , int64_t sector_num ,
int nb_sectors , uint8_t * buf )
{
uint64_t single_read_until = 0 ;
int n , ret ;
assert ( nb_sectors < = s - > buf_sectors ) ;
@ -1690,6 +1712,7 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
BlockBackend * blk ;
int src_cur ;
int64_t bs_sectors , src_cur_offset ;
uint64_t offset ;
/* In the case of compression with multiple source files, we can get a
* nb_sectors that spreads into the next part . So we must be able to
@ -1698,13 +1721,29 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
blk = s - > src [ src_cur ] ;
bs_sectors = s - > src_sectors [ src_cur ] ;
offset = ( sector_num - src_cur_offset ) < < BDRV_SECTOR_BITS ;
n = MIN ( nb_sectors , bs_sectors - ( sector_num - src_cur_offset ) ) ;
if ( single_read_until > offset ) {
n = 1 ;
}
ret = blk_co_pread (
blk , ( sector_num - src_cur_offset ) < < BDRV_SECTOR_BITS ,
n < < BDRV_SECTOR_BITS , buf , 0 ) ;
ret = blk_co_pread ( blk , offset , n < < BDRV_SECTOR_BITS , buf , 0 ) ;
if ( ret < 0 ) {
return ret ;
if ( s - > salvage ) {
if ( n > 1 ) {
single_read_until = offset + ( n < < BDRV_SECTOR_BITS ) ;
continue ;
} else {
if ( ! s - > quiet ) {
warn_report ( " error while reading offset % " PRIu64
" : %s " , offset , strerror ( - ret ) ) ;
}
memset ( buf , 0 , BDRV_SECTOR_SIZE ) ;
}
} else {
return ret ;
}
}
sector_num + = n ;
@ -2035,6 +2074,7 @@ static int img_convert(int argc, char **argv)
{ " image-opts " , no_argument , 0 , OPTION_IMAGE_OPTS } ,
{ " force-share " , no_argument , 0 , ' U ' } ,
{ " target-image-opts " , no_argument , 0 , OPTION_TARGET_IMAGE_OPTS } ,
{ " salvage " , no_argument , 0 , OPTION_SALVAGE } ,
{ 0 , 0 , 0 , 0 }
} ;
c = getopt_long ( argc , argv , " :hf:O:B:Cco:l:S:pt:T:qnm:WU " ,
@ -2152,6 +2192,9 @@ static int img_convert(int argc, char **argv)
case OPTION_IMAGE_OPTS :
image_opts = true ;
break ;
case OPTION_SALVAGE :
s . salvage = true ;
break ;
case OPTION_TARGET_IMAGE_OPTS :
tgt_image_opts = true ;
break ;
@ -2178,6 +2221,11 @@ static int img_convert(int argc, char **argv)
goto fail_getopt ;
}
if ( s . copy_range & & s . salvage ) {
error_report ( " Cannot use copy offloading in salvaging mode " ) ;
goto fail_getopt ;
}
if ( tgt_image_opts & & ! skip_create ) {
error_report ( " --target-image-opts requires use of -n flag " ) ;
goto fail_getopt ;