2026-04-02 16:00:27 +02:00
// SPDX-License-Identifier: GPL-3.0-or-later
2026-04-02 16:25:49 +02:00
// Copyright (C) 2011 Andrea Mazzoleni
2011-03-04 20:59:21 +01:00
2026-06-24 00:15:15 +02:00
# include "os/portable.h"
2011-03-04 20:59:21 +01:00
2015-01-02 18:52:04 +01:00
# include "support.h"
2011-03-04 20:59:21 +01:00
# include "elem.h"
# include "state.h"
# include "parity.h"
2014-09-04 22:52:04 +02:00
# include "handle.h"
2011-03-04 20:59:21 +01:00
2016-05-16 22:55:19 +02:00
/**
* Pseudo random limits for parity
*/
2017-11-03 23:46:45 +01:00
# define PARITY_LIMIT(size, split, level) \
2016-05-16 22:55:19 +02:00
size ? size + ( 123562341 + split * 634542351 + level * 983491341 ) % size : 0
2011-03-04 20:59:21 +01:00
/****************************************************************************/
/* parity */
2015-02-01 18:48:50 +01:00
block_off_t parity_allocated_size ( struct snapraid_state * state )
2011-03-04 20:59:21 +01:00
{
2011-03-12 10:09:59 +01:00
block_off_t parity_block ;
2011-09-23 21:48:50 +02:00
tommy_node * i ;
2011-03-04 20:59:21 +01:00
/* compute the size of the parity file */
parity_block = 0 ;
2014-09-27 00:32:39 +02:00
for ( i = state - > disklist ; i ! = 0 ; i = i - > next ) {
2011-09-23 21:48:50 +02:00
struct snapraid_disk * disk = i - > data ;
2011-03-04 20:59:21 +01:00
/* start from the declared size */
2016-01-01 10:00:18 +01:00
block_off_t block = fs_size ( disk ) ;
2011-03-04 20:59:21 +01:00
2026-04-27 15:43:06 +02:00
/*
* Decrease the block until an allocated one , but part of a file
* we don ' t stop at deleted blocks , because we want to have them cleared
* if they are at the end of the parity
*/
2016-01-16 14:26:05 +01:00
while ( block > parity_block & & ! block_has_file ( fs_par2block_find ( disk , block - 1 ) ) )
2011-03-04 20:59:21 +01:00
- - block ;
2011-09-23 21:48:50 +02:00
/* get the highest value */
if ( block > parity_block )
2011-03-04 20:59:21 +01:00
parity_block = block ;
}
return parity_block ;
}
2015-02-01 18:48:50 +01:00
block_off_t parity_used_size ( struct snapraid_state * state )
{
block_off_t parity_block ;
tommy_node * i ;
/* compute the size of the parity file */
parity_block = 0 ;
for ( i = state - > disklist ; i ! = 0 ; i = i - > next ) {
struct snapraid_disk * disk = i - > data ;
/* start from the declared size */
2016-01-01 10:00:18 +01:00
block_off_t block = fs_size ( disk ) ;
2015-02-01 18:48:50 +01:00
/* decrease the block until an used one */
2016-01-16 14:26:05 +01:00
while ( block > parity_block & & ! block_has_file_and_valid_parity ( fs_par2block_find ( disk , block - 1 ) ) )
2015-02-01 18:48:50 +01:00
- - block ;
/* get the highest value */
if ( block > parity_block )
parity_block = block ;
}
return parity_block ;
}
2012-10-06 13:17:21 +02:00
void parity_overflow ( struct snapraid_state * state , data_off_t size )
{
tommy_node * i ;
block_off_t blockalloc ;
2016-09-30 18:40:54 +02:00
int found = 0 ;
2012-10-06 13:17:21 +02:00
/* don't report if everything is outside or if the file is not accessible */
if ( size = = 0 ) {
return ;
}
blockalloc = size / state - > block_size ;
/* for all disks */
2014-09-27 00:32:39 +02:00
for ( i = state - > disklist ; i ! = 0 ; i = i - > next ) {
2012-10-06 13:17:21 +02:00
struct snapraid_disk * disk = i - > data ;
tommy_node * j ;
/* for all files */
2014-09-27 00:32:39 +02:00
for ( j = disk - > filelist ; j ! = 0 ; j = j - > next ) {
2012-10-06 13:17:21 +02:00
struct snapraid_file * file = j - > data ;
if ( file - > blockmax > 0 ) {
2015-10-01 18:19:48 +02:00
block_off_t parity_pos = fs_file2par_get ( disk , file , file - > blockmax - 1 ) ;
if ( parity_pos > = blockalloc ) {
2016-10-02 00:06:48 +02:00
found = 1 ;
2026-05-29 11:01:44 +02:00
log_tag ( " outofparity:%s:%s \n " , disk - > name , esc_tag ( file - > sub ) ) ;
2026-02-01 20:21:28 +01:00
log_fatal ( ESOFT , " outofparity %s%s \n " , disk - > dir , file - > sub ) ;
2012-10-06 13:17:21 +02:00
}
}
}
}
2016-09-30 18:40:54 +02:00
if ( found ) {
2026-02-01 20:21:28 +01:00
log_fatal ( ESOFT , " \n Insufficient parity space. Data requires more parity than available. \n " ) ;
log_fatal ( ESOFT , " Move the 'outofparity' files to a larger disk. \n " ) ;
2016-09-30 18:40:54 +02:00
}
2012-10-06 13:17:21 +02:00
}
2016-04-26 21:48:39 +02:00
void parity_size ( struct snapraid_parity_handle * handle , data_off_t * out_size )
2011-03-04 20:59:21 +01:00
{
2016-04-26 21:48:39 +02:00
unsigned s ;
data_off_t size ;
2016-09-28 20:32:50 +02:00
/* now compute the size summing all the parity splits */
2016-04-26 21:48:39 +02:00
size = 0 ;
2016-09-28 20:32:50 +02:00
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
size + = split - > size ;
2011-03-04 20:59:21 +01:00
}
2016-04-26 21:48:39 +02:00
* out_size = size ;
}
2016-09-28 20:32:50 +02:00
int parity_create ( struct snapraid_parity_handle * handle , const struct snapraid_parity * parity , unsigned level , int mode , uint32_t block_size , data_off_t limit_size )
2016-04-26 21:48:39 +02:00
{
unsigned s ;
2016-09-28 20:32:50 +02:00
data_off_t block_mask ;
/* mask of bits used by the block size */
block_mask = ( ( data_off_t ) block_size ) - 1 ;
2016-04-26 21:48:39 +02:00
handle - > level = level ;
handle - > split_mac = 0 ;
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < parity - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int ret ;
int flags ;
2016-05-15 14:18:44 +02:00
advise_init ( & split - > advise , mode ) ;
2016-04-26 21:48:39 +02:00
pathcpy ( split - > path , sizeof ( split - > path ) , parity - > split_map [ s ] . path ) ;
split - > size = parity - > split_map [ s ] . size ;
2016-05-16 22:55:19 +02:00
split - > limit_size = PARITY_LIMIT ( limit_size , s , level ) ;
2016-04-26 21:48:39 +02:00
/* opening in sequential mode in Windows */
2016-05-15 14:18:44 +02:00
flags = O_RDWR | O_CREAT | O_BINARY | advise_flags ( & split - > advise ) ;
2016-04-26 21:48:39 +02:00
split - > f = open ( split - > path , flags , 0600 ) ;
if ( split - > f = = - 1 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error opening parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-04-26 21:48:39 +02:00
goto bail ;
/* LCOV_EXCL_STOP */
}
2016-07-26 20:51:20 +02:00
/* we have a valid file handle */
+ + handle - > split_mac ;
2016-04-26 21:48:39 +02:00
/* get the stat info */
ret = fstat ( split - > f , & split - > st ) ;
2013-04-04 22:52:56 +02:00
if ( ret ! = 0 ) {
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error accessing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2013-04-04 22:52:56 +02:00
goto bail ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2013-04-04 22:52:56 +02:00
}
2013-02-27 20:58:03 +01:00
2019-05-19 08:33:08 +02:00
/* the initial valid size is the size on disk */
split - > valid_size = split - > st . st_size ;
2016-04-26 21:48:39 +02:00
/**
* If the parity size is not yet set , set it now .
2016-09-28 20:32:50 +02:00
* This happens when expanding the number of parities ,
* or when upgrading from a content file that has not split - > size data .
2016-04-26 21:48:39 +02:00
*/
2016-09-28 20:32:50 +02:00
if ( split - > size = = PARITY_SIZE_INVALID ) {
2016-04-26 21:48:39 +02:00
split - > size = split - > st . st_size ;
2016-09-28 20:32:50 +02:00
/* ensure that the resulting size if block aligned */
if ( ( split - > size & block_mask ) ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( ESOFT , " Error in preallocated size of parity file '%s' with size % " PRIu64 " and block %u . \n " , split - > path , split - > size , block_size ) ;
2016-09-28 20:32:50 +02:00
goto bail ;
/* LCOV_EXCL_STOP */
}
}
2016-05-15 14:18:44 +02:00
ret = advise_open ( & split - > advise , split - > f ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error advising parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-05-15 14:18:44 +02:00
goto bail ;
/* LCOV_EXCL_STOP */
2016-04-26 21:48:39 +02:00
}
}
2012-10-09 23:02:46 +02:00
return 0 ;
bail :
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
close ( split - > f ) ;
split - > f = - 1 ;
}
2012-10-09 23:02:46 +02:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2012-10-09 23:02:46 +02:00
}
2017-11-24 21:56:12 +01:00
static int parity_handle_grow ( struct snapraid_split_handle * split , data_off_t previous_size , data_off_t size , int skip_fallocate )
2012-10-09 23:02:46 +02:00
{
int ret ;
2011-10-09 07:51:25 +02:00
2017-11-24 21:56:12 +01:00
( void ) previous_size ;
2016-05-16 22:55:19 +02:00
/* simulate a failure for testing limits */
2026-01-24 19:19:11 +01:00
if ( split - > limit_size ! = 0 & & size > ( data_off_t ) split - > limit_size ) {
errno = ENXIO ;
2016-05-16 22:55:19 +02:00
return - 1 ;
2026-01-24 19:19:11 +01:00
}
2016-05-16 22:55:19 +02:00
2012-01-21 13:08:35 +01:00
# if HAVE_FALLOCATE
2016-04-26 21:48:39 +02:00
if ( ! skip_fallocate ) {
2016-05-01 18:11:55 +02:00
/*
* Allocate real space using the specific Linux fallocate ( ) operation .
* If the underline file - system doesn ' t support it , this operation fails .
*
* Instead posix_fallocate ( ) fallbacks to write the whole file ,
* and we cannot use it as we may need to initialize a multi terabyte
* file .
*
* See : fallocate vs posix_fallocate
* http : //stackoverflow.com/questions/14063046/fallocate-vs-posix-fallocate
2017-11-24 21:56:12 +01:00
*
* To work better with Btrfs , use as offset the previous allocated size .
* Otherwise Btrfs will count as space needed even the already allocated one .
*
* See : Massive loss of disk space
* https : //www.mail-archive.com/linux-btrfs@vger.kernel.org/msg66454.html
2016-05-01 18:11:55 +02:00
*/
2017-11-24 21:56:12 +01:00
ret = fallocate ( split - > f , 0 , previous_size , size - previous_size ) ;
2016-04-26 21:48:39 +02:00
2016-05-01 18:11:55 +02:00
/*
* In some legacy system fallocate ( ) may return the error number
* as positive integer , and in this case it doesn ' t set errno .
*
* Detect and handle this case .
*
* See : Fix fallocate error return on i386
* https : //sourceware.org/ml/libc-hacker/2010-04/msg00000.html
*
* See : [ PATCH XFS ] Fix error return for fallocate ( ) on XFS
* http : //oss.sgi.com/archives/xfs/2009-11/msg00201.html
*/
if ( ret > 0 ) {
2016-04-26 21:48:39 +02:00
/* LCOV_EXCL_START */
errno = ret ;
2012-01-21 13:08:35 +01:00
ret = - 1 ;
2016-04-26 21:48:39 +02:00
/* LCOV_EXCL_STOP */
2012-01-21 13:08:35 +01:00
}
2016-04-26 21:48:39 +02:00
} else {
errno = EOPNOTSUPP ;
ret = - 1 ;
}
2012-01-21 13:08:35 +01:00
2016-05-01 18:11:55 +02:00
/*
* Fallback to ftruncate ( ) if the operation is not supported .
*
* We get EOPNOTSUPP if the operation is not supported , like in ext3 / ext2
* or ENOSYS with kernel before 2.6 .23 , because fallocate is not supported
* at all .
*
* See : man fallocate
* ENOSYS - This kernel does not implement fallocate ( ) .
2017-11-03 23:46:45 +01:00
* EOPNOTSUPP - The file system containing the file referred to by fd does not support this operation
2016-05-01 18:11:55 +02:00
*/
if ( ret ! = 0 & & ( errno = = EOPNOTSUPP | | errno = = ENOSYS ) ) {
2016-04-26 21:48:39 +02:00
/* fallback using ftruncate() */
ret = ftruncate ( split - > f , size ) ;
}
2011-03-04 20:59:21 +01:00
# else
2016-04-26 21:48:39 +02:00
( void ) skip_fallocate ; /* avoid the warning */
2013-03-01 00:14:10 +01:00
2016-04-26 21:48:39 +02:00
/* allocate using a sparse file */
ret = ftruncate ( split - > f , size ) ;
2011-03-04 20:59:21 +01:00
# endif
2012-10-06 13:17:21 +02:00
2017-11-22 23:58:51 +01:00
if ( ret ! = 0 )
2026-08-17 19:02:15 +02:00
log_tag ( " split:grow:%s:% " PRIu64 " : failed with error %s \n " , esc_tag ( split - > path ) , size , strerror ( errno ) ) ;
2017-11-22 23:58:51 +01:00
else
2026-08-17 19:02:15 +02:00
log_tag ( " split:grow:%s:% " PRIu64 " : ok \n " , esc_tag ( split - > path ) , size ) ;
2017-11-22 23:58:51 +01:00
2016-04-26 21:48:39 +02:00
return ret ;
}
2016-07-25 21:46:15 +02:00
static int parity_handle_shrink ( struct snapraid_split_handle * split , data_off_t size )
{
2017-11-22 23:58:51 +01:00
int ret ;
ret = ftruncate ( split - > f , size ) ;
if ( ret ! = 0 )
2026-08-17 19:02:15 +02:00
log_tag ( " split:shrink:%s:% " PRIu64 " : failed with error %s \n " , esc_tag ( split - > path ) , size , strerror ( errno ) ) ;
2017-11-22 23:58:51 +01:00
else
2026-08-17 19:02:15 +02:00
log_tag ( " split:shrink:%s:% " PRIu64 " : ok \n " , esc_tag ( split - > path ) , size ) ;
2017-11-22 23:58:51 +01:00
return ret ;
2016-07-25 21:46:15 +02:00
}
2016-04-26 21:48:39 +02:00
/**
* Get the highest bit set .
*/
uint64_t hbit_u64 ( uint64_t v )
{
unsigned ilog ;
ilog = 0 ;
while ( ( v / = 2 ) ! = 0 )
+ + ilog ;
return 1ULL < < ilog ;
}
2016-10-04 23:56:13 +02:00
static int parity_handle_fill ( struct snapraid_split_handle * split , data_off_t size , uint32_t block_size , int skip_fallocate , int skip_space_holder )
2016-04-26 21:48:39 +02:00
{
data_off_t base ;
data_off_t delta ;
data_off_t block_mask ;
2016-07-27 23:06:59 +02:00
# ifdef _WIN32
/*
* In Windows we want to avoid the annoying warning
* message of disk full .
*
* To ensure to leave some space available , we first create
* a spaceholder file > 200 MB , to ensure to not fill completely
* the disk .
*/
char spaceholder_path [ PATH_MAX ] ;
pathprint ( spaceholder_path , sizeof ( spaceholder_path ) , " %s%s " , split - > path , " .spaceholder " ) ;
2016-10-04 23:56:13 +02:00
if ( ! skip_space_holder ) {
int spaceholder_f ;
2016-07-27 23:06:59 +02:00
2016-10-04 23:56:13 +02:00
spaceholder_f = open ( spaceholder_path , O_RDWR | O_CREAT | O_TRUNC | O_BINARY , 0600 ) ;
if ( spaceholder_f = = - 1 ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to create space holder file '%s'. \n " , spaceholder_path ) ;
2016-10-04 23:56:13 +02:00
return - 1 ;
}
2016-07-27 23:06:59 +02:00
2016-10-04 23:56:13 +02:00
/* note that in Windows ftruncate is really allocating space */
2026-01-30 09:54:54 +01:00
if ( ftruncate ( spaceholder_f , WINDOWS_SPACEHOLDER_SIZE ) ! = 0 ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " WARNING Failed to resize the space holder file '%s' to %u bytes. \n " , spaceholder_path , WINDOWS_SPACEHOLDER_SIZE ) ;
log_fatal ( errno , " Assuming that no more space is available. \n " ) ;
2016-10-04 23:56:13 +02:00
close ( spaceholder_f ) ;
remove ( spaceholder_path ) ;
return 0 ;
}
2016-07-27 23:06:59 +02:00
2016-10-04 23:56:13 +02:00
if ( fsync ( spaceholder_f ) ! = 0 ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to sync the space holder file '%s'. \n " , spaceholder_path ) ;
2016-10-04 23:56:13 +02:00
close ( spaceholder_f ) ;
remove ( spaceholder_path ) ;
return - 1 ;
}
if ( close ( spaceholder_f ) ! = 0 ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to close the space holder file '%s'. \n " , spaceholder_path ) ;
2016-10-04 23:56:13 +02:00
remove ( spaceholder_path ) ;
return - 1 ;
}
2016-07-27 23:06:59 +02:00
}
2016-10-04 23:56:13 +02:00
# else
( void ) skip_space_holder ;
2016-07-27 23:06:59 +02:00
# endif
2016-04-26 21:48:39 +02:00
/* mask of bits used by the block size */
block_mask = ( ( data_off_t ) block_size ) - 1 ;
/* present size */
base = split - > st . st_size ;
2026-04-27 15:43:06 +02:00
/*
* Truncate it to block size multiplier
* in case of damage the size may get wrong
*/
2016-04-26 21:48:39 +02:00
base & = ~ block_mask ;
/* size we have to increase */
delta = size - base ;
2026-08-17 19:02:15 +02:00
log_tag ( " split:fill:%s:% " PRIu64 " :% " PRIu64 " : \n " , esc_tag ( split - > path ) , base , size ) ;
2017-11-22 23:58:51 +01:00
2016-04-26 21:48:39 +02:00
/* grow the size one bit at time, like a kind of binary search */
while ( delta ! = 0 ) {
int ret ;
data_off_t run = hbit_u64 ( delta ) ;
2016-07-25 21:46:15 +02:00
/* mask out the bit we process */
delta & = ~ run ;
2016-04-26 21:48:39 +02:00
2026-08-17 19:02:15 +02:00
log_tag ( " split:delta:%s:% " PRIu64 " :% " PRIu64 " : \n " , esc_tag ( split - > path ) , base , run ) ;
2017-11-22 23:58:51 +01:00
2017-11-24 21:56:12 +01:00
ret = parity_handle_grow ( split , base , base + run , skip_fallocate ) ;
2011-03-04 20:59:21 +01:00
if ( ret ! = 0 ) {
2016-07-25 21:46:15 +02:00
/* we cannot grow, fallback enabling all the smaller bits */
2016-04-26 21:48:39 +02:00
delta = run - 1 ;
/* mask out the block size */
delta & = ~ block_mask ;
} else {
2016-07-25 21:46:15 +02:00
/* increase the effective size */
2016-04-26 21:48:39 +02:00
base + = run ;
2012-10-06 13:17:21 +02:00
}
2016-04-26 21:48:39 +02:00
}
2016-07-25 21:46:15 +02:00
/* ensure that the resulting size if block aligned */
if ( ( base & block_mask ) ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( EINTERNAL , " Internal inconsistency in requested parity size % " PRIu64 " with block %u \n " , base , block_size ) ;
2016-07-25 21:46:15 +02:00
os_abort ( ) ;
/* LCOV_EXCL_STOP */
}
2012-10-06 13:17:21 +02:00
2016-07-27 23:06:59 +02:00
# ifdef _WIN32
/* now delete the spaceholder file */
if ( remove ( spaceholder_path ) ! = 0 ) {
2026-02-01 20:21:28 +01:00
log_error ( errno , " WARNING Failed to remove the space holder file '%s'. \n " , spaceholder_path ) ;
log_error ( errno , " Continuing anyway. \n " ) ;
2016-07-27 23:06:59 +02:00
}
# endif
2026-04-27 15:43:06 +02:00
/*
* Shrink to the expected size to ensure to throw away any extra
* data allocated when the grow operation fails
*/
2016-07-25 21:46:15 +02:00
return parity_handle_shrink ( split , base ) ;
2016-04-26 21:48:39 +02:00
}
2012-10-06 13:17:21 +02:00
2016-10-04 23:56:13 +02:00
static int parity_handle_chsize ( struct snapraid_split_handle * split , data_off_t size , uint32_t block_size , int skip_fallocate , int skip_space_holder )
2016-04-26 21:48:39 +02:00
{
int ret ;
int f_ret ;
int f_errno ;
int f_dir ;
if ( split - > st . st_size < size ) {
2016-10-04 23:56:13 +02:00
f_ret = parity_handle_fill ( split , size , block_size , skip_fallocate , skip_space_holder ) ;
2016-04-26 21:48:39 +02:00
f_errno = errno ;
f_dir = 1 ;
} else if ( split - > st . st_size > size ) {
f_ret = parity_handle_shrink ( split , size ) ;
f_errno = errno ;
f_dir = - 1 ;
} else {
f_ret = 0 ;
f_errno = 0 ;
f_dir = 0 ;
}
/* get the stat info */
ret = fstat ( split - > f , & split - > st ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error accessing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-04-26 21:48:39 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
/* now check the error */
if ( f_ret ! = 0 ) {
/* LCOV_EXCL_START */
if ( f_dir > 0 ) {
2012-10-06 13:17:21 +02:00
if ( f_errno = = ENOSPC ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to grow parity file '%s' to size % " PRIu64 " due lack of space. \n " , split - > path , size ) ;
2011-03-04 20:59:21 +01:00
} else {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error growing parity file '%s' to size % " PRIu64 " . Do you have enough space? %s. \n " , split - > path , size , strerror ( f_errno ) ) ;
2011-03-04 20:59:21 +01:00
}
2016-04-26 21:48:39 +02:00
} else {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error truncating parity file '%s' to size % " PRIu64 " . %s. \n " , split - > path , size , strerror ( f_errno ) ) ;
2011-03-04 20:59:21 +01:00
}
2016-04-26 21:48:39 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
2013-12-24 22:07:09 +01:00
2019-05-19 08:33:08 +02:00
/* if we shrink, update the valid size, but don't update when growing */
if ( split - > valid_size > split - > st . st_size )
split - > valid_size = split - > st . st_size ;
2016-04-26 21:48:39 +02:00
return 0 ;
}
2011-10-09 07:51:25 +02:00
2016-04-26 21:48:39 +02:00
static int parity_split_is_fixed ( struct snapraid_parity_handle * handle , unsigned s )
{
/* next one */
+ + s ;
2013-12-24 22:07:09 +01:00
2016-04-26 21:48:39 +02:00
/* the latest one is always growing */
if ( s > = handle - > split_mac )
return 0 ;
/* if the next it's 0, this one is growing */
if ( handle - > split_map [ s ] . size = = 0 )
return 0 ;
return 1 ;
}
2016-10-04 23:56:13 +02:00
int parity_chsize ( struct snapraid_parity_handle * handle , struct snapraid_parity * parity , int * is_modified , data_off_t size , uint32_t block_size , int skip_fallocate , int skip_space_holder )
2016-04-26 21:48:39 +02:00
{
int ret ;
unsigned s ;
2016-07-25 21:46:15 +02:00
data_off_t block_mask ;
/* mask of bits used by the block size */
block_mask = ( ( data_off_t ) block_size ) - 1 ;
2016-04-26 21:48:39 +02:00
2016-11-06 18:27:44 +01:00
if ( size < 0 ) {
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2016-04-26 21:48:39 +02:00
return - 1 ;
2016-11-06 18:27:44 +01:00
/* LCOV_EXCL_STOP */
}
2016-04-26 21:48:39 +02:00
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int is_fixed = parity_split_is_fixed ( handle , s ) ;
data_off_t run ;
if ( is_fixed ) {
2026-04-27 15:43:06 +02:00
/*
* If the required size is smaller , we have to reduce also the file
* ignoring the previous size
*/
2016-05-18 20:58:41 +02:00
if ( size < = split - > size ) {
2016-09-28 20:32:50 +02:00
/* mark it as not fixed anymore for the later check */
is_fixed = 0 ;
run = size ; /* allocate only the needed size */
2016-04-26 21:48:39 +02:00
} else {
2016-09-28 20:32:50 +02:00
/* if the size cannot be changed, use the fixed one */
2016-04-26 21:48:39 +02:00
run = split - > size ;
2016-07-25 22:23:32 +02:00
if ( ( run & block_mask ) ! = 0 ) {
2016-07-26 19:34:48 +02:00
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2026-02-01 20:21:28 +01:00
log_fatal ( EINTERNAL , " Internal inconsistency in split '%s' size with extra '% " PRIu64 " ' bytes. \n " , split - > path , run & block_mask ) ;
2016-07-26 19:34:48 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
2016-07-25 22:23:32 +02:00
}
2016-04-26 21:48:39 +02:00
}
} else {
2016-09-28 20:32:50 +02:00
/* otherwise tries to allocate all the needed remaining size */
2016-04-26 21:48:39 +02:00
run = size ;
}
2017-11-03 23:46:45 +01:00
2016-10-04 23:56:13 +02:00
ret = parity_handle_chsize ( split , run , block_size , skip_fallocate , skip_space_holder ) ;
2016-11-06 18:27:44 +01:00
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2016-04-26 21:48:39 +02:00
return - 1 ;
2016-11-06 18:27:44 +01:00
/* LCOV_EXCL_STOP */
}
2016-04-26 21:48:39 +02:00
if ( split - > st . st_size > run ) {
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Unexpected over resizing parity file '%s' to size % " PRIu64 " resulting in size % " PRIu64 " . \n " , split - > path , run , ( uint64_t ) split - > st . st_size ) ;
2016-04-26 21:48:39 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
} else if ( is_fixed & & split - > st . st_size < run ) {
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed restoring parity file '%s' to size % " PRIu64 " resulting in size % " PRIu64 " . \n " , split - > path , run , ( uint64_t ) split - > st . st_size ) ;
2016-04-26 21:48:39 +02:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2016-04-26 21:48:39 +02:00
} else {
2016-09-28 20:32:50 +02:00
/* here it's possible to get less than the requested size */
2016-07-25 21:46:15 +02:00
run = split - > st . st_size ;
if ( ( run & block_mask ) ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( EINTERNAL , " Internal inconsistency in final parity size % " PRIu64 " with block size %u \n " , run , block_size ) ;
2016-07-25 21:46:15 +02:00
os_abort ( ) ;
/* LCOV_EXCL_STOP */
}
2016-09-28 20:32:50 +02:00
/* store what we have allocated */
2016-07-25 21:46:15 +02:00
split - > size = run ;
2016-09-28 20:32:50 +02:00
/* decrease the remaining size */
size - = run ;
2016-04-26 21:48:39 +02:00
}
}
2016-09-28 18:55:03 +02:00
/* if we cannot allocate all the space */
if ( size ! = 0 ) {
2016-11-06 18:27:44 +01:00
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to allocate all the required parity space. You miss % " PRIu64 " bytes. \n " , size ) ;
2016-09-28 18:55:03 +02:00
return - 1 ;
2016-11-06 18:27:44 +01:00
/* LCOV_EXCL_STOP */
2016-09-28 18:55:03 +02:00
}
2016-04-26 21:48:39 +02:00
/* now copy the new size in the parity data */
if ( is_modified )
* is_modified = 0 ;
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
if ( parity - > split_map [ s ] . size ! = split - > size ) {
parity - > split_map [ s ] . size = split - > size ;
if ( is_modified )
* is_modified = 1 ;
2012-10-06 13:17:21 +02:00
}
2016-04-26 21:48:39 +02:00
}
return 0 ;
}
2012-10-06 13:17:21 +02:00
2016-09-28 20:32:50 +02:00
int parity_open ( struct snapraid_parity_handle * handle , const struct snapraid_parity * parity , unsigned level , int mode , uint32_t block_size , data_off_t limit_size )
2016-04-26 21:48:39 +02:00
{
unsigned s ;
2016-09-28 20:32:50 +02:00
data_off_t block_mask ;
2016-04-26 21:48:39 +02:00
handle - > level = level ;
handle - > split_mac = 0 ;
2016-09-28 20:32:50 +02:00
/* mask of bits used by the block size */
block_mask = ( ( data_off_t ) block_size ) - 1 ;
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < parity - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int ret ;
int flags ;
2016-05-15 14:18:44 +02:00
advise_init ( & split - > advise , mode ) ;
2016-04-26 21:48:39 +02:00
pathcpy ( split - > path , sizeof ( split - > path ) , parity - > split_map [ s ] . path ) ;
split - > size = parity - > split_map [ s ] . size ;
2016-05-16 22:55:19 +02:00
split - > limit_size = PARITY_LIMIT ( limit_size , s , level ) ;
2016-04-26 21:48:39 +02:00
2026-04-27 15:43:06 +02:00
/*
* Open for read
* O_NOATIME : do not change access time
*/
2016-05-15 14:18:44 +02:00
flags = O_RDONLY | O_BINARY | advise_flags ( & split - > advise ) ;
2016-04-26 21:48:39 +02:00
split - > f = open_noatime ( split - > path , flags ) ;
if ( split - > f = = - 1 ) {
2016-09-28 20:32:50 +02:00
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error opening parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-04-26 21:48:39 +02:00
goto bail ;
2016-09-28 20:32:50 +02:00
/* LCOV_EXCL_STOP */
2016-04-26 21:48:39 +02:00
}
2012-10-06 13:17:21 +02:00
2016-07-26 20:51:20 +02:00
/* we have a valid file handle */
+ + handle - > split_mac ;
2016-04-26 21:48:39 +02:00
/* get the stat info */
ret = fstat ( split - > f , & split - > st ) ;
if ( ret ! = 0 ) {
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error accessing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2013-12-24 22:07:09 +01:00
goto bail ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2013-12-24 22:07:09 +01:00
}
2019-05-19 08:33:08 +02:00
/* the initial valid size is the size on disk */
split - > valid_size = split - > st . st_size ;
2016-04-26 21:48:39 +02:00
/**
* If the parity size is not yet set , set it now .
2016-09-28 20:32:50 +02:00
* This happens when expanding the number of parities ,
* or when upgrading from a content file that has not split - > size data .
2016-04-26 21:48:39 +02:00
*/
2016-09-28 20:32:50 +02:00
if ( split - > size = = PARITY_SIZE_INVALID ) {
2016-04-26 21:48:39 +02:00
split - > size = split - > st . st_size ;
2016-09-28 20:32:50 +02:00
/* ensure that the resulting size if block aligned */
if ( ( split - > size & block_mask ) ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( ESOFT , " Error in preallocated size of parity file '%s' with size % " PRIu64 " and block %u . \n " , split - > path , split - > size , block_size ) ;
2016-09-28 20:32:50 +02:00
goto bail ;
/* LCOV_EXCL_STOP */
}
}
2016-05-15 14:18:44 +02:00
ret = advise_open ( & split - > advise , split - > f ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error advising parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-05-15 14:18:44 +02:00
goto bail ;
/* LCOV_EXCL_STOP */
2016-04-26 21:48:39 +02:00
}
2011-03-04 20:59:21 +01:00
}
2011-10-09 07:51:25 +02:00
return 0 ;
2011-03-18 22:38:11 +01:00
bail :
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
close ( split - > f ) ;
split - > f = - 1 ;
}
2011-03-18 22:38:11 +01:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2011-03-04 20:59:21 +01:00
}
2016-04-26 21:48:39 +02:00
int parity_sync ( struct snapraid_parity_handle * handle )
2011-03-04 20:59:21 +01:00
{
2016-04-26 21:48:39 +02:00
# if HAVE_FSYNC
unsigned s ;
2011-10-09 07:51:25 +02:00
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int ret ;
2011-10-09 07:51:25 +02:00
2026-04-27 15:43:06 +02:00
/*
* Ensure that data changes are written to disk .
* This is required to ensure that parity is more updated than content
* in case of a system crash .
*/
2016-04-26 21:48:39 +02:00
ret = fsync ( split - > f ) ;
2013-04-04 22:52:56 +02:00
if ( ret ! = 0 ) {
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error syncing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-04-26 21:48:39 +02:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2013-04-04 22:52:56 +02:00
}
2011-03-04 20:59:21 +01:00
}
# endif
2011-10-09 07:51:25 +02:00
return 0 ;
2011-03-04 20:59:21 +01:00
}
2019-05-21 22:33:24 +02:00
int parity_truncate ( struct snapraid_parity_handle * handle )
2011-03-04 20:59:21 +01:00
{
2016-04-26 21:48:39 +02:00
unsigned s ;
int f_ret = 0 ;
2011-03-04 20:59:21 +01:00
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int ret ;
2019-05-21 22:33:24 +02:00
/* truncate any data that we know it's not valid */
ret = ftruncate ( split - > f , split - > valid_size ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error truncating the parity file '%s' to size % " PRIu64 " . %s. \n " , split - > path , split - > valid_size , strerror ( errno ) ) ;
2019-05-21 22:33:24 +02:00
f_ret = - 1 ;
/* LCOV_EXCL_STOP */
2019-05-19 08:33:08 +02:00
2019-05-21 22:33:24 +02:00
/* continue to truncate the others */
2019-05-19 08:33:08 +02:00
}
2019-05-21 22:33:24 +02:00
}
return f_ret ;
}
int parity_close ( struct snapraid_parity_handle * handle )
{
unsigned s ;
int f_ret = 0 ;
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
int ret ;
2019-05-19 08:33:08 +02:00
2026-05-21 00:39:03 +02:00
advise_close ( & split - > advise , split - > f ) ;
2016-04-26 21:48:39 +02:00
ret = close ( split - > f ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-04-27 15:43:06 +02:00
/*
* This is a serious error , as it may be the result of a failed write
* identified at later time .
* In a normal file - system ( not NFS ) it should never happen
*/
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error closing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-04-26 21:48:39 +02:00
f_ret = - 1 ;
/* LCOV_EXCL_STOP */
/* continue to close the others */
}
/* reset the descriptor */
split - > f = - 1 ;
2011-03-04 20:59:21 +01:00
}
2011-03-18 22:38:11 +01:00
2016-04-26 21:48:39 +02:00
return f_ret ;
2011-03-12 10:09:59 +01:00
}
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * parity_split_find ( struct snapraid_parity_handle * handle , data_off_t * offset )
2011-03-12 10:09:59 +01:00
{
2016-04-26 21:48:39 +02:00
unsigned s ;
2011-03-04 20:59:21 +01:00
2016-04-26 21:48:39 +02:00
if ( * offset < 0 )
return 0 ;
2011-03-18 22:38:11 +01:00
2017-11-03 23:46:45 +01:00
for ( s = 0 ; s < handle - > split_mac ; + + s ) {
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split = & handle - > split_map [ s ] ;
2016-05-18 20:58:41 +02:00
if ( * offset < split - > size )
2016-04-26 21:48:39 +02:00
return split ;
* offset - = split - > size ;
}
2011-10-09 07:51:25 +02:00
2011-03-18 22:38:11 +01:00
return 0 ;
2011-03-04 20:59:21 +01:00
}
2016-04-26 21:48:39 +02:00
int parity_write ( struct snapraid_parity_handle * handle , block_off_t pos , unsigned char * block_buffer , unsigned block_size )
2011-03-04 20:59:21 +01:00
{
ssize_t write_ret ;
2011-03-12 10:09:59 +01:00
data_off_t offset ;
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split ;
2026-01-25 11:29:41 +01:00
unsigned count ;
2016-05-15 14:18:44 +02:00
int ret ;
2011-03-04 20:59:21 +01:00
2011-03-12 10:09:59 +01:00
offset = pos * ( data_off_t ) block_size ;
2011-03-04 20:59:21 +01:00
2016-04-26 21:48:39 +02:00
split = parity_split_find ( handle , & offset ) ;
if ( ! split ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
errno = ENXIO ;
log_fatal ( errno , " Writing parity data outside range at extra offset % " PRIu64 " . \n " , offset ) ;
2016-04-26 21:48:39 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
2019-05-19 08:33:08 +02:00
/* update the valid range */
if ( split - > valid_size < offset + block_size )
split - > valid_size = offset + block_size ;
2026-08-16 16:09:12 +02:00
bw_limit ( handle - > bw , block_size ) ;
2026-01-25 11:29:41 +01:00
count = 0 ;
do {
write_ret = pwrite ( split - > f , block_buffer + count , block_size - count , offset + count ) ;
if ( write_ret = = - 1 ) {
2026-08-16 16:09:12 +02:00
if ( errno = = EINTR )
continue ;
2026-01-25 11:29:41 +01:00
/* LCOV_EXCL_START */
if ( errno = = ENOSPC ) {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Failed to grow parity file '%s' using write due lack of space. \n " , split - > path ) ;
2026-01-25 11:29:41 +01:00
} else {
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error writing parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2026-01-25 11:29:41 +01:00
}
return - 1 ;
/* LCOV_EXCL_STOP */
2011-03-04 20:59:21 +01:00
}
2026-01-25 11:29:41 +01:00
if ( write_ret = = 0 ) {
/* LCOV_EXCL_START */
2026-01-24 19:19:11 +01:00
errno = ENXIO ;
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Unexpected 0 write to file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2026-01-25 11:29:41 +01:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
count + = write_ret ;
} while ( count < block_size ) ;
2011-03-18 22:38:11 +01:00
2016-05-15 14:18:44 +02:00
ret = advise_write ( & split - > advise , split - > f , offset , block_size ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
log_fatal ( errno , " Error advising parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-05-15 14:18:44 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
2011-03-29 18:27:25 +02:00
2011-03-18 22:38:11 +01:00
return 0 ;
2011-03-04 20:59:21 +01:00
}
2026-06-03 20:49:36 +02:00
int parity_read ( struct snapraid_parity_handle * handle , block_off_t pos , unsigned char * block_buffer , unsigned block_size )
2011-03-04 20:59:21 +01:00
{
ssize_t read_ret ;
2011-03-12 10:09:59 +01:00
data_off_t offset ;
2012-03-13 19:11:09 +01:00
unsigned count ;
2016-04-26 21:48:39 +02:00
struct snapraid_split_handle * split ;
2016-05-15 14:18:44 +02:00
int ret ;
2011-03-04 20:59:21 +01:00
2011-03-12 10:09:59 +01:00
offset = pos * ( data_off_t ) block_size ;
2011-03-04 20:59:21 +01:00
2016-04-26 21:48:39 +02:00
split = parity_split_find ( handle , & offset ) ;
if ( ! split ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
errno = ENXIO ;
2026-06-03 20:49:36 +02:00
log_error ( errno , " Reading parity data outside range at extra offset % " PRIu64 " . \n " , offset ) ;
2011-10-09 07:51:25 +02:00
return - 1 ;
2016-04-26 21:48:39 +02:00
/* LCOV_EXCL_STOP */
2011-10-09 07:51:25 +02:00
}
2019-05-19 08:33:08 +02:00
/* if read is completely out of the valid range */
if ( offset > = split - > valid_size ) {
/* LCOV_EXCL_START */
2026-02-01 20:21:28 +01:00
errno = ENXIO ;
2026-06-03 20:49:36 +02:00
log_error ( errno , " Reading over the end from parity file '%s' at offset % " PRIu64 " for size %u. \n " , split - > path , offset , block_size ) ;
2019-05-19 08:33:08 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
2026-08-16 16:09:12 +02:00
bw_limit ( handle - > bw , block_size ) ;
2012-03-13 19:11:09 +01:00
count = 0 ;
do {
2016-04-26 21:48:39 +02:00
read_ret = pread ( split - > f , block_buffer + count , block_size - count , offset + count ) ;
2026-01-25 11:29:41 +01:00
if ( read_ret = = - 1 ) {
2026-08-16 16:09:12 +02:00
if ( errno = = EINTR )
continue ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-06-03 20:49:36 +02:00
log_error ( errno , " Error reading parity file '%s' at offset % " PRIu64 " for size %u. %s. \n " , split - > path , offset + count , block_size - count , strerror ( errno ) ) ;
2012-03-13 19:11:09 +01:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2012-03-13 19:11:09 +01:00
}
if ( read_ret = = 0 ) {
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_START */
2026-08-16 16:09:12 +02:00
errno = ENXIO ;
2026-06-03 20:49:36 +02:00
log_error ( errno , " Unexpected end of parity file '%s' at offset % " PRIu64 " . %s. \n " , split - > path , offset , strerror ( errno ) ) ;
2012-03-13 19:11:09 +01:00
return - 1 ;
2014-02-12 22:40:00 +01:00
/* LCOV_EXCL_STOP */
2012-03-13 19:11:09 +01:00
}
count + = read_ret ;
} while ( count < block_size ) ;
2011-03-04 20:59:21 +01:00
2016-05-15 14:18:44 +02:00
ret = advise_read ( & split - > advise , split - > f , offset , block_size ) ;
if ( ret ! = 0 ) {
/* LCOV_EXCL_START */
2026-06-03 20:49:36 +02:00
log_error ( errno , " Error advising parity file '%s'. %s. \n " , split - > path , strerror ( errno ) ) ;
2016-05-15 14:18:44 +02:00
return - 1 ;
/* LCOV_EXCL_STOP */
}
2011-03-29 18:27:25 +02:00
2011-03-04 20:59:21 +01:00
return block_size ;
}