2011-03-04 20:59:21 +01:00
/*
* Copyright ( C ) 2011 Andrea Mazzoleni
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "portable.h"
# include "elem.h"
2015-01-02 18:52:04 +01:00
# include "support.h"
2011-03-04 20:59:21 +01:00
# include "util.h"
/****************************************************************************/
/* snapraid */
2016-04-07 21:39:02 +02:00
int BLOCK_HASH_SIZE = HASH_MAX ;
2011-09-20 22:35:15 +02:00
struct snapraid_content * content_alloc ( const char * path , uint64_t dev )
2011-04-25 13:43:51 +02:00
{
struct snapraid_content * content ;
content = malloc_nofail ( sizeof ( struct snapraid_content ) ) ;
2011-11-14 19:21:52 +01:00
pathimport ( content - > content , sizeof ( content - > content ) , path ) ;
2011-09-20 22:35:15 +02:00
content - > device = dev ;
2011-04-25 13:43:51 +02:00
return content ;
}
void content_free ( struct snapraid_content * content )
{
free ( content ) ;
}
2012-10-10 23:32:09 +02:00
struct snapraid_filter * filter_alloc_file ( int direction , const char * pattern )
2011-03-16 23:52:10 +01:00
{
struct snapraid_filter * filter ;
char * i ;
char * first ;
char * last ;
2015-08-03 19:31:07 +02:00
int token_is_valid ;
int token_is_filled ;
2011-03-16 23:52:10 +01:00
filter = malloc_nofail ( sizeof ( struct snapraid_filter ) ) ;
2011-05-03 23:28:03 +02:00
pathimport ( filter - > pattern , sizeof ( filter - > pattern ) , pattern ) ;
2011-04-26 18:51:42 +02:00
filter - > direction = direction ;
2011-03-16 23:52:10 +01:00
/* find first and last slash */
first = 0 ;
last = 0 ;
2015-08-03 19:31:07 +02:00
/* reject invalid tokens, like "<empty>", ".", ".." and more dots */
token_is_valid = 0 ;
token_is_filled = 0 ;
2014-09-27 00:32:39 +02:00
for ( i = filter - > pattern ; * i ; + + i ) {
2011-03-16 23:52:10 +01:00
if ( * i = = ' / ' ) {
2015-08-03 19:31:07 +02:00
/* reject invalid tokens, but accept an empty one as first */
if ( ! token_is_valid & & ( first ! = 0 | | token_is_filled ) ) {
free ( filter ) ;
return 0 ;
}
token_is_valid = 0 ;
token_is_filled = 0 ;
/* update slash position */
2011-03-16 23:52:10 +01:00
if ( ! first )
first = i ;
last = i ;
2015-08-03 19:31:07 +02:00
} else if ( * i ! = ' . ' ) {
token_is_valid = 1 ;
token_is_filled = 1 ;
} else {
token_is_filled = 1 ;
2011-03-16 23:52:10 +01:00
}
}
2015-08-03 19:31:07 +02:00
/* reject invalid tokens, but accept an empty one as last, but not if it's the only one */
if ( ! token_is_valid & & ( first = = 0 | | token_is_filled ) ) {
free ( filter ) ;
return 0 ;
}
2012-10-10 23:32:09 +02:00
/* it's a file filter */
filter - > is_disk = 0 ;
2011-03-16 23:52:10 +01:00
if ( first = = 0 ) {
/* no slash */
filter - > is_path = 0 ;
filter - > is_dir = 0 ;
} else if ( first = = last & & last [ 1 ] = = 0 ) {
/* one slash at the end */
filter - > is_path = 0 ;
filter - > is_dir = 1 ;
last [ 0 ] = 0 ;
} else {
/* at least a slash not at the end */
filter - > is_path = 1 ;
if ( last [ 1 ] = = 0 ) {
filter - > is_dir = 1 ;
last [ 0 ] = 0 ;
} else {
filter - > is_dir = 0 ;
}
2015-05-30 13:18:16 +02:00
/* a slash must be the first char, as we don't support PATH/FILE and PATH/DIR/ */
2011-03-16 23:52:10 +01:00
if ( filter - > pattern [ 0 ] ! = ' / ' ) {
free ( filter ) ;
return 0 ;
}
}
return filter ;
}
2012-10-10 23:32:09 +02:00
struct snapraid_filter * filter_alloc_disk ( int direction , const char * pattern )
{
struct snapraid_filter * filter ;
filter = malloc_nofail ( sizeof ( struct snapraid_filter ) ) ;
pathimport ( filter - > pattern , sizeof ( filter - > pattern ) , pattern ) ;
filter - > direction = direction ;
/* it's a disk filter */
filter - > is_disk = 1 ;
filter - > is_path = 0 ;
filter - > is_dir = 0 ;
/* no slash allowed in disk names */
if ( strchr ( filter - > pattern , ' / ' ) ! = 0 ) {
2014-03-20 22:10:19 +01:00
/* LCOV_EXCL_START */
2012-10-10 23:32:09 +02:00
free ( filter ) ;
return 0 ;
2014-03-20 22:10:19 +01:00
/* LCOV_EXCL_STOP */
2012-10-10 23:32:09 +02:00
}
return filter ;
}
2011-03-16 23:52:10 +01:00
void filter_free ( struct snapraid_filter * filter )
{
free ( filter ) ;
}
2015-01-27 23:32:13 +01:00
const char * filter_type ( struct snapraid_filter * filter , char * out , size_t out_size )
2011-03-16 23:52:10 +01:00
{
2015-01-27 23:32:13 +01:00
const char * direction ;
2016-04-10 22:44:40 +02:00
2015-01-27 23:32:13 +01:00
if ( filter - > direction < 0 )
direction = " exclude " ;
else
direction = " include " ;
if ( filter - > is_disk )
pathprint ( out , out_size , " %s %s: " , direction , filter - > pattern ) ;
else if ( filter - > is_dir )
pathprint ( out , out_size , " %s %s/ " , direction , filter - > pattern ) ;
else
pathprint ( out , out_size , " %s %s " , direction , filter - > pattern ) ;
return out ;
2015-01-27 23:10:38 +01:00
}
static int filter_apply ( struct snapraid_filter * filter , struct snapraid_filter * * reason , const char * path , const char * name , int is_dir )
{
int ret = 0 ;
2015-10-07 22:07:20 +02:00
/* match dirs with dirs and files with files */
2011-03-16 23:52:10 +01:00
if ( filter - > is_dir & & ! is_dir )
2011-04-26 18:51:42 +02:00
return 0 ;
2011-03-16 23:52:10 +01:00
if ( ! filter - > is_dir & & is_dir )
2011-04-26 18:51:42 +02:00
return 0 ;
2011-03-16 23:52:10 +01:00
if ( filter - > is_path ) {
/* skip initial slash, as always missing from the path */
2013-05-14 21:34:51 +02:00
if ( fnmatch ( filter - > pattern + 1 , path , FNM_PATHNAME | FNM_CASEINSENSITIVE_FOR_WIN ) = = 0 )
2015-01-27 23:10:38 +01:00
ret = filter - > direction ;
2011-03-16 23:52:10 +01:00
} else {
2013-05-14 21:34:51 +02:00
if ( fnmatch ( filter - > pattern , name , FNM_CASEINSENSITIVE_FOR_WIN ) = = 0 )
2015-01-27 23:10:38 +01:00
ret = filter - > direction ;
2011-03-16 23:52:10 +01:00
}
2015-01-27 23:10:38 +01:00
if ( reason ! = 0 & & ret < 0 )
* reason = filter ;
return ret ;
2011-03-16 23:52:10 +01:00
}
2015-01-27 23:10:38 +01:00
static int filter_recurse ( struct snapraid_filter * filter , struct snapraid_filter * * reason , const char * const_path , int is_dir )
2011-03-30 00:14:43 +02:00
{
2011-03-30 17:02:02 +02:00
char path [ PATH_MAX ] ;
char * name ;
unsigned i ;
2011-04-26 18:51:42 +02:00
pathcpy ( path , sizeof ( path ) , const_path ) ;
2011-03-30 17:02:02 +02:00
2011-04-26 18:51:42 +02:00
/* filter for all the directories */
2011-03-30 17:02:02 +02:00
name = path ;
2014-09-27 00:32:39 +02:00
for ( i = 0 ; path [ i ] ! = 0 ; + + i ) {
2011-03-30 17:02:02 +02:00
if ( path [ i ] = = ' / ' ) {
/* set a terminator */
path [ i ] = 0 ;
/* filter the directory */
2015-01-27 23:10:38 +01:00
if ( filter_apply ( filter , reason , path , name , 1 ) ! = 0 )
2011-04-26 18:51:42 +02:00
return filter - > direction ;
2011-03-30 17:02:02 +02:00
/* restore the slash */
path [ i ] = ' / ' ;
/* next name */
name = path + i + 1 ;
}
}
/* filter the final file */
2015-01-27 23:10:38 +01:00
if ( filter_apply ( filter , reason , path , name , is_dir ) ! = 0 )
2011-04-26 18:51:42 +02:00
return filter - > direction ;
return 0 ;
}
2016-05-14 21:59:33 +02:00
static int filter_element ( tommy_list * filterlist , struct snapraid_filter * * reason , const char * disk , const char * sub , int is_dir , int is_def_include )
2011-04-26 18:51:42 +02:00
{
tommy_node * i ;
int direction = 1 ; /* by default include all */
/* for each filter */
2014-09-27 00:32:39 +02:00
for ( i = tommy_list_head ( filterlist ) ; i ! = 0 ; i = i - > next ) {
2011-04-26 18:51:42 +02:00
int ret ;
struct snapraid_filter * filter = i - > data ;
2012-10-10 23:32:09 +02:00
if ( filter - > is_disk ) {
2013-05-14 21:34:51 +02:00
if ( fnmatch ( filter - > pattern , disk , FNM_CASEINSENSITIVE_FOR_WIN ) = = 0 )
2012-10-10 23:32:09 +02:00
ret = filter - > direction ;
else
ret = 0 ;
2015-01-27 23:10:38 +01:00
if ( reason ! = 0 & & ret < 0 )
* reason = filter ;
2012-10-10 23:32:09 +02:00
} else {
2015-01-27 23:10:38 +01:00
ret = filter_recurse ( filter , reason , sub , is_dir ) ;
2012-10-10 23:32:09 +02:00
}
2011-04-26 18:51:42 +02:00
if ( ret > 0 ) {
/* include the file */
2012-07-03 21:51:50 +02:00
return 0 ;
2011-04-26 18:51:42 +02:00
} else if ( ret < 0 ) {
/* exclude the file */
2012-07-03 21:51:50 +02:00
return - 1 ;
2011-04-26 18:51:42 +02:00
} else {
/* default is opposite of the last filter */
direction = - filter - > direction ;
2015-01-27 23:10:38 +01:00
if ( reason ! = 0 & & direction < 0 )
* reason = filter ;
2011-04-26 18:51:42 +02:00
/* continue with the next one */
}
}
2012-06-29 20:35:43 +02:00
/* directories are always included by default, otherwise we cannot apply rules */
/* to the contained files */
2016-05-14 21:59:33 +02:00
if ( is_def_include )
2012-06-29 20:35:43 +02:00
return 0 ;
/* files are excluded/included depending of the last rule processed */
2011-04-26 18:51:42 +02:00
if ( direction < 0 )
return - 1 ;
2011-03-30 17:02:02 +02:00
2011-04-26 18:51:42 +02:00
return 0 ;
2011-03-30 00:14:43 +02:00
}
2015-01-27 23:10:38 +01:00
int filter_path ( tommy_list * filterlist , struct snapraid_filter * * reason , const char * disk , const char * sub )
2011-09-18 22:43:41 +02:00
{
2016-05-14 21:59:33 +02:00
return filter_element ( filterlist , reason , disk , sub , 0 , 0 ) ;
2011-09-18 22:43:41 +02:00
}
2016-05-14 21:59:33 +02:00
int filter_subdir ( tommy_list * filterlist , struct snapraid_filter * * reason , const char * disk , const char * sub )
2011-09-18 22:43:41 +02:00
{
2016-05-14 21:59:33 +02:00
return filter_element ( filterlist , reason , disk , sub , 1 , 1 ) ;
}
int filter_emptydir ( tommy_list * filterlist , struct snapraid_filter * * reason , const char * disk , const char * sub )
{
return filter_element ( filterlist , reason , disk , sub , 1 , 0 ) ;
2011-09-18 22:43:41 +02:00
}
2013-03-01 18:29:04 +01:00
int filter_existence ( int filter_missing , const char * dir , const char * sub )
2013-02-24 11:33:09 +01:00
{
2013-03-01 18:29:04 +01:00
char path [ PATH_MAX ] ;
struct stat st ;
if ( ! filter_missing )
return 0 ;
/* we directly check if in the disk the file is present or not */
pathprint ( path , sizeof ( path ) , " %s%s " , dir , sub ) ;
2014-09-27 00:32:39 +02:00
2013-03-01 18:29:04 +01:00
if ( lstat ( path , & st ) ! = 0 ) {
/* if the file doesn't exist, we don't filter it out */
if ( errno = = ENOENT )
return 0 ;
2014-02-03 22:40:51 +01:00
/* LCOV_EXCL_START */
2015-04-20 22:07:42 +02:00
log_fatal ( " Error in stat file '%s'. %s. \n " , path , strerror ( errno ) ) ;
2013-03-01 18:29:04 +01:00
exit ( EXIT_FAILURE ) ;
2014-02-03 22:40:51 +01:00
/* LCOV_EXCL_STOP */
2013-03-01 18:29:04 +01:00
}
2013-08-18 19:24:55 +02:00
/* the file is present, so we filter it out */
return 1 ;
}
2015-10-01 18:19:48 +02:00
int filter_correctness ( int filter_error , tommy_arrayblkof * infoarr , struct snapraid_disk * disk , struct snapraid_file * file )
2013-08-18 19:24:55 +02:00
{
unsigned i ;
if ( ! filter_error )
return 0 ;
/* check each block of the file */
2014-09-27 00:32:39 +02:00
for ( i = 0 ; i < file - > blockmax ; + + i ) {
2015-10-01 18:19:48 +02:00
block_off_t parity_pos = fs_file2par_get ( disk , file , i ) ;
snapraid_info info = info_get ( infoarr , parity_pos ) ;
2013-08-18 19:24:55 +02:00
/* if the file has a bad block, don't exclude it */
if ( info_get_bad ( info ) )
return 0 ;
}
/* the file is correct, so we filter it out */
2013-03-01 18:29:04 +01:00
return 1 ;
2013-02-24 11:33:09 +01:00
}
2011-09-18 22:43:41 +02:00
int filter_content ( tommy_list * contentlist , const char * path )
{
tommy_node * i ;
2014-09-27 00:32:39 +02:00
for ( i = tommy_list_head ( contentlist ) ; i ! = 0 ; i = i - > next ) {
2011-09-18 22:43:41 +02:00
struct snapraid_content * content = i - > data ;
2012-04-14 14:03:49 +02:00
char tmp [ PATH_MAX ] ;
2011-09-18 22:43:41 +02:00
2013-06-01 22:49:15 +02:00
if ( pathcmp ( content - > content , path ) = = 0 )
2011-09-18 22:43:41 +02:00
return - 1 ;
2012-04-14 14:03:49 +02:00
/* exclude also the ".tmp" copy used to save it */
pathprint ( tmp , sizeof ( tmp ) , " %s.tmp " , content - > content ) ;
2013-06-01 22:49:15 +02:00
if ( pathcmp ( tmp , path ) = = 0 )
2012-04-14 14:03:49 +02:00
return - 1 ;
2014-06-13 18:23:24 +02:00
/* exclude also the ".lock" file */
pathprint ( tmp , sizeof ( tmp ) , " %s.lock " , content - > content ) ;
if ( pathcmp ( tmp , path ) = = 0 )
return - 1 ;
2011-09-18 22:43:41 +02:00
}
return 0 ;
}
2014-10-04 10:27:23 +02:00
struct snapraid_file * file_alloc ( unsigned block_size , const char * sub , data_off_t size , uint64_t mtime_sec , int mtime_nsec , uint64_t inode , uint64_t physical )
2011-03-04 20:59:21 +01:00
{
struct snapraid_file * file ;
2011-03-12 10:09:59 +01:00
block_off_t i ;
2011-03-04 20:59:21 +01:00
file = malloc_nofail ( sizeof ( struct snapraid_file ) ) ;
2013-02-26 21:26:45 +01:00
file - > sub = strdup_nofail ( sub ) ;
2011-03-04 20:59:21 +01:00
file - > size = size ;
file - > blockmax = ( size + block_size - 1 ) / block_size ;
2012-07-10 23:24:31 +02:00
file - > mtime_sec = mtime_sec ;
file - > mtime_nsec = mtime_nsec ;
2011-03-20 22:36:49 +01:00
file - > inode = inode ;
2013-06-25 22:41:10 +02:00
file - > physical = physical ;
2011-04-28 23:09:19 +02:00
file - > flag = 0 ;
2016-04-07 21:39:02 +02:00
file - > blockvec = malloc_nofail ( file - > blockmax * block_sizeof ( ) ) ;
2011-03-04 20:59:21 +01:00
2014-09-27 00:32:39 +02:00
for ( i = 0 ; i < file - > blockmax ; + + i ) {
2016-04-07 21:39:02 +02:00
struct snapraid_block * block = file_block ( file , i ) ;
block_state_set ( block , BLOCK_STATE_CHG ) ;
hash_invalid_set ( block - > hash ) ;
2011-03-04 20:59:21 +01:00
}
return file ;
}
2015-10-01 18:19:48 +02:00
struct snapraid_file * file_dup ( struct snapraid_file * copy )
{
struct snapraid_file * file ;
block_off_t i ;
file = malloc_nofail ( sizeof ( struct snapraid_file ) ) ;
file - > sub = strdup_nofail ( copy - > sub ) ;
file - > size = copy - > size ;
file - > blockmax = copy - > blockmax ;
file - > mtime_sec = copy - > mtime_sec ;
file - > mtime_nsec = copy - > mtime_nsec ;
file - > inode = copy - > inode ;
file - > physical = copy - > physical ;
file - > flag = copy - > flag ;
2016-04-07 21:39:02 +02:00
file - > blockvec = malloc_nofail ( file - > blockmax * block_sizeof ( ) ) ;
2015-10-01 18:19:48 +02:00
for ( i = 0 ; i < file - > blockmax ; + + i ) {
2016-04-07 21:39:02 +02:00
struct snapraid_block * block = file_block ( file , i ) ;
struct snapraid_block * copy_block = file_block ( copy , i ) ;
block - > state = copy_block - > state ;
memcpy ( block - > hash , copy_block - > hash , BLOCK_HASH_SIZE ) ;
2015-10-01 18:19:48 +02:00
}
return file ;
}
2011-03-04 20:59:21 +01:00
void file_free ( struct snapraid_file * file )
{
2013-02-26 21:26:45 +01:00
free ( file - > sub ) ;
2015-10-01 18:19:48 +02:00
file - > sub = 0 ;
2011-03-04 20:59:21 +01:00
free ( file - > blockvec ) ;
2015-10-01 18:19:48 +02:00
file - > blockvec = 0 ;
2011-03-04 20:59:21 +01:00
free ( file ) ;
}
2011-03-30 00:14:43 +02:00
2013-02-26 21:26:45 +01:00
void file_rename ( struct snapraid_file * file , const char * sub )
{
free ( file - > sub ) ;
file - > sub = strdup_nofail ( sub ) ;
}
2014-02-12 20:02:35 +01:00
void file_copy ( struct snapraid_file * src_file , struct snapraid_file * dst_file )
{
block_off_t i ;
if ( src_file - > size ! = dst_file - > size ) {
/* LCOV_EXCL_START */
2015-04-20 22:07:42 +02:00
log_fatal ( " Internal inconsistency in copy file with different size \n " ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2014-02-12 20:02:35 +01:00
/* LCOV_EXCL_STOP */
}
2014-05-15 23:45:51 +02:00
if ( src_file - > mtime_sec ! = dst_file - > mtime_sec ) {
/* LCOV_EXCL_START */
2015-04-20 22:07:42 +02:00
log_fatal ( " Internal inconsistency in copy file with different mtime_sec \n " ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2014-05-15 23:45:51 +02:00
/* LCOV_EXCL_STOP */
}
if ( src_file - > mtime_nsec ! = dst_file - > mtime_nsec ) {
/* LCOV_EXCL_START */
2015-04-20 22:07:42 +02:00
log_fatal ( " Internal inconsistency in copy file with different mtime_nsec \n " ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2014-05-15 23:45:51 +02:00
/* LCOV_EXCL_STOP */
}
2014-09-27 00:32:39 +02:00
for ( i = 0 ; i < dst_file - > blockmax ; + + i ) {
2014-02-12 20:02:35 +01:00
/* set a block with hash computed but without parity */
2016-04-07 21:39:02 +02:00
block_state_set ( file_block ( dst_file , i ) , BLOCK_STATE_REP ) ;
2014-02-12 20:02:35 +01:00
/* copy the hash */
2016-04-07 21:39:02 +02:00
memcpy ( file_block ( dst_file , i ) - > hash , file_block ( src_file , i ) - > hash , BLOCK_HASH_SIZE ) ;
2014-02-12 20:02:35 +01:00
}
2014-05-15 23:45:51 +02:00
file_flag_set ( dst_file , FILE_IS_COPY ) ;
2014-02-12 20:02:35 +01:00
}
const char * file_name ( const struct snapraid_file * file )
2011-03-30 00:14:43 +02:00
{
const char * r = strrchr ( file - > sub , ' / ' ) ;
2014-09-27 00:32:39 +02:00
2011-03-30 00:14:43 +02:00
if ( ! r )
r = file - > sub ;
else
+ + r ;
return r ;
}
2011-03-04 20:59:21 +01:00
2015-10-03 10:43:02 +02:00
unsigned file_block_size ( struct snapraid_file * file , block_off_t file_pos , unsigned block_size )
{
/* if it's the last block */
if ( file_pos + 1 = = file - > blockmax ) {
2015-10-08 22:19:52 +02:00
unsigned block_remainder ;
2015-10-03 10:43:02 +02:00
if ( file - > size = = 0 )
return 0 ;
2015-10-08 22:19:52 +02:00
block_remainder = file - > size % block_size ;
if ( block_remainder = = 0 )
block_remainder = block_size ;
return block_remainder ;
2015-10-03 10:43:02 +02:00
}
return block_size ;
}
int file_block_is_last ( struct snapraid_file * file , block_off_t file_pos )
{
if ( file_pos = = 0 & & file - > blockmax = = 0 )
return 1 ;
if ( file_pos > = file - > blockmax ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file block position \n " ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-10-03 10:43:02 +02:00
/* LCOV_EXCL_STOP */
}
return file_pos = = file - > blockmax - 1 ;
}
2013-06-25 22:41:10 +02:00
int file_inode_compare_to_arg ( const void * void_arg , const void * void_data )
2011-03-04 20:59:21 +01:00
{
2011-03-20 22:36:49 +01:00
const uint64_t * arg = void_arg ;
2011-03-04 20:59:21 +01:00
const struct snapraid_file * file = void_data ;
2014-09-27 00:32:39 +02:00
2011-03-20 22:36:49 +01:00
if ( * arg < file - > inode )
return - 1 ;
if ( * arg > file - > inode )
return 1 ;
return 0 ;
2011-03-04 20:59:21 +01:00
}
2013-06-25 22:41:10 +02:00
int file_inode_compare ( const void * void_a , const void * void_b )
{
const struct snapraid_file * file_a = void_a ;
const struct snapraid_file * file_b = void_b ;
2014-09-27 00:32:39 +02:00
2013-06-25 22:41:10 +02:00
if ( file_a - > inode < file_b - > inode )
return - 1 ;
if ( file_a - > inode > file_b - > inode )
return 1 ;
return 0 ;
}
2014-02-12 20:02:35 +01:00
int file_path_compare ( const void * void_a , const void * void_b )
2013-06-25 22:41:10 +02:00
{
const struct snapraid_file * file_a = void_a ;
const struct snapraid_file * file_b = void_b ;
2014-09-27 00:32:39 +02:00
2013-06-25 22:41:10 +02:00
return strcmp ( file_a - > sub , file_b - > sub ) ;
}
int file_physical_compare ( const void * void_a , const void * void_b )
{
const struct snapraid_file * file_a = void_a ;
const struct snapraid_file * file_b = void_b ;
2014-09-27 00:32:39 +02:00
2013-06-25 22:41:10 +02:00
if ( file_a - > physical < file_b - > physical )
return - 1 ;
if ( file_a - > physical > file_b - > physical )
return 1 ;
return 0 ;
}
2014-02-12 20:02:35 +01:00
int file_path_compare_to_arg ( const void * void_arg , const void * void_data )
2011-10-09 23:41:08 +02:00
{
const char * arg = void_arg ;
const struct snapraid_file * file = void_data ;
2014-09-27 00:32:39 +02:00
2011-10-09 23:41:08 +02:00
return strcmp ( arg , file - > sub ) ;
}
2014-02-12 20:02:35 +01:00
int file_name_compare ( const void * void_a , const void * void_b )
{
const struct snapraid_file * file_a = void_a ;
const struct snapraid_file * file_b = void_b ;
const char * name_a = file_name ( file_a ) ;
const char * name_b = file_name ( file_b ) ;
return strcmp ( name_a , name_b ) ;
}
int file_stamp_compare ( const void * void_a , const void * void_b )
{
const struct snapraid_file * file_a = void_a ;
const struct snapraid_file * file_b = void_b ;
if ( file_a - > size < file_b - > size )
return - 1 ;
if ( file_a - > size > file_b - > size )
return 1 ;
if ( file_a - > mtime_sec < file_b - > mtime_sec )
return - 1 ;
if ( file_a - > mtime_sec > file_b - > mtime_sec )
return 1 ;
if ( file_a - > mtime_nsec < file_b - > mtime_nsec )
return - 1 ;
if ( file_a - > mtime_nsec > file_b - > mtime_nsec )
return 1 ;
return 0 ;
}
int file_namestamp_compare ( const void * void_a , const void * void_b )
{
int ret ;
ret = file_name_compare ( void_a , void_b ) ;
if ( ret ! = 0 )
return ret ;
return file_stamp_compare ( void_a , void_b ) ;
}
2014-05-15 23:45:51 +02:00
int file_pathstamp_compare ( const void * void_a , const void * void_b )
{
int ret ;
ret = file_path_compare ( void_a , void_b ) ;
if ( ret ! = 0 )
return ret ;
return file_stamp_compare ( void_a , void_b ) ;
}
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent_alloc ( block_off_t parity_pos , struct snapraid_file * file , block_off_t file_pos , block_off_t count )
2015-10-04 22:02:05 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
2015-10-04 22:02:05 +02:00
2015-11-18 22:10:50 +01:00
if ( count = = 0 ) {
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when allocating empty extent for file '%s' at position '%u/%u' \n " , file - > sub , file_pos , file - > blockmax ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-11-18 22:10:50 +01:00
/* LCOV_EXCL_STOP */
}
if ( file_pos + count > file - > blockmax ) {
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when allocating overflowing extent for file '%s' at position '%u:%u/%u' \n " , file - > sub , file_pos , count , file - > blockmax ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-11-18 22:10:50 +01:00
/* LCOV_EXCL_STOP */
}
2015-11-16 22:54:00 +01:00
2016-05-23 22:10:05 +02:00
extent = malloc_nofail ( sizeof ( struct snapraid_extent ) ) ;
extent - > parity_pos = parity_pos ;
extent - > file = file ;
extent - > file_pos = file_pos ;
extent - > count = count ;
2015-10-04 22:02:05 +02:00
2016-05-23 22:10:05 +02:00
return extent ;
2015-10-04 22:02:05 +02:00
}
2016-05-23 22:10:05 +02:00
void extent_free ( struct snapraid_extent * extent )
2015-10-04 22:02:05 +02:00
{
2016-05-23 22:10:05 +02:00
free ( extent ) ;
2015-10-04 22:02:05 +02:00
}
2016-05-23 22:10:05 +02:00
int extent_parity_compare ( const void * void_a , const void * void_b )
2015-10-04 22:02:05 +02:00
{
2016-05-23 22:10:05 +02:00
const struct snapraid_extent * arg_a = void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-04 22:02:05 +02:00
if ( arg_a - > parity_pos < arg_b - > parity_pos )
return - 1 ;
if ( arg_a - > parity_pos > arg_b - > parity_pos )
return 1 ;
return 0 ;
}
2016-05-23 22:10:05 +02:00
int extent_file_compare ( const void * void_a , const void * void_b )
2015-10-04 22:02:05 +02:00
{
2016-05-23 22:10:05 +02:00
const struct snapraid_extent * arg_a = void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-04 22:02:05 +02:00
if ( arg_a - > file < arg_b - > file )
return - 1 ;
if ( arg_a - > file > arg_b - > file )
return 1 ;
if ( arg_a - > file_pos < arg_b - > file_pos )
return - 1 ;
if ( arg_a - > file_pos > arg_b - > file_pos )
return 1 ;
return 0 ;
}
2013-02-28 21:56:02 +01:00
struct snapraid_link * link_alloc ( const char * sub , const char * linkto , unsigned link_flag )
2011-08-26 14:18:38 +02:00
{
2015-10-08 22:19:52 +02:00
struct snapraid_link * slink ;
2011-08-26 14:18:38 +02:00
2015-10-08 22:19:52 +02:00
slink = malloc_nofail ( sizeof ( struct snapraid_link ) ) ;
slink - > sub = strdup_nofail ( sub ) ;
slink - > linkto = strdup_nofail ( linkto ) ;
slink - > flag = link_flag ;
2011-08-26 14:18:38 +02:00
2015-10-08 22:19:52 +02:00
return slink ;
2011-08-26 14:18:38 +02:00
}
2015-10-08 22:19:52 +02:00
void link_free ( struct snapraid_link * slink )
2011-08-26 14:18:38 +02:00
{
2015-10-08 22:19:52 +02:00
free ( slink - > sub ) ;
free ( slink - > linkto ) ;
free ( slink ) ;
2011-08-26 14:18:38 +02:00
}
2013-10-19 13:24:35 +02:00
int link_name_compare_to_arg ( const void * void_arg , const void * void_data )
2011-08-26 14:18:38 +02:00
{
const char * arg = void_arg ;
2015-10-08 22:19:52 +02:00
const struct snapraid_link * slink = void_data ;
2014-09-27 00:32:39 +02:00
2015-10-08 22:19:52 +02:00
return strcmp ( arg , slink - > sub ) ;
2011-08-26 14:18:38 +02:00
}
2013-10-19 13:24:35 +02:00
int link_alpha_compare ( const void * void_a , const void * void_b )
{
2015-10-08 22:19:52 +02:00
const struct snapraid_link * slink_a = void_a ;
const struct snapraid_link * slink_b = void_b ;
2014-09-27 00:32:39 +02:00
2015-10-08 22:19:52 +02:00
return strcmp ( slink_a - > sub , slink_b - > sub ) ;
2013-10-19 13:24:35 +02:00
}
2013-01-27 16:44:04 +01:00
struct snapraid_dir * dir_alloc ( const char * sub )
{
struct snapraid_dir * dir ;
dir = malloc_nofail ( sizeof ( struct snapraid_dir ) ) ;
2013-05-30 23:50:26 +02:00
dir - > sub = strdup_nofail ( sub ) ;
2013-01-27 16:44:04 +01:00
dir - > flag = 0 ;
return dir ;
}
void dir_free ( struct snapraid_dir * dir )
{
2013-05-30 23:50:26 +02:00
free ( dir - > sub ) ;
2013-01-27 16:44:04 +01:00
free ( dir ) ;
}
int dir_name_compare ( const void * void_arg , const void * void_data )
{
const char * arg = void_arg ;
const struct snapraid_dir * dir = void_data ;
2014-09-27 00:32:39 +02:00
2013-01-27 16:44:04 +01:00
return strcmp ( arg , dir - > sub ) ;
}
2015-12-28 12:09:13 +01:00
struct snapraid_disk * disk_alloc ( const char * name , const char * dir , uint64_t dev , const char * uuid , int skip )
2011-03-04 20:59:21 +01:00
{
struct snapraid_disk * disk ;
disk = malloc_nofail ( sizeof ( struct snapraid_disk ) ) ;
2011-03-16 23:52:10 +01:00
pathcpy ( disk - > name , sizeof ( disk - > name ) , name ) ;
2011-05-02 20:32:54 +02:00
pathimport ( disk - > dir , sizeof ( disk - > dir ) , dir ) ;
2015-12-28 12:09:13 +01:00
pathcpy ( disk - > uuid , sizeof ( disk - > uuid ) , uuid ) ;
2011-03-12 10:23:42 +01:00
/* ensure that the dir terminate with "/" if it isn't empty */
2011-03-16 23:52:10 +01:00
pathslash ( disk - > dir , sizeof ( disk - > dir ) ) ;
2011-03-12 10:23:42 +01:00
2016-03-18 18:45:35 +01:00
# if HAVE_PTHREAD
2016-02-13 15:35:23 +01:00
thread_mutex_init ( & disk - > fs_mutex , 0 ) ;
2016-03-18 18:45:35 +01:00
# endif
2016-01-01 10:00:18 +01:00
2015-04-08 22:56:44 +02:00
disk - > smartctl [ 0 ] = 0 ;
2011-09-20 22:35:15 +02:00
disk - > device = dev ;
2014-06-25 22:32:36 +02:00
disk - > tick = 0 ;
2017-11-19 19:33:47 +01:00
disk - > cached_blocks = 0 ;
disk - > progress_file = 0 ;
2014-11-09 19:14:29 +01:00
disk - > total_blocks = 0 ;
disk - > free_blocks = 0 ;
2011-03-04 20:59:21 +01:00
disk - > first_free_block = 0 ;
2013-12-14 17:54:04 +01:00
disk - > has_volatile_inodes = 0 ;
2017-10-29 18:07:01 +01:00
disk - > has_volatile_hardlinks = 0 ;
2013-12-14 17:54:04 +01:00
disk - > has_unreliable_physical = 0 ;
disk - > has_different_uuid = 0 ;
2015-12-28 12:09:13 +01:00
disk - > has_unsupported_uuid = * uuid = = 0 ; /* empty UUID means unsupported */
2014-01-04 17:42:45 +01:00
disk - > had_empty_uuid = 0 ;
2014-11-09 10:51:48 +01:00
disk - > mapping_idx = - 1 ;
2015-10-16 23:17:38 +02:00
disk - > skip_access = skip ;
2011-03-04 20:59:21 +01:00
tommy_list_init ( & disk - > filelist ) ;
2013-02-24 19:02:53 +01:00
tommy_list_init ( & disk - > deletedlist ) ;
2011-03-20 22:36:49 +01:00
tommy_hashdyn_init ( & disk - > inodeset ) ;
2011-10-09 23:41:08 +02:00
tommy_hashdyn_init ( & disk - > pathset ) ;
2014-02-12 20:02:35 +01:00
tommy_hashdyn_init ( & disk - > stampset ) ;
2011-08-26 14:18:38 +02:00
tommy_list_init ( & disk - > linklist ) ;
tommy_hashdyn_init ( & disk - > linkset ) ;
2013-01-27 16:44:04 +01:00
tommy_list_init ( & disk - > dirlist ) ;
tommy_hashdyn_init ( & disk - > dirset ) ;
2016-05-23 22:10:05 +02:00
tommy_tree_init ( & disk - > fs_parity , extent_parity_compare ) ;
tommy_tree_init ( & disk - > fs_file , extent_file_compare ) ;
2015-10-04 23:47:06 +02:00
disk - > fs_last = 0 ;
2011-03-04 20:59:21 +01:00
return disk ;
}
void disk_free ( struct snapraid_disk * disk )
{
2011-12-08 20:37:27 +01:00
tommy_list_foreach ( & disk - > filelist , ( tommy_foreach_func * ) file_free ) ;
2015-10-01 23:22:21 +02:00
tommy_list_foreach ( & disk - > deletedlist , ( tommy_foreach_func * ) file_free ) ;
2016-05-23 22:10:05 +02:00
tommy_tree_foreach ( & disk - > fs_file , ( tommy_foreach_func * ) extent_free ) ;
2011-03-20 22:36:49 +01:00
tommy_hashdyn_done ( & disk - > inodeset ) ;
2011-10-09 23:41:08 +02:00
tommy_hashdyn_done ( & disk - > pathset ) ;
2014-02-12 20:02:35 +01:00
tommy_hashdyn_done ( & disk - > stampset ) ;
2011-12-08 20:37:27 +01:00
tommy_list_foreach ( & disk - > linklist , ( tommy_foreach_func * ) link_free ) ;
2011-08-26 14:18:38 +02:00
tommy_hashdyn_done ( & disk - > linkset ) ;
2013-01-27 16:44:04 +01:00
tommy_list_foreach ( & disk - > dirlist , ( tommy_foreach_func * ) dir_free ) ;
tommy_hashdyn_done ( & disk - > dirset ) ;
2016-01-01 10:00:18 +01:00
2016-03-18 18:45:35 +01:00
# if HAVE_PTHREAD
2016-02-13 15:35:23 +01:00
thread_mutex_destroy ( & disk - > fs_mutex ) ;
2016-03-18 18:45:35 +01:00
# endif
2016-01-01 10:00:18 +01:00
2011-03-04 20:59:21 +01:00
free ( disk ) ;
}
2011-03-06 22:52:50 +01:00
2016-01-01 10:00:18 +01:00
static inline void fs_lock ( struct snapraid_disk * disk )
{
2016-03-18 18:45:35 +01:00
# if HAVE_PTHREAD
2016-02-13 15:35:23 +01:00
thread_mutex_lock ( & disk - > fs_mutex ) ;
2016-03-18 18:45:35 +01:00
# else
( void ) disk ;
# endif
2016-01-01 10:00:18 +01:00
}
static inline void fs_unlock ( struct snapraid_disk * disk )
{
2016-03-18 18:45:35 +01:00
# if HAVE_PTHREAD
2016-02-13 15:35:23 +01:00
thread_mutex_unlock ( & disk - > fs_mutex ) ;
2016-03-18 18:45:35 +01:00
# else
( void ) disk ;
# endif
2016-01-01 10:00:18 +01:00
}
2016-05-23 22:10:05 +02:00
struct extent_disk_empty {
2015-10-04 22:02:05 +02:00
block_off_t blockmax ;
} ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/**
2016-05-23 22:10:05 +02:00
* Compare the extent if inside the specified blockmax .
2015-10-04 22:02:05 +02:00
*/
2016-05-23 22:10:05 +02:00
static int extent_disk_empty_compare_unlock ( const void * void_a , const void * void_b )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
const struct extent_disk_empty * arg_a = void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/* if the block is inside the specified blockmax, it's found */
if ( arg_a - > blockmax > arg_b - > parity_pos )
return 0 ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/* otherwise search for a smaller one */
return - 1 ;
2015-10-01 18:19:48 +02:00
}
2016-01-01 10:00:18 +01:00
int fs_is_empty ( struct snapraid_disk * disk , block_off_t blockmax )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
struct extent_disk_empty arg = { blockmax } ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/* if there is an element, it's not empty */
/* even if links and dirs have no block allocation */
if ( ! tommy_list_empty ( & disk - > filelist ) )
return 0 ;
if ( ! tommy_list_empty ( & disk - > linklist ) )
return 0 ;
if ( ! tommy_list_empty ( & disk - > dirlist ) )
2015-10-01 18:19:48 +02:00
return 0 ;
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2016-05-23 22:10:05 +02:00
/* search for any extent inside blockmax */
if ( tommy_tree_search_compare ( & disk - > fs_parity , extent_disk_empty_compare_unlock , & arg ) ! = 0 ) {
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return 0 ;
2016-01-01 10:00:18 +01:00
}
2015-10-03 10:43:02 +02:00
2015-10-04 22:02:05 +02:00
/* finally, it's empty */
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return 1 ;
2015-10-01 18:19:48 +02:00
}
2016-05-23 22:10:05 +02:00
struct extent_disk_size {
2015-10-04 22:02:05 +02:00
block_off_t size ;
} ;
/**
2016-05-23 22:10:05 +02:00
* Compare the extent by highest parity position .
2015-10-04 22:02:05 +02:00
*
* The maximum parity position is stored as size .
*/
2016-05-23 22:10:05 +02:00
static int extent_disk_size_compare_unlock ( const void * void_a , const void * void_b )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
struct extent_disk_size * arg_a = ( void * ) void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/* get the maximum size */
if ( arg_a - > size < arg_b - > parity_pos + arg_b - > count )
arg_a - > size = arg_b - > parity_pos + arg_b - > count ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/* search always for a bigger one */
return 1 ;
2015-10-01 18:19:48 +02:00
}
2016-01-01 10:00:18 +01:00
block_off_t fs_size ( struct snapraid_disk * disk )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
struct extent_disk_size arg = { 0 } ;
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2016-05-23 22:10:05 +02:00
tommy_tree_search_compare ( & disk - > fs_parity , extent_disk_size_compare_unlock , & arg ) ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return arg . size ;
}
2015-10-01 18:19:48 +02:00
2016-05-23 22:10:05 +02:00
struct extent_check {
const struct snapraid_extent * prev ;
2015-10-05 21:40:44 +02:00
int result ;
} ;
2016-05-23 22:10:05 +02:00
static void extent_parity_check_foreach_unlock ( void * void_arg , void * void_obj )
2015-10-05 21:40:44 +02:00
{
2016-05-23 22:10:05 +02:00
struct extent_check * arg = void_arg ;
const struct snapraid_extent * obj = void_obj ;
const struct snapraid_extent * prev = arg - > prev ;
2015-10-05 21:40:44 +02:00
/* set the next previous block */
arg - > prev = obj ;
/* stop reporting if too many errors */
if ( arg - > result > 100 ) {
/* LCOV_EXCL_START */
return ;
/* LCOV_EXCL_STOP */
}
2015-11-16 22:54:00 +01:00
if ( obj - > count = = 0 ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in parity count zero for file '%s' at '%u' \n " ,
obj - > file - > sub , obj - > parity_pos ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
2015-10-05 21:40:44 +02:00
/* check only if there is a previous block */
if ( ! prev )
return ;
/* check the order */
if ( prev - > parity_pos > = obj - > parity_pos ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in parity order for files '%s' at '%u:%u' and '%s' at '%u:%u' \n " ,
prev - > file - > sub , prev - > parity_pos , prev - > count , obj - > file - > sub , obj - > parity_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
2016-05-23 22:10:05 +02:00
/* check that the extents don't overlap */
2015-10-05 21:40:44 +02:00
if ( prev - > parity_pos + prev - > count > obj - > parity_pos ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency for parity overlap for files '%s' at '%u:%u' and '%s' at '%u:%u' \n " ,
prev - > file - > sub , prev - > parity_pos , prev - > count , obj - > file - > sub , obj - > parity_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
}
2016-05-23 22:10:05 +02:00
static void extent_file_check_foreach_unlock ( void * void_arg , void * void_obj )
2015-10-05 21:40:44 +02:00
{
2016-05-23 22:10:05 +02:00
struct extent_check * arg = void_arg ;
const struct snapraid_extent * obj = void_obj ;
const struct snapraid_extent * prev = arg - > prev ;
2015-10-05 21:40:44 +02:00
/* set the next previous block */
arg - > prev = obj ;
/* stop reporting if too many errors */
if ( arg - > result > 100 ) {
/* LCOV_EXCL_START */
return ;
/* LCOV_EXCL_STOP */
}
2015-11-16 22:54:00 +01:00
if ( obj - > count = = 0 ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file count zero for file '%s' at '%u' \n " ,
obj - > file - > sub , obj - > file_pos ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
2016-05-23 22:10:05 +02:00
/* note that for deleted files, some extents may be missing */
2015-10-05 21:40:44 +02:00
/* if the files are different */
if ( ! prev | | prev - > file ! = obj - > file ) {
if ( prev ! = 0 ) {
if ( file_flag_has ( prev - > file , FILE_IS_DELETED ) ) {
2016-05-23 22:10:05 +02:00
/* check that the extent doesn't overflow the file */
2015-10-05 21:40:44 +02:00
if ( prev - > file_pos + prev - > count > prev - > file - > blockmax ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in delete end for file '%s' at '%u:%u' overflowing size '%u' \n " ,
prev - > file - > sub , prev - > file_pos , prev - > count , prev - > file - > blockmax ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
} else {
2016-05-23 22:10:05 +02:00
/* check that the extent ends the file */
2015-10-05 21:40:44 +02:00
if ( prev - > file_pos + prev - > count ! = prev - > file - > blockmax ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file end for file '%s' at '%u:%u' instead of size '%u' \n " ,
prev - > file - > sub , prev - > file_pos , prev - > count , prev - > file - > blockmax ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
}
}
if ( file_flag_has ( obj - > file , FILE_IS_DELETED ) ) {
2016-05-23 22:10:05 +02:00
/* check that the extent doesn't overflow the file */
2015-10-05 21:40:44 +02:00
if ( obj - > file_pos + obj - > count > obj - > file - > blockmax ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in delete start for file '%s' at '%u:%u' overflowing size '%u' \n " ,
obj - > file - > sub , obj - > file_pos , obj - > count , obj - > file - > blockmax ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
} else {
2016-05-23 22:10:05 +02:00
/* check that the extent starts the file */
2015-10-05 21:40:44 +02:00
if ( obj - > file_pos ! = 0 ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file start for file '%s' at '%u:%u' \n " ,
obj - > file - > sub , obj - > file_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
}
} else {
/* check the order */
if ( prev - > file_pos > = obj - > file_pos ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file order for file '%s' at '%u:%u' and at '%u:%u' \n " ,
prev - > file - > sub , prev - > file_pos , prev - > count , obj - > file_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
if ( file_flag_has ( obj - > file , FILE_IS_DELETED ) ) {
2016-05-23 22:10:05 +02:00
/* check that the extents don't overlap */
2015-10-05 21:40:44 +02:00
if ( prev - > file_pos + prev - > count > obj - > file_pos ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in delete sequence for file '%s' at '%u:%u' and at '%u:%u' \n " ,
prev - > file - > sub , prev - > file_pos , prev - > count , obj - > file_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
} else {
2016-05-23 22:10:05 +02:00
/* check that the extents are sequential */
2015-10-05 21:40:44 +02:00
if ( prev - > file_pos + prev - > count ! = obj - > file_pos ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency in file sequence for file '%s' at '%u:%u' and at '%u:%u' \n " ,
prev - > file - > sub , prev - > file_pos , prev - > count , obj - > file_pos , obj - > count ) ;
+ + arg - > result ;
return ;
/* LCOV_EXCL_STOP */
}
}
}
}
int fs_check ( struct snapraid_disk * disk )
{
2016-05-23 22:10:05 +02:00
struct extent_check arg ;
2015-10-05 21:40:44 +02:00
/* error count starts from 0 */
arg . result = 0 ;
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2015-10-05 21:40:44 +02:00
/* check parity sequence */
arg . prev = 0 ;
2016-05-23 22:10:05 +02:00
tommy_tree_foreach_arg ( & disk - > fs_parity , extent_parity_check_foreach_unlock , & arg ) ;
2015-10-05 21:40:44 +02:00
/* check file sequence */
arg . prev = 0 ;
2016-05-23 22:10:05 +02:00
tommy_tree_foreach_arg ( & disk - > fs_file , extent_file_check_foreach_unlock , & arg ) ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-05 21:40:44 +02:00
if ( arg . result ! = 0 )
return - 1 ;
return 0 ;
}
2016-05-23 22:10:05 +02:00
struct extent_parity_inside {
2015-10-04 22:02:05 +02:00
block_off_t parity_pos ;
} ;
2015-10-01 18:19:48 +02:00
2015-10-04 22:02:05 +02:00
/**
2016-05-23 22:10:05 +02:00
* Compare the extent if containing the specified parity position .
2015-10-04 22:02:05 +02:00
*/
2016-05-23 22:10:05 +02:00
static int extent_parity_inside_compare_unlock ( const void * void_a , const void * void_b )
2015-10-04 22:02:05 +02:00
{
2016-05-23 22:10:05 +02:00
const struct extent_parity_inside * arg_a = void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-04 22:02:05 +02:00
if ( arg_a - > parity_pos < arg_b - > parity_pos )
return - 1 ;
if ( arg_a - > parity_pos > = arg_b - > parity_pos + arg_b - > count )
return 1 ;
return 0 ;
2015-10-01 18:19:48 +02:00
}
2015-10-05 21:40:44 +02:00
/**
2016-05-23 22:10:05 +02:00
* Search the extent at the specified parity position .
2015-10-05 21:40:44 +02:00
* The search is optimized for sequential accesses .
* \ return If not found return 0
*/
2016-05-23 22:10:05 +02:00
static struct snapraid_extent * fs_par2extent_get_unlock ( struct snapraid_disk * disk , struct snapraid_extent * * fs_last , block_off_t parity_pos )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
/* check if the last accessed extent matches */
2015-10-30 19:06:24 +01:00
if ( * fs_last
& & parity_pos > = ( * fs_last ) - > parity_pos
& & parity_pos < ( * fs_last ) - > parity_pos + ( * fs_last ) - > count
2015-10-04 23:47:06 +02:00
) {
2016-05-23 22:10:05 +02:00
extent = * fs_last ;
2015-10-04 23:47:06 +02:00
} else {
2016-05-23 22:10:05 +02:00
struct extent_parity_inside arg = { parity_pos } ;
extent = tommy_tree_search_compare ( & disk - > fs_parity , extent_parity_inside_compare_unlock , & arg ) ;
2015-10-04 23:47:06 +02:00
}
2015-10-04 22:02:05 +02:00
2016-05-23 22:10:05 +02:00
if ( ! extent )
2015-10-04 22:02:05 +02:00
return 0 ;
2016-05-23 22:10:05 +02:00
/* store the last accessed extent */
* fs_last = extent ;
2015-10-04 22:02:05 +02:00
2016-05-23 22:10:05 +02:00
return extent ;
2015-10-01 18:19:48 +02:00
}
2016-05-23 22:10:05 +02:00
struct extent_file_inside {
2015-10-04 22:02:05 +02:00
struct snapraid_file * file ;
block_off_t file_pos ;
} ;
/**
2016-05-23 22:10:05 +02:00
* Compare the extent if containing the specified file position .
2015-10-04 22:02:05 +02:00
*/
2016-05-23 22:10:05 +02:00
static int extent_file_inside_compare_unlock ( const void * void_a , const void * void_b )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
const struct extent_file_inside * arg_a = void_a ;
const struct snapraid_extent * arg_b = void_b ;
2015-10-04 22:02:05 +02:00
if ( arg_a - > file < arg_b - > file )
return - 1 ;
if ( arg_a - > file > arg_b - > file )
return 1 ;
if ( arg_a - > file_pos < arg_b - > file_pos )
return - 1 ;
if ( arg_a - > file_pos > = arg_b - > file_pos + arg_b - > count )
return 1 ;
return 0 ;
2015-10-01 18:19:48 +02:00
}
2015-10-05 21:40:44 +02:00
/**
2016-05-23 22:10:05 +02:00
* Search the extent at the specified file position .
2015-10-05 21:40:44 +02:00
* The search is optimized for sequential accesses .
* \ return If not found return 0
*/
2016-05-23 22:10:05 +02:00
static struct snapraid_extent * fs_file2extent_get_unlock ( struct snapraid_disk * disk , struct snapraid_extent * * fs_last , struct snapraid_file * file , block_off_t file_pos )
2015-10-04 23:47:06 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
/* check if the last accessed extent matches */
2015-10-30 19:06:24 +01:00
if ( * fs_last
& & file = = ( * fs_last ) - > file
& & file_pos > = ( * fs_last ) - > file_pos
& & file_pos < ( * fs_last ) - > file_pos + ( * fs_last ) - > count
2015-10-04 23:47:06 +02:00
) {
2016-05-23 22:10:05 +02:00
extent = * fs_last ;
2015-10-04 23:47:06 +02:00
} else {
2016-05-23 22:10:05 +02:00
struct extent_file_inside arg = { file , file_pos } ;
extent = tommy_tree_search_compare ( & disk - > fs_file , extent_file_inside_compare_unlock , & arg ) ;
2015-10-04 23:47:06 +02:00
}
2016-05-23 22:10:05 +02:00
if ( ! extent )
2015-10-04 23:47:06 +02:00
return 0 ;
2016-05-23 22:10:05 +02:00
/* store the last accessed extent */
* fs_last = extent ;
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
return extent ;
2015-10-04 23:47:06 +02:00
}
2016-01-16 14:26:05 +01:00
struct snapraid_file * fs_par2file_find ( struct snapraid_disk * disk , block_off_t parity_pos , block_off_t * file_pos )
2015-10-04 23:47:06 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
2016-01-01 10:00:18 +01:00
struct snapraid_file * file ;
2015-10-04 23:47:06 +02:00
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2016-05-23 22:10:05 +02:00
extent = fs_par2extent_get_unlock ( disk , & disk - > fs_last , parity_pos ) ;
2016-01-01 10:00:18 +01:00
2016-05-23 22:10:05 +02:00
if ( ! extent ) {
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 23:47:06 +02:00
return 0 ;
2016-01-01 10:00:18 +01:00
}
2015-10-04 23:47:06 +02:00
if ( file_pos )
2016-05-23 22:10:05 +02:00
* file_pos = extent - > file_pos + ( parity_pos - extent - > parity_pos ) ;
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
file = extent - > file ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
return file ;
2015-10-04 23:47:06 +02:00
}
2016-01-16 14:26:05 +01:00
block_off_t fs_file2par_find ( struct snapraid_disk * disk , struct snapraid_file * file , block_off_t file_pos )
2015-10-01 18:19:48 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
2016-01-01 10:00:18 +01:00
block_off_t ret ;
2015-10-04 22:02:05 +02:00
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2016-05-23 22:10:05 +02:00
extent = fs_file2extent_get_unlock ( disk , & disk - > fs_last , file , file_pos ) ;
if ( ! extent ) {
2016-01-15 20:16:06 +01:00
fs_unlock ( disk ) ;
2016-01-16 14:26:05 +01:00
return POS_NULL ;
2015-10-04 22:02:05 +02:00
}
2016-05-23 22:10:05 +02:00
ret = extent - > parity_pos + ( file_pos - extent - > file_pos ) ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
return ret ;
2015-10-01 18:19:48 +02:00
}
2015-10-04 22:02:05 +02:00
void fs_allocate ( struct snapraid_disk * disk , block_off_t parity_pos , struct snapraid_file * file , block_off_t file_pos )
2013-08-23 22:35:14 +02:00
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
struct snapraid_extent * parity_extent ;
struct snapraid_extent * file_extent ;
2013-08-23 22:35:14 +02:00
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2015-10-04 22:02:05 +02:00
if ( file_pos > 0 ) {
2016-05-23 22:10:05 +02:00
/* search an existing extent for the previous file_pos */
extent = fs_file2extent_get_unlock ( disk , & disk - > fs_last , file , file_pos - 1 ) ;
2015-10-04 22:02:05 +02:00
2016-05-23 22:10:05 +02:00
if ( extent ! = 0 & & parity_pos = = extent - > parity_pos + extent - > count ) {
/* ensure that we are extending the extent at the end */
if ( file_pos ! = extent - > file_pos + extent - > count ) {
2015-10-04 22:02:05 +02:00
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when allocating file '%s' at position '%u/%u' in the middle of extent '%u:%u' in disk '%s' \n " , file - > sub , file_pos , file - > blockmax , extent - > file_pos , extent - > count , disk - > name ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-10-04 22:02:05 +02:00
/* LCOV_EXCL_STOP */
}
2016-05-23 22:10:05 +02:00
/* extend the existing extent */
+ + extent - > count ;
2015-10-04 22:02:05 +02:00
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return ;
2013-08-23 22:35:14 +02:00
}
}
2016-05-23 22:10:05 +02:00
/* a extent doesn't exist, and we have to create a new one */
extent = extent_alloc ( parity_pos , file , file_pos , 1 ) ;
2015-10-04 22:02:05 +02:00
2016-05-23 22:10:05 +02:00
/* insert the extent in the trees */
parity_extent = tommy_tree_insert ( & disk - > fs_parity , & extent - > parity_node , extent ) ;
file_extent = tommy_tree_insert ( & disk - > fs_file , & extent - > file_node , extent ) ;
2015-10-05 21:40:44 +02:00
2016-05-23 22:10:05 +02:00
if ( parity_extent ! = extent | | file_extent ! = extent ) {
2015-10-05 21:40:44 +02:00
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when allocating file '%s' at position '%u/%u' for existing extent '%u:%u' in disk '%s' \n " , file - > sub , file_pos , file - > blockmax , extent - > file_pos , extent - > count , disk - > name ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-10-05 21:40:44 +02:00
/* LCOV_EXCL_STOP */
}
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
/* store the last accessed extent */
disk - > fs_last = extent ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
}
void fs_deallocate ( struct snapraid_disk * disk , block_off_t parity_pos )
{
2016-05-23 22:10:05 +02:00
struct snapraid_extent * extent ;
struct snapraid_extent * second_extent ;
struct snapraid_extent * parity_extent ;
struct snapraid_extent * file_extent ;
2015-10-05 22:48:16 +02:00
block_off_t first_count , second_count ;
2015-10-04 22:02:05 +02:00
2016-01-01 10:00:18 +01:00
fs_lock ( disk ) ;
2016-05-23 22:10:05 +02:00
extent = fs_par2extent_get_unlock ( disk , & disk - > fs_last , parity_pos ) ;
if ( ! extent ) {
2015-10-04 22:02:05 +02:00
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when deallocating parity position '%u' for not existing extent in disk '%s' \n " , parity_pos , disk - > name ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-10-04 22:02:05 +02:00
/* LCOV_EXCL_STOP */
}
2016-05-23 22:10:05 +02:00
/* if it's the only block of the extent, delete it */
if ( extent - > count = = 1 ) {
2015-10-04 22:02:05 +02:00
/* remove from the trees */
2016-05-23 22:10:05 +02:00
tommy_tree_remove ( & disk - > fs_parity , extent ) ;
tommy_tree_remove ( & disk - > fs_file , extent ) ;
2015-10-04 22:02:05 +02:00
/* deallocate */
2016-05-23 22:10:05 +02:00
extent_free ( extent ) ;
2015-10-04 23:47:06 +02:00
2016-05-23 22:10:05 +02:00
/* clear the last accessed extent */
2015-10-04 23:47:06 +02:00
disk - > fs_last = 0 ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return ;
}
2016-05-23 22:10:05 +02:00
/* if it's at the start of the extent, shrink the extent */
if ( parity_pos = = extent - > parity_pos ) {
+ + extent - > parity_pos ;
+ + extent - > file_pos ;
- - extent - > count ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return ;
}
2016-05-23 22:10:05 +02:00
/* if it's at the end of the extent, shrink the extent */
if ( parity_pos = = extent - > parity_pos + extent - > count - 1 ) {
- - extent - > count ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-10-04 22:02:05 +02:00
return ;
}
2015-10-05 22:48:16 +02:00
/* otherwise it's in the middle */
2016-05-23 22:10:05 +02:00
first_count = parity_pos - extent - > parity_pos ;
second_count = extent - > count - first_count - 1 ;
2015-10-05 22:48:16 +02:00
2016-05-23 22:10:05 +02:00
/* adjust the first extent */
extent - > count = first_count ;
2015-10-05 22:48:16 +02:00
2016-05-23 22:10:05 +02:00
/* allocate the second extent */
second_extent = extent_alloc ( extent - > parity_pos + first_count + 1 , extent - > file , extent - > file_pos + first_count + 1 , second_count ) ;
2015-10-05 22:48:16 +02:00
2016-05-23 22:10:05 +02:00
/* insert the extent in the trees */
parity_extent = tommy_tree_insert ( & disk - > fs_parity , & second_extent - > parity_node , second_extent ) ;
file_extent = tommy_tree_insert ( & disk - > fs_file , & second_extent - > file_node , second_extent ) ;
2015-10-05 22:48:16 +02:00
2016-05-23 22:10:05 +02:00
if ( parity_extent ! = second_extent | | file_extent ! = second_extent ) {
2015-10-05 22:48:16 +02:00
/* LCOV_EXCL_START */
2016-05-23 22:10:05 +02:00
log_fatal ( " Internal inconsistency when deallocating parity position '%u' for splitting extent '%u:%u' in disk '%s' \n " , parity_pos , second_extent - > file_pos , second_extent - > count , disk - > name ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-10-05 22:48:16 +02:00
/* LCOV_EXCL_STOP */
}
2016-05-23 22:10:05 +02:00
/* store the last accessed extent */
disk - > fs_last = second_extent ;
2016-01-01 10:00:18 +01:00
fs_unlock ( disk ) ;
2015-11-18 22:10:50 +01:00
}
struct snapraid_block * fs_file2block_get ( struct snapraid_file * file , block_off_t file_pos )
{
if ( file_pos > = file - > blockmax ) {
/* LCOV_EXCL_START */
log_fatal ( " Internal inconsistency when dereferencing file '%s' at position '%u/%u' \n " , file - > sub , file_pos , file - > blockmax ) ;
2015-12-02 23:21:33 +01:00
os_abort ( ) ;
2015-11-18 22:10:50 +01:00
/* LCOV_EXCL_STOP */
}
2016-04-07 21:39:02 +02:00
return file_block ( file , file_pos ) ;
2015-10-04 22:02:05 +02:00
}
2016-01-16 14:26:05 +01:00
struct snapraid_block * fs_par2block_find ( struct snapraid_disk * disk , block_off_t parity_pos )
2015-10-04 22:02:05 +02:00
{
struct snapraid_file * file ;
block_off_t file_pos ;
2016-01-16 14:26:05 +01:00
file = fs_par2file_find ( disk , parity_pos , & file_pos ) ;
2016-01-15 20:22:41 +01:00
if ( file = = 0 )
2016-01-16 14:26:05 +01:00
return BLOCK_NULL ;
2015-10-04 22:02:05 +02:00
return fs_file2block_get ( file , file_pos ) ;
2013-08-23 22:35:14 +02:00
}
2014-11-09 19:14:29 +01:00
struct snapraid_map * map_alloc ( const char * name , unsigned position , block_off_t total_blocks , block_off_t free_blocks , const char * uuid )
2011-10-01 19:18:32 +02:00
{
struct snapraid_map * map ;
map = malloc_nofail ( sizeof ( struct snapraid_map ) ) ;
pathcpy ( map - > name , sizeof ( map - > name ) , name ) ;
map - > position = position ;
2014-11-09 19:14:29 +01:00
map - > total_blocks = total_blocks ;
map - > free_blocks = free_blocks ;
pathcpy ( map - > uuid , sizeof ( map - > uuid ) , uuid ) ;
2011-10-01 19:18:32 +02:00
return map ;
}
void map_free ( struct snapraid_map * map )
{
free ( map ) ;
}
2015-08-27 18:58:25 +02:00
int time_compare ( const void * void_a , const void * void_b )
2013-06-29 17:53:40 +02:00
{
2015-08-27 18:58:25 +02:00
const time_t * time_a = void_a ;
const time_t * time_b = void_b ;
2014-09-27 00:32:39 +02:00
2015-08-27 18:58:25 +02:00
if ( * time_a < * time_b )
2013-06-29 17:53:40 +02:00
return - 1 ;
2015-08-27 18:58:25 +02:00
if ( * time_a > * time_b )
2013-06-29 17:53:40 +02:00
return 1 ;
return 0 ;
}
2016-04-10 22:44:40 +02:00
2016-10-11 20:30:12 +02:00
/****************************************************************************/
/* format */
int FMT_MODE = FMT_FILE ;
/**
* Format a file path for poll reference
*/
const char * fmt_poll ( const struct snapraid_disk * disk , const char * str , char * buffer )
{
( void ) disk ;
return esc_shell ( str , buffer ) ;
}
/**
* Format a path name for terminal reference
*/
const char * fmt_term ( const struct snapraid_disk * disk , const char * str , char * buffer )
{
const char * out [ 3 ] ;
switch ( FMT_MODE ) {
case FMT_FILE :
default :
return esc_shell ( str , buffer ) ;
case FMT_DISK :
out [ 0 ] = disk - > name ;
out [ 1 ] = " : " ;
out [ 2 ] = str ;
return esc_shell_multi ( out , 3 , buffer ) ;
case FMT_PATH :
out [ 0 ] = disk - > dir ;
out [ 1 ] = str ;
return esc_shell_multi ( out , 2 , buffer ) ;
}
}