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-10-13 11:20:19 +02:00
# ifndef ELEM_H
# define ELEM_H
2011-03-04 20:59:21 +01:00
2011-03-25 21:04:46 +01:00
# include "util.h"
2015-02-03 19:35:43 +01:00
# include "support.h"
2014-03-22 21:02:12 +01:00
# include "tommyds/tommyhash.h"
2015-10-04 22:02:05 +02:00
# include "tommyds/tommylist.h"
# include "tommyds/tommytree.h"
2014-03-22 21:02:12 +01:00
# include "tommyds/tommyhashdyn.h"
# include "tommyds/tommyarray.h"
# include "tommyds/tommyarrayblkof.h"
2011-03-04 20:59:21 +01:00
/****************************************************************************/
/* snapraid */
2026-10-07 09:09:39 +02:00
/**
2026-08-27 16:07:59 +02:00
* Maximum number of block positions in a data / parity disk span .
*
* With the default 256 KiB block size , this limits the maximum supported
* size of the largest data / parity disk to :
*
* 32 - bit : 2 ^ 27 blocks = 32 TiB
* 64 - bit : 2 ^ 42 blocks = 1 EiB
*
* The limit scales linearly with the configured block size . For example ,
* on 64 - bit systems a 512 KiB block size allows 2 EiB per disk .
*
* This is an architectural sanity limit , not a memory - usage limit .
* SnapRAID stores per - block metadata in memory , so practical configurations
* will reach memory constraints long before BLOCK_MAX . The actual memory
* requirement depends on block size , hash size , number of data disks , and
* array layout .
*
* Based on historical HDD capacity growth , single disks are not expected
* to approach 1 EiB before approximately the year 2100. If necessary ,
* larger disks can still be supported without changing BLOCK_MAX simply
* by increasing the configured block size .
*/
# if SIZE_MAX == UINT32_MAX
# define BLOCK_MAX (1ULL << 27)
# else
# define BLOCK_MAX (1ULL << 42)
# endif
2016-01-26 23:25:01 +01:00
/**
* Number of measures of the operation progress .
*/
# define PROGRESS_MAX 100
2015-12-28 12:09:13 +01:00
/**
* Max UUID length .
*/
# define UUID_MAX 128
2026-01-29 18:43:00 +01:00
/**
* Max filesystem type / label length
*/
# define FSINFO_MAX 64
2011-03-04 20:59:21 +01:00
/**
* Invalid position .
*/
2016-01-16 14:26:05 +01:00
# define POS_NULL ((block_off_t)-1)
2011-03-04 20:59:21 +01:00
2011-04-25 13:43:51 +02:00
/**
* Content file specification .
*/
struct snapraid_content {
char content [ PATH_MAX ] ; /**< Path of the content file. */
2011-09-20 22:35:15 +02:00
uint64_t device ; /**< Device identifier. */
2015-10-29 23:37:58 +01:00
void * context ; /**< Context used for multithread operations. */
2011-04-25 13:43:51 +02:00
tommy_node node ; /**< Next node in the list. */
} ;
2011-03-16 23:52:10 +01:00
/**
* Filter for paths .
*/
struct snapraid_filter {
char pattern [ PATH_MAX ] ; /**< Filter pattern. */
2026-01-10 16:30:35 +01:00
char root [ PATH_MAX ] ; /**< If empty, it's a global pattern. If not empty, it's a local pattern that applies only to that dir. */
int is_disk ; /**< If the pattern is a disk one, otherwise it's a file pattern */
2026-01-10 16:57:04 +01:00
int is_abs ; /**< If the pattern is an absolute path (start with /), otherwise it's a relative one */
2026-01-10 16:30:35 +01:00
int is_dir ; /**< If the pattern is only for dir, otherwise it's only for file. */
2011-04-26 18:51:42 +02:00
int direction ; /**< If it's an inclusion (=1) or an exclusion (=-1). */
2011-03-16 23:52:10 +01:00
tommy_node node ; /**< Next node in the list. */
} ;
2015-10-03 10:43:02 +02:00
/**
* Block pointer used to represent unused blocks .
*/
2016-01-16 14:26:05 +01:00
# define BLOCK_NULL 0
2015-10-03 10:43:02 +02:00
/**
* This block is an empty one .
2016-01-16 14:26:05 +01:00
* Note that an empty block is represent with : : BLOCK_NULL .
2015-10-03 10:43:02 +02:00
*/
# define BLOCK_STATE_EMPTY 0
2012-02-09 23:17:36 +01:00
/**
* The block has both the hash and the parity computed .
* This is the normal state of a saved block .
2013-02-24 19:02:53 +01:00
*
2026-04-26 15:59:58 +02:00
* The block hash is the hash of the CURRENT data .
* The parity for this block IS valid .
2012-02-09 23:17:36 +01:00
*/
2013-02-24 19:02:53 +01:00
# define BLOCK_STATE_BLK 1
2012-02-09 23:17:36 +01:00
/**
2014-02-01 17:57:26 +01:00
* The block is new and not yet hashed .
2026-01-17 21:16:21 +01:00
* This happens when a new block overwrites a just removed block , or an empty
* space .
2013-02-24 19:02:53 +01:00
*
2026-04-26 15:59:58 +02:00
* The block hash is the hash of the OLD data . Possible values are :
* - ZERO - > The OLD block was empty
* - INVALID - > The OLD block has an unknown hash
* - Otherwise - > The OLD block has this hash
2014-02-01 17:57:26 +01:00
*
2026-04-26 15:59:58 +02:00
* The parity for this block IS NOT valid , because it was computed with the old
* data referenced by the hash .
2013-02-24 19:02:53 +01:00
*
2026-04-26 15:59:58 +02:00
* If the state is read from an incomplete sync , we don ' t really know if the
* hash is referring to the data used to compute the parity , because the sync
* process was interrupted at an unknown point , and the parity may or may not
* be updated .
2012-02-09 23:17:36 +01:00
*/
2014-02-01 17:57:26 +01:00
# define BLOCK_STATE_CHG 2
/**
* The block is new and hashed .
2026-04-26 15:59:58 +02:00
* This happens when a new but hashed block overwrites a just removed block ,
* or an empty space .
*
* The block hash is the hash of the NEW data .
* The parity for this block IS NOT valid .
2014-02-01 17:57:26 +01:00
*
2014-10-19 22:25:30 +02:00
* Note that when the file copy heuristic is enabled , the REP blocks may be set
2016-01-02 16:52:20 +01:00
* using this heuristic , meaning that the hash may be wrong .
2026-04-26 15:59:58 +02:00
* For this reason , when the : : force_nocopy flag is enabled , we convert all the REP blocks
2014-10-19 22:25:30 +02:00
* to CHG , invalidating the stored hash .
2014-02-01 17:57:26 +01:00
*/
# define BLOCK_STATE_REP 3
2012-02-09 23:17:36 +01:00
/**
2013-02-24 19:02:53 +01:00
* This block is a deleted one .
* This happens when a file is deleted .
*
2026-04-26 15:59:58 +02:00
* The block hash is the hash of the OLD data . Possible values are :
* - INVALID - > The OLD block has an unknown hash
* - Otherwise - > The OLD block has this hash
2013-02-24 19:02:53 +01:00
*
2026-04-26 15:59:58 +02:00
* The parity for this block IS NOT valid , because it was computed with the old
* data referenced by the hash .
2013-09-29 21:01:31 +02:00
*
2026-04-26 15:59:58 +02:00
* If the state is read from an incomplete sync , we don ' t really know if the
* hash is referring to the data used to compute the parity , because the sync
* process was interrupted at an unknown point , and the parity may or may not
* be updated .
2012-02-09 23:17:36 +01:00
*/
2013-02-24 19:43:53 +01:00
# define BLOCK_STATE_DELETED 4
2012-02-09 23:17:36 +01:00
2026-08-28 12:11:05 +02:00
/**
* The block contains current data and a current hash , but its parity must be
* rebuilt in place .
*
* The block hash is the hash of the CURRENT data .
*
* Physical parity for this block MUST NOT be trusted . It may still be correct ,
* may be missing , or may have been only partly rebuilt by an interrupted
* - - force - full sync .
*
* Unlike CHG and REP , this state does not permit automatic parity
* reallocation . The existing data - to - parity mapping must be preserved .
*
* REBUILD is converted back to BLK only after the corresponding parity update
* has completed and the normal sync durability ordering allows that progress
* to be persisted .
*/
# define BLOCK_STATE_REBUILD 5
2016-04-07 21:39:02 +02:00
/**
* Block hash size .
*
* At max HASH_MAX .
*/
2026-05-03 22:29:11 +02:00
extern size_t BLOCK_HASH_SIZE ;
2016-04-07 21:39:02 +02:00
2011-03-04 20:59:21 +01:00
/**
* Block of a file .
*/
struct snapraid_block {
2015-10-04 22:02:05 +02:00
unsigned char state ; /**< State of the block. */
2016-04-07 21:39:02 +02:00
/**
* Hash of the block .
*
* The effective stored size is BLOCK_HASH_SIZE .
*/
unsigned char hash [ HASH_MAX ] ;
2011-03-04 20:59:21 +01:00
} ;
2013-04-28 19:01:36 +02:00
/**
2013-05-31 23:34:59 +02:00
* If a file is present in the disk .
* It ' s used only in scan to detect present and missing files .
2013-04-28 19:01:36 +02:00
*/
# define FILE_IS_PRESENT 0x01
/**
* If it ' s an excluded file from the processing .
2013-05-31 23:34:59 +02:00
* It ' s used in both check and fix to mark files to exclude from the processing .
2013-04-28 19:01:36 +02:00
*/
# define FILE_IS_EXCLUDED 0x02
/**
* If a fix was attempted but it failed .
2013-05-31 23:34:59 +02:00
* It ' s used only in fix to mark that some data is unrecoverable .
2013-04-28 19:01:36 +02:00
*/
2014-12-29 08:50:20 +01:00
# define FILE_IS_DAMAGED 0x04
2013-04-28 19:01:36 +02:00
/**
* If a fix was done .
2013-05-31 23:34:59 +02:00
* It ' s used only in fix to mark that some data was recovered .
2013-04-28 19:01:36 +02:00
*/
2014-12-29 08:50:20 +01:00
# define FILE_IS_FIXED 0x08
2013-04-28 19:01:36 +02:00
/**
2013-05-31 23:34:59 +02:00
* If the file was originally missing , and it was created in the fix process .
* It ' s used only in fix to mark files recovered from scratch ,
* meaning that they don ' t have any previous content .
* This is important because it means that deleting them , you are not going
* to lose something that cannot be recovered .
2014-09-27 00:32:39 +02:00
* Note that excluded files won ' t ever get this flag .
2013-04-28 19:01:36 +02:00
*/
2014-12-29 08:50:20 +01:00
# define FILE_IS_CREATED 0x10
2013-02-28 21:56:02 +01:00
2013-05-31 23:34:59 +02:00
/**
* If the file has completed its processing , meaning that it won ' t be opened anymore .
* It ' s used only in fix to mark when we finish processing one file .
* Note that excluded files won ' t ever get this flag .
*/
2014-12-29 08:50:20 +01:00
# define FILE_IS_FINISHED 0x20
2013-05-31 23:34:59 +02:00
2014-05-15 23:45:51 +02:00
/**
* If the file hash was obtained from a file copy
* identified by the same name , size and stamp .
*/
2014-12-29 08:50:20 +01:00
# define FILE_IS_COPY 0x40
2014-05-15 23:45:51 +02:00
2014-12-29 08:50:20 +01:00
/**
* If the file was opened .
* It ' s used in fix to detect if it ' s the first time a file is opened .
*/
# define FILE_IS_OPENED 0x80
/**
* If the file is modified from the latest sync .
2026-01-17 21:16:21 +01:00
* It ' s used in fix to store the state of the file before being modified .
2014-12-29 08:50:20 +01:00
*/
# define FILE_IS_UNSYNCED 0x100
2011-04-28 23:09:19 +02:00
2026-08-29 21:25:49 +02:00
/**
* If the current recovery attempt was actually moved to the . unrecoverable name .
* It ' s used only in fix to track the physical quarantine state independently
* from FILE_IS_DAMAGED .
*/
# define FILE_IS_QUARANTINED 0x200
2014-12-29 08:50:20 +01:00
2015-10-05 21:40:44 +02:00
/**
* The file is deleted .
* This happens when a file is deleted from the array ,
* but it ' s keep inside the parity until the next sync .
*
2016-01-02 16:52:20 +01:00
* During the file - system check we needs this information ,
2015-10-05 21:40:44 +02:00
* because deleted files may be present only partially .
*/
# define FILE_IS_DELETED 0x400
2015-10-15 19:34:58 +02:00
/**
* The file is missing .
* This happens in fix / check when a file is cannot be opened ,
* and marking it as such prevents to retry to open it again .
*/
# define FILE_IS_MISSING 0x800
2026-03-18 11:51:52 +01:00
# define FILE_IS_HARDLINK 0x1000 /**< If it's an hardlink. */
# define FILE_IS_SYMLINK 0x2000 /**< If it's a file symlink. */
# define FILE_IS_SYMDIR 0x4000 /**< If it's a dir symlink for Windows. Not yet supported. */
# define FILE_IS_JUNCTION 0x8000 /**< If it's a junction for Windows. Not yet supported. */
# define FILE_IS_LINK_MASK 0xF000 /**< Mask for link type. */
2026-07-16 23:22:15 +02:00
/**
* Flag to indicate the old version of a modified file during scanning .
*/
# define FILE_IS_MODIFIED_OLD 0x10000
/**
2026-08-17 23:57:56 +02:00
* Flag to indicate the new version of a modified file during scanning .
2026-07-16 23:22:15 +02:00
*/
# define FILE_IS_MODIFIED_NEW 0x20000
/**
* Flag to indicate the old version of a kept file being reallocated during scanning .
*/
# define FILE_IS_REALLOC_OLD 0x40000
2026-08-17 23:57:56 +02:00
/**
* Flag to indicate the new version of a kept file being reallocated during scanning .
*/
# define FILE_IS_REALLOC_NEW 0x80000
2026-03-18 11:51:52 +01:00
/**
2026-09-07 17:16:24 +02:00
* Flag to indicate that an existing file was discovered on the disk during Phase 1.
2026-03-18 11:51:52 +01:00
*/
2026-09-07 17:16:24 +02:00
# define FILE_IS_DISCOVERED 0x100000
2026-03-18 11:51:52 +01:00
2026-03-14 17:48:30 +01:00
/**
* During scan if the file is found missing and relocated to another place
*
* This is used to avoid to report it " removed " .
*/
2026-07-16 23:22:15 +02:00
# define FILE_IS_RELOCATED 0x1000000
2013-08-26 20:33:25 +02:00
2011-03-04 20:59:21 +01:00
/**
* File .
*/
struct snapraid_file {
2012-07-10 23:24:31 +02:00
int64_t mtime_sec ; /**< Modification time. */
2011-04-28 23:09:19 +02:00
uint64_t inode ; /**< Inode. */
2011-03-12 10:09:59 +01:00
data_off_t size ; /**< Size of the file. */
2011-03-04 20:59:21 +01:00
struct snapraid_block * blockvec ; /**< All the blocks of the file. */
2011-03-12 10:09:59 +01:00
block_off_t blockmax ; /**< Number of blocks. */
2026-06-03 23:06:27 +02:00
char * sub ; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
int mtime_nsec ; /**< Modification time nanoseconds. In the range 0 <= x < 1,000,000,000, or STAT_NSEC_INVALID if not present. */
2026-07-16 23:22:15 +02:00
uint32_t flag ; /**< FILE_IS_* flags. */
2011-04-28 23:09:19 +02:00
2011-03-04 20:59:21 +01:00
/* nodes for data structures */
tommy_node nodelist ;
tommy_hashdyn_node nodeset ;
2011-10-09 23:41:08 +02:00
tommy_hashdyn_node pathset ;
2014-02-12 20:02:35 +01:00
tommy_hashdyn_node stampset ;
2026-10-03 17:12:44 +02:00
char sub_inline [ ] ; /**< Inline storage for the initial sub path. */
2011-03-04 20:59:21 +01:00
} ;
2011-08-26 14:18:38 +02:00
/**
* Symbolic Link .
*/
struct snapraid_link {
unsigned flag ; /**< FILE_IS_* flags. */
2013-05-30 23:50:26 +02:00
char * sub ; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
char * linkto ; /**< Link to. */
2011-08-26 14:18:38 +02:00
/* nodes for data structures */
tommy_node nodelist ;
tommy_hashdyn_node nodeset ;
2014-09-27 00:32:39 +02:00
} ;
2011-08-26 14:18:38 +02:00
2013-01-27 16:44:04 +01:00
/**
* Dir .
*/
struct snapraid_dir {
unsigned flag ; /**< FILE_IS_* flags. */
2013-05-30 23:50:26 +02:00
char * sub ; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
2013-01-27 16:44:04 +01:00
/* nodes for data structures */
tommy_node nodelist ;
tommy_hashdyn_node nodeset ;
2014-09-27 00:32:39 +02:00
} ;
2013-01-27 16:44:04 +01:00
2026-09-25 23:40:58 +02:00
/**
* Deallocated block .
*/
struct snapraid_dealloc_block {
unsigned char prev ; /**< If the hash uses the previous hash generation. */
unsigned char hash [ HASH_MAX ] ; /**< Hash of the block. Only BLOCK_HASH_SIZE bytes are significant. */
} ;
2026-04-27 14:39:38 +02:00
/**
* Deallocated file .
*/
struct snapraid_dealloc {
char * sub ; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
data_off_t size ; /**< Size of the file. */
int64_t mtime_sec ; /**< Modification time. */
int mtime_nsec ; /**< Modification time nanoseconds. In the range 0 <= x < 1,000,000,000, or STAT_NSEC_INVALID if not present. */
block_off_t blockmax ; /**< Number of blocks. */
/* nodes for data structures */
tommy_node nodelist ;
2026-09-25 23:40:58 +02:00
struct snapraid_dealloc_block block [ ] ; /**< Blocks of the file. */
2026-04-27 14:39:38 +02:00
} ;
2015-10-04 22:02:05 +02:00
/**
* Chunk .
*
2016-05-23 22:10:05 +02:00
* A extent represents a fragment of a file mapped into the parity .
2015-10-04 22:02:05 +02:00
*/
2016-05-23 22:10:05 +02:00
struct snapraid_extent {
struct snapraid_file * file ; /**< File containing this extent. */
2015-10-04 22:02:05 +02:00
block_off_t parity_pos ; /**< Parity position. */
block_off_t file_pos ; /**< Position in the file. */
block_off_t count ; /**< Number of sequential blocks in the file and parity. */
tommy_tree_node parity_node ; /**< Tree sorted by <parity_pos>. */
tommy_tree_node file_node ; /**< Tree sorter by <file,file_pos>. */
} ;
2011-03-04 20:59:21 +01:00
/**
2026-03-11 13:53:42 +01:00
* Other disk .
*/
struct snapraid_extra {
char name [ PATH_MAX ] ; /**< Name of the disk. */
char dir [ PATH_MAX ] ; /**< Mount point of the disk. It always terminates with /. */
2026-09-14 15:40:54 +02:00
char smartctl [ SMARTCTL_MAX ] ; /**< Custom option for smartctl. Empty means auto. */
2026-10-07 09:09:39 +02:00
char smartctl_info [ SMARTCTL_MAX ] ; /**< Info options for smartctl. Empty means -a. */
2026-06-25 22:52:53 +02:00
struct smartignore_struct smartignore [ SMART_IGNORE_MAX ] ; /**< Smart attributes to ignore for this device. */
2026-03-11 13:53:42 +01:00
char uuid [ UUID_MAX ] ; /**< UUID of the disk. They are probed during the config reading. */
char fstype [ FSINFO_MAX ] ; /**< Filesystem type */
char fslabel [ FSINFO_MAX ] ; /**< Filesystem label */
uint64_t device ; /**< Device identifier. */
/* nodes for data structures */
tommy_node node ;
} ;
/**
* Data disk .
2011-03-04 20:59:21 +01:00
*/
struct snapraid_disk {
char name [ PATH_MAX ] ; /**< Name of the disk. */
2026-04-27 14:39:38 +02:00
/**
* Configured mount point of the disk .
*
* It always terminates with /
*/
char mount_point [ PATH_MAX ] ;
/**
* Effective mount point of the disk .
*
* It could be either the real mount point or a snapshot .
* It always terminates with /
*/
char dir [ PATH_MAX ] ;
/**
2026-05-04 10:59:12 +02:00
* Snapshot context
2026-04-27 14:39:38 +02:00
*/
2026-05-04 10:59:12 +02:00
struct fssnapshot_struct fss ;
2026-04-27 14:39:38 +02:00
2026-09-14 15:40:54 +02:00
char smartctl [ SMARTCTL_MAX ] ; /**< Custom option for smartctl. Empty means auto. */
2026-10-07 09:09:39 +02:00
char smartctl_info [ SMARTCTL_MAX ] ; /**< Info options for smartctl. Empty means -a. */
2026-06-25 22:52:53 +02:00
struct smartignore_struct smartignore [ SMART_IGNORE_MAX ] ; /**< Smart attributes to ignore for this device. */
2025-12-22 00:03:38 +01:00
char uuid [ UUID_MAX ] ; /**< UUID of the disk. They are probed during the config reading. */
2026-01-29 18:43:00 +01:00
char fstype [ FSINFO_MAX ] ; /**< Filesystem type */
char fslabel [ FSINFO_MAX ] ; /**< Filesystem label */
2015-12-28 12:09:13 +01:00
2026-04-28 00:35:15 +02:00
uint64_t mount_device ; /**< Device identifier of the mount_point. */
2014-11-09 19:14:29 +01:00
block_off_t total_blocks ; /**< Number of total blocks. */
block_off_t free_blocks ; /**< Number of free blocks at the last sync. */
2016-01-26 23:25:01 +01:00
uint64_t tick ; /**< Usage time. */
uint64_t progress_tick [ PROGRESS_MAX ] ; /**< Last ticks of progress. */
2017-11-19 19:33:47 +01:00
unsigned cached_blocks ; /**< Number of IO blocks cached. */
struct snapraid_file * progress_file ; /**< File in progress. */
2016-01-26 23:25:01 +01:00
2014-02-01 23:32:53 +01:00
/**
* First free searching block .
2016-01-02 16:52:20 +01:00
* Note that it doesn ' t necessarily point at the first free block ,
2014-02-01 23:32:53 +01:00
* but it just tell you that no free block is present before this position .
*/
block_off_t first_free_block ;
2016-01-02 16:52:20 +01:00
int has_volatile_inodes ; /**< If the underline file-system has not persistent inodes. */
2020-05-02 14:21:40 +02:00
int has_volatile_hardlinks ; /**< If the underline file-system has not synchronized metadata for hardlink (NTFS). */
2016-01-02 16:52:20 +01:00
int has_different_uuid ; /**< If the disk has a different UUID, meaning that it is not the same file-system. */
2014-04-03 23:02:43 +02:00
int has_unsupported_uuid ; /**< If the disk doesn't report UUID, meaning it's not supported. */
2014-01-04 17:42:45 +01:00
int had_empty_uuid ; /**< If the disk had an empty UUID, meaning that it's a new disk. */
2014-11-09 10:51:48 +01:00
int mapping_idx ; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
2016-01-02 16:52:20 +01:00
int skip_access ; /**< If the disk is inaccessible and it should be skipped. */
2013-02-24 19:02:53 +01:00
2021-05-25 22:08:12 +02:00
# if HAVE_THREAD
2026-03-11 15:50:49 +01:00
int single_thread ; /**< Running in single thread, and then not needing the mutex */
2016-01-01 10:00:18 +01:00
/**
* Mutex for protecting the filesystem structure .
*
* Specifically , this protects : : fs_parity , : : fs_file , and : : fs_last ,
2016-05-23 22:37:18 +02:00
* meaning that it protects only extents .
2016-01-01 10:00:18 +01:00
*
* Files , links and dirs are not protected as they are not expected to
* change during multithread processing .
*/
2021-05-25 22:08:12 +02:00
thread_mutex_t fs_mutex ;
2021-11-28 15:50:38 +01:00
2016-03-18 18:45:35 +01:00
# endif
2016-01-01 10:00:18 +01:00
2015-10-04 22:02:05 +02:00
/**
2016-05-23 22:10:05 +02:00
* Mapping of extents in the parity .
2015-10-04 22:02:05 +02:00
* Sorted by < parity_pos > and by < file , file_pos >
2013-02-24 19:02:53 +01:00
*/
2015-10-04 22:02:05 +02:00
tommy_tree fs_parity ;
tommy_tree fs_file ;
2013-02-24 19:02:53 +01:00
2015-10-04 23:47:06 +02:00
/**
2016-05-23 22:10:05 +02:00
* Last extent we accessed .
2015-10-04 23:47:06 +02:00
* It ' s used to optimize access of sequential blocks .
*/
2016-05-23 22:10:05 +02:00
struct snapraid_extent * fs_last ;
2015-10-04 23:47:06 +02:00
2013-02-24 19:02:53 +01:00
/**
* List of all the snapraid_file for the disk .
*/
tommy_list filelist ;
/**
2015-10-01 23:22:21 +02:00
* List of all the deleted file for the disk .
2013-02-24 19:02:53 +01:00
*
* These files are kept allocated , because the blocks are still referenced in
* the : : blockarr .
*/
tommy_list deletedlist ;
2011-03-20 22:36:49 +01:00
tommy_hashdyn inodeset ; /**< Hashtable by inode of all the files. */
2011-10-09 23:41:08 +02:00
tommy_hashdyn pathset ; /**< Hashtable by path of all the files. */
2014-02-12 20:02:35 +01:00
tommy_hashdyn stampset ; /**< Hashtable by stamp (size and time) of all the files. */
2011-08-26 14:18:38 +02:00
tommy_list linklist ; /**< List of all the links. */
tommy_hashdyn linkset ; /**< Hashtable by name of all the links. */
2016-05-14 21:59:33 +02:00
tommy_list dirlist ; /**< List of all the empty dirs. */
tommy_hashdyn dirset ; /**< Hashtable by name of all the empty dirs. */
2026-04-27 14:39:38 +02:00
tommy_list dealloclist ; /**< List of all the deallocs. */
2011-09-23 21:48:50 +02:00
/* nodes for data structures */
tommy_node node ;
2011-03-04 20:59:21 +01:00
} ;
2011-10-01 19:18:32 +02:00
/**
* Disk mapping .
*/
struct snapraid_map {
char name [ PATH_MAX ] ; /**< Name of the disk. */
2026-06-28 23:35:44 +02:00
char content_uuid [ UUID_MAX ] ; /**< UUID of the disk. Empty if unknown. They are read from the content file. */
2014-11-09 19:14:29 +01:00
block_off_t total_blocks ; /**< Number of total blocks. */
block_off_t free_blocks ; /**< Number of free blocks at last 'sync'. */
unsigned position ; /**< Position of the disk in the parity. */
2011-10-01 19:18:32 +02:00
/* nodes for data structures */
tommy_node node ;
} ;
2014-11-09 10:32:00 +01:00
/**
2016-04-26 21:48:39 +02:00
* Max number of parity split .
2014-11-09 10:32:00 +01:00
*/
2016-04-26 21:48:39 +02:00
# define SPLIT_MAX 8
/**
* Invalid parity size .
*
2026-09-26 16:29:26 +02:00
* This value identifies new parity levels or splits
* added in the configuration , for example when
* creating a new parity level with ' fix ' .
2016-04-26 21:48:39 +02:00
* Given that ' fix ' doesn ' t write the content file ,
* the new size will be written only at the next
* ' sync ' .
*/
2016-05-18 20:58:41 +02:00
# define PARITY_SIZE_INVALID -1LL
2016-04-26 21:48:39 +02:00
/**
* Parity split .
*/
struct snapraid_split {
2014-11-09 10:32:00 +01:00
char path [ PATH_MAX ] ; /**< Path of the parity file. */
2026-06-28 22:47:58 +02:00
char uuid [ UUID_MAX ] ; /**< UUID of the disk. Empty if unknown. They are probed during the config reading. */
char content_uuid [ UUID_MAX ] ; /**< UUID read from the content file. */
2026-01-29 18:43:00 +01:00
char fstype [ FSINFO_MAX ] ; /**< Filesystem type */
char fslabel [ FSINFO_MAX ] ; /**< Filesystem label */
2016-04-26 21:48:39 +02:00
/**
* Size of the parity split .
* Only the latest not zero size is allowed to grow .
* If the value is unset , it ' s PARITY_SIZE_INVALID .
*/
2016-05-18 20:58:41 +02:00
data_off_t size ;
2016-04-26 21:48:39 +02:00
2014-11-09 10:32:00 +01:00
uint64_t device ; /**< Device identifier of the parity. */
2016-04-26 21:48:39 +02:00
} ;
/**
* Parity .
*/
struct snapraid_parity {
struct snapraid_split split_map [ SPLIT_MAX ] ; /**< Parity splits. */
unsigned split_mac ; /**< Number of parity splits. */
2026-09-14 15:40:54 +02:00
char smartctl [ SMARTCTL_MAX ] ; /**< Custom option for smartctl. Empty means auto. */
2026-10-07 09:09:39 +02:00
char smartctl_info [ SMARTCTL_MAX ] ; /**< Info options for smartctl. Empty means -a. */
2026-06-25 22:52:53 +02:00
struct smartignore_struct smartignore [ SMART_IGNORE_MAX ] ; /**< Smart attributes to ignore for this device. */
2014-11-09 19:14:29 +01:00
block_off_t total_blocks ; /**< Number of total blocks. */
block_off_t free_blocks ; /**< Number of free blocks at the last sync. */
2017-03-26 18:10:46 +02:00
int is_excluded_by_filter ; /**< If the parity is excluded by filters. */
2016-04-26 21:48:39 +02:00
int skip_access ; /**< If at least one of the parity disk is inaccessible and it should be skipped. */
2016-01-26 23:25:01 +01:00
uint64_t tick ; /**< Usage time. */
uint64_t progress_tick [ PROGRESS_MAX ] ; /**< Last cpu ticks of progress. */
2017-11-19 19:33:47 +01:00
unsigned cached_blocks ; /**< Number of IO blocks cached. */
2014-11-09 10:32:00 +01:00
} ;
2013-06-22 18:13:19 +02:00
/**
* Info .
*/
2025-10-08 12:42:40 +02:00
typedef uint64_t snapraid_info ;
2013-06-22 18:13:19 +02:00
2011-04-25 13:43:51 +02:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a content .
2011-04-25 13:43:51 +02:00
*/
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
/**
2015-10-07 22:07:20 +02:00
* Deallocate a content .
2011-04-25 13:43:51 +02:00
*/
2026-08-24 23:03:00 +02:00
void content_free ( void * void_content ) ;
2011-04-25 13:43:51 +02:00
2011-03-16 23:52:10 +01:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a filter pattern for files and directories .
2011-03-16 23:52:10 +01:00
*/
2026-01-10 16:30:35 +01:00
struct snapraid_filter * filter_alloc_file ( int is_include , const char * root , const char * pattern ) ;
2012-10-10 23:32:09 +02:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a filter pattern for disks .
2012-10-10 23:32:09 +02:00
*/
struct snapraid_filter * filter_alloc_disk ( int is_include , const char * pattern ) ;
2011-03-16 23:52:10 +01:00
/**
2015-10-07 22:07:20 +02:00
* Deallocate an exclusion .
2011-03-16 23:52:10 +01:00
*/
2026-01-10 16:30:35 +01:00
void filter_free ( void * filter ) ;
2011-03-16 23:52:10 +01:00
2015-01-27 23:10:38 +01:00
/**
* Filter type description .
*/
2015-01-27 23:32:13 +01:00
const char * filter_type ( struct snapraid_filter * filter , char * out , size_t out_size ) ;
2015-01-27 23:10:38 +01:00
2011-12-08 22:40:30 +01:00
/**
* Filter hidden files .
* Return ! = 0 if it matches and it should be excluded .
*/
2013-01-18 00:15:55 +01:00
static inline int filter_hidden ( int enable , struct dirent * dd )
2011-12-08 22:40:30 +01:00
{
2013-01-18 00:15:55 +01:00
if ( enable & & dirent_hidden ( dd ) ) {
2011-12-08 22:40:30 +01:00
return 1 ; /* filter out */
}
return 0 ;
}
2011-03-30 00:14:43 +02:00
/**
2015-10-07 22:07:20 +02:00
* Filter a path using a list of filters .
2011-04-26 18:51:42 +02:00
* For each element of the path all the filters are applied , until the first one that matches .
2013-03-01 18:29:04 +01:00
* Return ! = 0 if it should be excluded .
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
2013-02-24 11:33:09 +01:00
/**
* Filter a file / link / dir if missing .
2013-03-01 18:29:04 +01:00
* This call imply a disk check for the file presence .
* Return ! = 0 if the file is present and it should be excluded .
2013-02-24 11:33:09 +01: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-08-18 19:24:55 +02:00
/**
* Filter a file if bad .
* Return ! = 0 if the file is correct and it should be excluded .
*/
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
2011-09-18 22:43:41 +02:00
/**
2015-10-07 22:07:20 +02:00
* Filter a dir using a list of filters .
2011-09-18 22:43:41 +02:00
* For each element of the path all the filters are applied , until the first one that matches .
2016-05-14 21:59:33 +02:00
* Thesesdir are always by included by default , to allow to apply rules at the contained files .
2013-03-01 18:29:04 +01:00
* Return ! = 0 if should be excluded .
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 ) ;
/**
* Filter a dir using a list of filters .
* For each element of the path all the filters are applied , until the first one that matches .
* Return ! = 0 if should be excluded .
*/
int filter_emptydir ( tommy_list * filterlist , struct snapraid_filter * * reason , const char * disk , const char * sub ) ;
2011-09-18 22:43:41 +02:00
/**
2015-10-07 22:07:20 +02:00
* Filter a path if it ' s a content file .
2013-03-01 18:29:04 +01:00
* Return ! = 0 if should be excluded .
2011-09-18 22:43:41 +02:00
*/
2026-05-11 23:24:36 +02:00
int filter_content ( tommy_list * contentlist , const char * mount_point , size_t mount_point_len , const char * sub , size_t sub_len , const char * name ) ;
/**
* Filter a path that is in a snapshot
* Return ! = 0 if should be excluded .
*/
2026-08-14 09:47:12 +02:00
int filter_snapshot ( int enable , const char * sub , const char * name ) ;
2011-03-16 23:52:10 +01:00
2026-09-09 23:40:37 +02:00
/**
* Copy a block hash using the configured hash size .
*
* Keep the common full - size case explicit so the compiler can inline a fixed
* 16 - byte copy instead of emitting a call to memcpy ( ) with a runtime size .
*/
static __always_inline void * hash_copy ( void * dst , const void * src )
{
if ( BLOCK_HASH_SIZE = = HASH_MAX )
return memcpy ( dst , src , HASH_MAX ) ;
else
return memcpy ( dst , src , BLOCK_HASH_SIZE ) ;
}
2011-08-31 23:33:43 +02:00
/**
2015-10-07 22:07:20 +02:00
* Check if the specified hash is invalid .
2015-10-03 10:43:02 +02:00
*
* An invalid hash is represented with all bytes at 0x00 .
2016-04-10 19:13:08 +02:00
*
* If working with reduced hash lengths , this function always return 0.
2011-08-31 23:33:43 +02:00
*/
2015-10-03 10:43:02 +02:00
static inline int hash_is_invalid ( const unsigned char * hash )
2011-04-28 23:09:19 +02:00
{
2026-05-03 22:29:11 +02:00
size_t i ;
2015-10-03 10:43:02 +02:00
2016-04-10 19:13:08 +02:00
/* if the hash is reduced, we cannot grant that it's a specific kind of hash */
if ( BLOCK_HASH_SIZE ! = HASH_MAX )
return 0 ;
2026-09-09 23:40:37 +02:00
for ( i = 0 ; i < HASH_MAX ; + + i )
2015-10-03 10:43:02 +02:00
if ( hash [ i ] ! = 0x00 )
return 0 ;
return 1 ;
2011-04-28 23:09:19 +02:00
}
2011-08-31 23:33:43 +02:00
/**
2015-10-07 22:07:20 +02:00
* Check if the specified hash represent the zero block .
2015-10-03 10:43:02 +02:00
*
* A zero hash is represented with all bytes at 0xFF .
2016-04-10 19:13:08 +02:00
*
* If working with reduced hash lengths , this function always return 0.
2011-08-31 23:33:43 +02:00
*/
2015-10-03 10:43:02 +02:00
static inline int hash_is_zero ( const unsigned char * hash )
2011-04-28 23:09:19 +02:00
{
2026-05-03 22:29:11 +02:00
size_t i ;
2013-02-24 19:02:53 +01:00
2016-04-10 19:13:08 +02:00
/* if the hash is reduced, we cannot grant that it's a specific kind of hash */
if ( BLOCK_HASH_SIZE ! = HASH_MAX )
return 0 ;
2016-04-07 21:39:02 +02:00
for ( i = 0 ; i < BLOCK_HASH_SIZE ; + + i )
2015-10-03 10:43:02 +02:00
if ( hash [ i ] ! = 0xFF )
return 0 ;
2013-02-24 19:02:53 +01:00
2015-10-03 10:43:02 +02:00
return 1 ;
}
/**
2016-05-23 22:37:18 +02:00
* Check if the specified hash is unequivocally representing the data .
2016-04-10 19:13:08 +02:00
*
* If working with reduced hash lengths , this function always return 0.
2015-10-03 10:43:02 +02:00
*/
2016-04-10 19:13:08 +02:00
static inline int hash_is_unique ( const unsigned char * hash )
2015-10-03 10:43:02 +02:00
{
2016-04-10 19:13:08 +02:00
/* if the hash is reduced, we cannot grant that it's a specific kind of hash */
if ( BLOCK_HASH_SIZE ! = HASH_MAX )
return 0 ;
2015-10-03 10:43:02 +02:00
return ! hash_is_zero ( hash ) & & ! hash_is_invalid ( hash ) ;
}
/**
* Set the hash to the special INVALID value .
*/
static inline void hash_invalid_set ( unsigned char * hash )
{
2016-04-07 21:39:02 +02:00
memset ( hash , 0x00 , BLOCK_HASH_SIZE ) ;
2015-10-03 10:43:02 +02:00
}
/**
* Set the hash to the special ZERO value .
*/
static inline void hash_zero_set ( unsigned char * hash )
{
2016-04-07 21:39:02 +02:00
memset ( hash , 0xFF , BLOCK_HASH_SIZE ) ;
}
/**
* Allocated space for block .
*/
static inline size_t block_sizeof ( void )
{
return 1 + BLOCK_HASH_SIZE ;
2012-02-09 23:17:36 +01:00
}
2013-02-24 19:02:53 +01:00
/**
* Get the state of the block .
*
* For this function , it ' s allowed to pass a NULL block
* pointer than results in the BLOCK_STATE_EMPTY state .
*/
2013-02-24 11:33:09 +01:00
static inline unsigned block_state_get ( const struct snapraid_block * block )
2012-02-09 23:17:36 +01:00
{
2016-01-16 14:26:05 +01:00
if ( block = = BLOCK_NULL )
2013-02-24 19:02:53 +01:00
return BLOCK_STATE_EMPTY ;
2015-10-04 22:02:05 +02:00
return block - > state ;
2011-04-28 23:09:19 +02:00
}
2015-10-04 22:02:05 +02:00
/**
* Set the state of the block .
*/
2012-02-09 23:17:36 +01:00
static inline void block_state_set ( struct snapraid_block * block , unsigned state )
2011-04-28 23:09:19 +02:00
{
2015-10-04 22:02:05 +02:00
block - > state = state ;
2011-04-28 23:09:19 +02:00
}
2013-02-24 19:43:53 +01:00
/**
2015-10-07 22:07:20 +02:00
* Check if the specified block has an updated hash .
2013-02-24 19:43:53 +01:00
*
2014-02-01 17:57:26 +01:00
* Note that EMPTY / CHG / DELETED return 0.
2013-02-24 19:43:53 +01:00
*/
2013-08-21 22:24:12 +02:00
static inline int block_has_updated_hash ( const struct snapraid_block * block )
2011-04-28 23:09:19 +02:00
{
2012-02-09 23:17:36 +01:00
unsigned state = block_state_get ( block ) ;
2013-02-24 19:02:53 +01:00
2026-08-28 12:11:05 +02:00
return state = = BLOCK_STATE_BLK
| | state = = BLOCK_STATE_REP
| | state = = BLOCK_STATE_REBUILD ;
2011-04-28 23:09:19 +02:00
}
2014-02-01 17:57:26 +01:00
/**
2015-10-07 22:07:20 +02:00
* Check if the specified block is part of a file .
2013-09-29 21:01:31 +02:00
*
2014-02-01 17:57:26 +01:00
* Note that EMPTY / DELETED return 0.
2013-09-29 21:01:31 +02:00
*/
2014-02-01 17:57:26 +01:00
static inline int block_has_file ( const struct snapraid_block * block )
2013-09-29 21:01:31 +02:00
{
unsigned state = block_state_get ( block ) ;
2014-02-01 17:57:26 +01:00
return state = = BLOCK_STATE_BLK
2026-08-28 12:11:05 +02:00
| | state = = BLOCK_STATE_CHG
| | state = = BLOCK_STATE_REP
| | state = = BLOCK_STATE_REBUILD ;
2013-09-29 21:01:31 +02:00
}
2013-02-24 19:02:53 +01:00
/**
2015-10-07 22:07:20 +02:00
* Check if the block has an invalid parity than needs to be updated .
2013-02-24 19:02:53 +01:00
*
2013-08-21 23:21:18 +02:00
* Note that EMPTY / BLK return 0.
2013-02-24 19:02:53 +01:00
*/
2013-02-24 19:43:53 +01:00
static inline int block_has_invalid_parity ( const struct snapraid_block * block )
2013-02-24 19:02:53 +01:00
{
unsigned state = block_state_get ( block ) ;
2014-02-01 17:57:26 +01:00
return state = = BLOCK_STATE_DELETED
2026-08-28 12:11:05 +02:00
| | state = = BLOCK_STATE_CHG
| | state = = BLOCK_STATE_REP
| | state = = BLOCK_STATE_REBUILD ;
2013-02-24 19:02:53 +01:00
}
2015-02-01 18:48:50 +01:00
/**
2015-10-07 22:07:20 +02:00
* Check if the block is part of a file with valid parity .
2015-02-01 18:48:50 +01:00
*
* Note that anything different than BLK return 0.
*/
static inline int block_has_file_and_valid_parity ( const struct snapraid_block * block )
{
unsigned state = block_state_get ( block ) ;
return state = = BLOCK_STATE_BLK ;
}
2026-08-28 12:11:05 +02:00
/**
* Check if a live block with invalid parity may participate in automatic
* parity reallocation .
*
* REBUILD is deliberately excluded because it requires an in - place parity
* rebuild preserving the existing data - to - parity mapping .
*/
static inline int block_has_reallocatable_parity ( const struct snapraid_block * block )
{
unsigned state = block_state_get ( block ) ;
return state = = BLOCK_STATE_CHG
| | state = = BLOCK_STATE_REP ;
}
2013-02-24 11:33:09 +01:00
static inline int file_flag_has ( const struct snapraid_file * file , unsigned mask )
2011-04-28 23:09:19 +02:00
{
2026-09-07 17:16:24 +02:00
return ( file - > flag & mask ) = = mask ;
2011-04-28 23:09:19 +02:00
}
static inline void file_flag_set ( struct snapraid_file * file , unsigned mask )
{
2026-09-07 17:16:24 +02:00
file - > flag | = mask ;
2011-04-28 23:09:19 +02:00
}
static inline void file_flag_clear ( struct snapraid_file * file , unsigned mask )
{
2026-09-07 17:16:24 +02:00
file - > flag & = ~ mask ;
2011-04-28 23:09:19 +02:00
}
2011-03-12 23:36:37 +01:00
/**
2026-09-09 17:56:44 +02:00
* Allocate a file without initializing its blocks .
2011-03-12 23:36:37 +01:00
*/
2026-10-03 17:00:24 +02:00
struct snapraid_file * file_alloc_len ( unsigned block_size , const char * sub , size_t sub_len , data_off_t size , uint64_t mtime_sec , int mtime_nsec , uint64_t inode ) ;
static inline 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 )
{
return file_alloc_len ( block_size , sub , strlen ( sub ) , size , mtime_sec , mtime_nsec , inode ) ;
}
2011-03-04 20:59:21 +01:00
2011-03-12 23:36:37 +01:00
/**
2015-10-01 18:19:48 +02:00
* Duplicate a file .
*/
struct snapraid_file * file_dup ( struct snapraid_file * copy ) ;
/**
* Deallocate a file .
2011-03-12 23:36:37 +01:00
*/
2026-08-24 23:03:00 +02:00
void file_free ( void * void_file ) ;
2011-03-04 20:59:21 +01:00
2013-02-26 21:26:45 +01:00
/**
* Rename a file .
*/
void file_rename ( struct snapraid_file * file , const char * sub ) ;
2014-02-12 20:02:35 +01:00
/**
* Copy a file .
*/
void file_copy ( struct snapraid_file * src_file , struct snapraid_file * dest_file ) ;
2016-04-07 21:39:02 +02:00
/**
* Return the block at the specified position .
*
* Note that the block size if a runtime value .
*/
2026-08-26 17:06:28 +02:00
static inline struct snapraid_block * file_block ( struct snapraid_file * file , block_off_t pos )
2016-04-07 21:39:02 +02:00
{
unsigned char * ptr = ( unsigned char * ) file - > blockvec ;
return ( struct snapraid_block * ) ( ptr + pos * block_sizeof ( ) ) ;
}
2011-03-30 00:14:43 +02:00
/**
2015-10-07 22:07:20 +02:00
* Return the name of the file , without the dir .
2011-03-30 00:14:43 +02:00
*/
2014-02-12 20:02:35 +01:00
const char * file_name ( const struct snapraid_file * file ) ;
2015-10-03 10:43:02 +02:00
/**
2015-10-07 22:07:20 +02:00
* Check if the block is the last in the file .
2015-10-03 10:43:02 +02:00
*/
int file_block_is_last ( struct snapraid_file * file , block_off_t file_pos ) ;
/**
2015-10-07 22:07:20 +02:00
* Get the size in bytes of the block .
2015-10-03 10:43:02 +02:00
* If it ' s the last block of a file it could be less than block_size .
*/
2026-06-04 00:34:51 +02:00
size_t file_block_size ( struct snapraid_file * file , block_off_t file_pos , size_t block_size ) ;
2011-03-30 00:14:43 +02:00
2011-03-12 23:36:37 +01:00
/**
2015-10-07 22:07:20 +02:00
* Compare a file with an inode .
2011-03-12 23:36:37 +01:00
*/
2013-06-25 22:41:10 +02:00
int file_inode_compare_to_arg ( const void * void_arg , const void * void_data ) ;
/**
2015-10-07 22:07:20 +02:00
* Compare files by inode .
2013-06-25 22:41:10 +02:00
*/
int file_inode_compare ( const void * void_a , const void * void_b ) ;
/**
2015-10-07 22:07:20 +02:00
* Compare files by path .
2013-06-25 22:41:10 +02:00
*/
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
2011-03-12 23:36:37 +01:00
/**
2015-10-07 22:07:20 +02:00
* Compute the hash of a file inode .
2011-03-12 23:36:37 +01:00
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t file_inode_hash ( uint64_t inode )
2011-03-04 20:59:21 +01:00
{
2026-10-14 18:46:56 +02:00
# if TOMMY_SIZE_BIT == 64
return tommy_mulhash_u64 ( inode ) ;
# else
/* avoid expensive 64-bit multiplications on 32-bit architectures */
2026-10-07 19:13:27 +02:00
return tommy_inthash_u64 ( inode ) ;
2026-10-14 18:46:56 +02:00
# endif
2011-03-04 20:59:21 +01:00
}
2011-10-09 23:41:08 +02:00
/**
2015-10-07 22:07:20 +02:00
* Compare a file with a path .
2011-10-09 23:41:08 +02:00
*/
2014-02-12 20:02:35 +01:00
int file_path_compare_to_arg ( const void * void_arg , const void * void_data ) ;
/**
* Compare a file with another file for name , stamp , and both .
*/
int file_name_compare ( const void * void_a , const void * void_b ) ;
int file_stamp_compare ( const void * void_a , const void * void_b ) ;
int file_namestamp_compare ( const void * void_a , const void * void_b ) ;
2014-05-15 23:45:51 +02:00
int file_pathstamp_compare ( const void * void_a , const void * void_b ) ;
2011-10-09 23:41:08 +02:00
2026-10-03 17:00:24 +02:00
/**
* Compute the hash of a file path with known length .
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t file_path_hash_len ( const char * sub , size_t len )
2026-10-03 17:00:24 +02:00
{
2026-10-07 19:13:27 +02:00
# if TOMMY_SIZE_BIT == 64
return tommy_hash_u64 ( 0 , sub , len ) ;
# else
2026-10-03 17:00:24 +02:00
return tommy_hash_u32 ( 0 , sub , len ) ;
2026-10-07 19:13:27 +02:00
# endif
2026-10-03 17:00:24 +02:00
}
2011-10-09 23:41:08 +02:00
/**
2015-10-07 22:07:20 +02:00
* Compute the hash of a file path .
2011-10-09 23:41:08 +02:00
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t file_path_hash ( const char * sub )
2011-10-09 23:41:08 +02:00
{
2026-10-03 17:00:24 +02:00
return file_path_hash_len ( sub , strlen ( sub ) ) ;
2011-10-09 23:41:08 +02:00
}
2014-02-12 20:02:35 +01:00
/**
2015-10-07 22:07:20 +02:00
* Compute the hash of a file stamp .
2014-02-12 20:02:35 +01:00
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t file_stamp_hash ( data_off_t size , int64_t mtime_sec , int mtime_nsec )
2014-02-12 20:02:35 +01:00
{
2026-10-14 18:46:56 +02:00
tommy_uint32_t nsec = mtime_nsec ;
2026-10-07 19:13:27 +02:00
# if TOMMY_SIZE_BIT == 64
2026-10-14 18:46:56 +02:00
tommy_uint64_t size_key = size ;
tommy_uint64_t sec_key = mtime_sec ;
tommy_uint64_t nsec_key = nsec ;
/* valid nanoseconds use 30 bits above contemporary seconds; -1 stays distinct */
return tommy_mulhash_u64 ( size_key ^ tommy_mulhash_u64 ( sec_key ^ ( nsec_key < < 34 ) ) ) ;
2026-10-07 19:13:27 +02:00
# else
2026-10-14 18:46:56 +02:00
tommy_uint32_t size_key = size ;
tommy_uint32_t sec_key = mtime_sec ;
return tommy_mulhash_u32 ( size_key ^ tommy_mulhash_u32 ( sec_key ) ^ tommy_mulhash_u32 ( nsec ) ) ;
2026-10-07 19:13:27 +02:00
# endif
2014-02-12 20:02:35 +01:00
}
2015-10-04 22:02:05 +02:00
/**
2016-05-23 22:10:05 +02:00
* Allocate a extent .
2015-10-04 22:02:05 +02:00
*/
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
* Deallocate a extent .
2015-10-04 22:02:05 +02:00
*/
2026-08-24 23:03:00 +02:00
void extent_free ( void * void_extent ) ;
2015-10-04 22:02:05 +02:00
/**
2016-05-23 22:10:05 +02:00
* Compare extent by parity position .
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
* Compare extent by file and file position .
2015-10-04 22:02:05 +02:00
*/
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
2015-10-08 22:19:52 +02:00
static inline int link_flag_has ( const struct snapraid_link * slink , unsigned mask )
2011-08-26 14:18:38 +02:00
{
2015-10-08 22:19:52 +02:00
return ( slink - > flag & mask ) = = mask ;
2011-08-26 14:18:38 +02:00
}
2015-10-08 22:19:52 +02:00
static inline void link_flag_set ( struct snapraid_link * slink , unsigned mask )
2011-08-26 14:18:38 +02:00
{
2015-10-08 22:19:52 +02:00
slink - > flag | = mask ;
2011-08-26 14:18:38 +02:00
}
2015-10-08 22:19:52 +02:00
static inline void link_flag_clear ( struct snapraid_link * slink , unsigned mask )
2011-08-26 14:18:38 +02:00
{
2015-10-08 22:19:52 +02:00
slink - > flag & = ~ mask ;
2011-08-26 14:18:38 +02:00
}
2015-10-08 22:19:52 +02:00
static inline void link_flag_let ( struct snapraid_link * slink , unsigned flag , unsigned mask )
2013-02-28 21:56:02 +01:00
{
2015-10-08 22:19:52 +02:00
slink - > flag & = ~ mask ;
slink - > flag | = flag & mask ;
2013-02-28 21:56:02 +01:00
}
2015-10-08 22:19:52 +02:00
static inline unsigned link_flag_get ( struct snapraid_link * slink , unsigned mask )
2013-01-27 18:06:15 +01:00
{
2015-10-08 22:19:52 +02:00
return slink - > flag & mask ;
2013-01-27 18:06:15 +01:00
}
2011-08-26 14:18:38 +02:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a link .
2011-08-26 14:18:38 +02:00
*/
2026-10-03 17:00:24 +02:00
struct snapraid_link * link_alloc_len ( const char * name , size_t name_len , const char * slink , size_t slink_len , unsigned link_flag ) ;
static inline struct snapraid_link * link_alloc ( const char * name , const char * slink , unsigned link_flag )
{
return link_alloc_len ( name , strlen ( name ) , slink , strlen ( slink ) , link_flag ) ;
}
2011-08-26 14:18:38 +02:00
/**
2015-10-07 22:07:20 +02:00
* Deallocate a link .
2011-08-26 14:18:38 +02:00
*/
2026-08-24 23:03:00 +02:00
void link_free ( void * void_link ) ;
2011-08-26 14:18:38 +02:00
/**
* Compare a link with a name .
*/
2013-10-19 13:24:35 +02:00
int link_name_compare_to_arg ( const void * void_arg , const void * void_data ) ;
/**
2015-10-07 22:07:20 +02:00
* Compare links by path .
2013-10-19 13:24:35 +02:00
*/
int link_alpha_compare ( const void * void_a , const void * void_b ) ;
2011-08-26 14:18:38 +02:00
2026-10-03 17:00:24 +02:00
/**
* Compute the hash of a link name with known length .
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t link_name_hash_len ( const char * name , size_t len )
2026-10-03 17:00:24 +02:00
{
2026-10-07 19:13:27 +02:00
# if TOMMY_SIZE_BIT == 64
return tommy_hash_u64 ( 0 , name , len ) ;
# else
2026-10-03 17:00:24 +02:00
return tommy_hash_u32 ( 0 , name , len ) ;
2026-10-07 19:13:27 +02:00
# endif
2026-10-03 17:00:24 +02:00
}
2011-08-26 14:18:38 +02:00
/**
2015-10-07 22:07:20 +02:00
* Compute the hash of a link name .
2011-08-26 14:18:38 +02:00
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t link_name_hash ( const char * name )
2011-08-26 14:18:38 +02:00
{
2026-10-03 17:00:24 +02:00
return link_name_hash_len ( name , strlen ( name ) ) ;
2011-08-26 14:18:38 +02:00
}
2013-02-24 11:33:09 +01:00
static inline int dir_flag_has ( const struct snapraid_dir * dir , unsigned mask )
2013-01-27 16:44:04 +01:00
{
return ( dir - > flag & mask ) = = mask ;
}
static inline void dir_flag_set ( struct snapraid_dir * dir , unsigned mask )
{
dir - > flag | = mask ;
}
static inline void dir_flag_clear ( struct snapraid_dir * dir , unsigned mask )
{
dir - > flag & = ~ mask ;
}
/**
2015-10-07 22:07:20 +02:00
* Allocate a dir .
2013-01-27 16:44:04 +01:00
*/
2026-10-03 17:00:24 +02:00
struct snapraid_dir * dir_alloc_len ( const char * name , size_t name_len ) ;
static inline struct snapraid_dir * dir_alloc ( const char * name )
{
return dir_alloc_len ( name , strlen ( name ) ) ;
}
2013-01-27 16:44:04 +01:00
/**
2015-10-07 22:07:20 +02:00
* Deallocate a dir .
2013-01-27 16:44:04 +01:00
*/
2026-08-24 23:03:00 +02:00
void dir_free ( void * void_dir ) ;
2013-01-27 16:44:04 +01:00
/**
* Compare a dir with a name .
*/
int dir_name_compare ( const void * void_arg , const void * void_data ) ;
2026-10-03 17:00:24 +02:00
/**
* Compute the hash of a dir name with known length .
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t dir_name_hash_len ( const char * name , size_t len )
2026-10-03 17:00:24 +02:00
{
2026-10-07 19:13:27 +02:00
# if TOMMY_SIZE_BIT == 64
return tommy_hash_u64 ( 0 , name , len ) ;
# else
2026-10-03 17:00:24 +02:00
return tommy_hash_u32 ( 0 , name , len ) ;
2026-10-07 19:13:27 +02:00
# endif
2026-10-03 17:00:24 +02:00
}
2013-01-27 16:44:04 +01:00
/**
2015-10-07 22:07:20 +02:00
* Compute the hash of a dir name .
2013-01-27 16:44:04 +01:00
*/
2026-10-07 19:13:27 +02:00
static inline tommy_hash_t dir_name_hash ( const char * name )
2013-01-27 16:44:04 +01:00
{
2026-10-03 17:00:24 +02:00
return dir_name_hash_len ( name , strlen ( name ) ) ;
2013-01-27 16:44:04 +01:00
}
2026-04-27 14:39:38 +02:00
/**
* Allocate a dealloc .
*/
2026-10-03 17:00:24 +02:00
struct snapraid_dealloc * dealloc_alloc_len ( unsigned block_size , const char * sub , size_t sub_len , data_off_t size , int64_t mtime_sec , int32_t mtime_nsec ) ;
static inline struct snapraid_dealloc * dealloc_alloc ( unsigned block_size , const char * sub , data_off_t size , int64_t mtime_sec , int32_t mtime_nsec )
{
return dealloc_alloc_len ( block_size , sub , strlen ( sub ) , size , mtime_sec , mtime_nsec ) ;
}
2026-04-27 14:39:38 +02:00
/**
* Deallocate a dealloc .
*/
2026-08-24 23:03:00 +02:00
void dealloc_free ( void * void_dealloc ) ;
2026-04-27 14:39:38 +02:00
/**
* Import file hash in the dealloc .
*/
2026-09-25 23:40:58 +02:00
void dealloc_import ( tommy_arrayblkof * infoarr , struct snapraid_disk * disk , struct snapraid_dealloc * dealloc , struct snapraid_file * file ) ;
2026-04-27 14:39:38 +02:00
2011-03-12 23:36:37 +01:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a disk .
2011-03-12 23:36:37 +01:00
*/
2021-05-22 10:09:43 +02:00
struct snapraid_disk * disk_alloc ( const char * name , const char * dir , uint64_t dev , const char * uuid , int skip_access ) ;
2011-03-04 20:59:21 +01:00
2011-03-12 23:36:37 +01:00
/**
2015-10-07 22:07:20 +02:00
* Deallocate a disk .
2011-03-12 23:36:37 +01:00
*/
2026-08-24 23:03:00 +02:00
void disk_free ( void * void_disk ) ;
2011-03-04 20:59:21 +01:00
2026-03-11 13:53:42 +01:00
/**
* Allocate a extra disk .
*/
struct snapraid_extra * extra_alloc ( const char * name , const char * dir , uint64_t dev , const char * uuid ) ;
/**
* Deallocate a other disk .
*/
2026-08-24 23:03:00 +02:00
void extra_free ( void * void_extra ) ;
2026-03-11 13:53:42 +01:00
2011-03-12 23:36:37 +01:00
/**
2015-10-01 18:19:48 +02:00
* Get the size of the disk in blocks .
2011-03-12 23:36:37 +01: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
/**
2015-10-04 22:02:05 +02:00
* Check if a disk is totally empty and can be discarded from the content file .
* A disk is empty if it doesn ' t contain any file , symlink , hardlink or dir
* and without any DELETED block .
* The blockmax is used to limit the search of DELETED block up to blockmax .
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
2015-10-05 21:40:44 +02:00
/**
2016-01-02 16:52:20 +01:00
* Check the file - system for errors .
2015-10-05 21:40:44 +02:00
* Return 0 if it ' s OK .
*/
int fs_check ( struct snapraid_disk * disk ) ;
2015-10-01 18:19:48 +02:00
/**
2026-09-09 18:06:09 +02:00
* Allocate a run of parity positions for the specified file positions .
2015-10-04 22:02:05 +02:00
*
* After this call you can use the par2file / par2block operations
* to query the relation .
2015-10-30 19:06:24 +01:00
*
2020-05-02 14:21:40 +02:00
* \ note This function is NOT thread - safe as it uses the disk cache . +
2015-10-01 18:19:48 +02:00
*/
2026-09-09 18:06:09 +02:00
void fs_allocate ( struct snapraid_disk * disk , block_off_t parity_pos , struct snapraid_file * file , block_off_t file_pos , block_off_t count ) ;
2015-10-01 18:19:48 +02:00
/**
2015-10-04 22:02:05 +02:00
* Deallocate the parity position .
*
2015-10-05 22:48:16 +02:00
* After this call the par2file / par2block operations
2015-10-04 22:02:05 +02:00
* won ' t find anymore the parity association .
2015-10-30 19:06:24 +01:00
*
2020-05-02 14:21:40 +02:00
* \ note This function is NOT thread - safe as it uses the disk cache .
2015-10-01 18:19:48 +02:00
*/
2015-10-04 22:02:05 +02:00
void fs_deallocate ( struct snapraid_disk * disk , block_off_t pos ) ;
2015-10-01 18:19:48 +02:00
/**
* Get the block from the file position .
*/
2015-11-18 22:10:50 +01:00
struct snapraid_block * fs_file2block_get ( struct snapraid_file * file , block_off_t file_pos ) ;
2015-10-01 18:19:48 +02:00
2026-10-06 10:42:03 +02:00
/**
* Find the first extent ending after the specified parity position .
* Return 0 if no such extent exists . The caller must ensure that the extent
* trees remain unchanged while using the returned extent or its tree node .
*/
struct snapraid_extent * fs_par2extent_find_next ( struct snapraid_disk * disk , block_off_t parity_pos ) ;
2015-10-01 18:19:48 +02:00
/**
2015-10-04 22:02:05 +02:00
* Get the file position from the parity position .
* Return 0 if no file is using it .
2015-10-30 19:06:24 +01: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 ) ;
2016-01-15 20:22:41 +01:00
/**
* Get the file position from the parity position .
*/
static inline struct snapraid_file * fs_par2file_get ( struct snapraid_disk * disk , block_off_t parity_pos , block_off_t * file_pos )
{
struct snapraid_file * ret ;
2016-01-16 14:26:05 +01:00
ret = fs_par2file_find ( disk , parity_pos , file_pos ) ;
2016-01-15 20:22:41 +01:00
if ( ret = = 0 ) {
/* LCOV_EXCL_START */
2026-06-03 23:06:27 +02:00
log_fatal ( EINTERNAL , " Internal inconsistency: Deresolving parity to file at position '% " PRIu64 " ' in disk '%s' \n " , parity_pos , disk - > name ) ;
2016-01-15 20:22:41 +01:00
os_abort ( ) ;
/* LCOV_EXCL_STOP */
}
return ret ;
}
2015-10-01 18:19:48 +02:00
/**
2015-10-04 22:02:05 +02:00
* Get the parity position from the file position .
2016-01-16 14:26:05 +01:00
* Return POS_NULL if no parity is allocated .
2015-10-01 18:19:48 +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 ) ;
2016-01-15 20:05:38 +01:00
/**
2026-09-09 21:58:54 +02:00
* Get the parity position from the file position . If count is specified , return
* the number of blocks remaining in the same extent , including the current one .
* Return POS_NULL if no parity is allocated .
2016-01-15 20:05:38 +01:00
*/
2026-09-09 21:58:54 +02:00
block_off_t fs_file2par_find_run ( struct snapraid_disk * disk , struct snapraid_file * file , block_off_t file_pos , block_off_t * count ) ;
/**
* Get the parity position and the number of blocks remaining in the same extent ,
* including the current one , from the file position .
*/
static inline block_off_t fs_file2par_get_run ( struct snapraid_disk * disk , struct snapraid_file * file , block_off_t file_pos , block_off_t * count )
2016-01-15 20:05:38 +01:00
{
block_off_t ret ;
2026-09-09 21:58:54 +02:00
ret = fs_file2par_find_run ( disk , file , file_pos , count ) ;
2016-01-16 14:26:05 +01:00
if ( ret = = POS_NULL ) {
2016-01-15 20:05:38 +01:00
/* LCOV_EXCL_START */
2026-06-03 23:06:27 +02:00
log_fatal ( EINTERNAL , " Internal inconsistency: Resolving file '%s' at position '% " PRIu64 " /% " PRIu64 " ' in disk '%s' \n " , file - > sub , file_pos , file - > blockmax , disk - > name ) ;
2016-01-15 20:05:38 +01:00
os_abort ( ) ;
/* LCOV_EXCL_STOP */
}
return ret ;
}
2015-10-01 18:19:48 +02:00
2026-09-09 21:58:54 +02:00
/**
* Get the parity position from the file position .
*/
static inline block_off_t fs_file2par_get ( struct snapraid_disk * disk , struct snapraid_file * file , block_off_t file_pos )
{
return fs_file2par_get_run ( disk , file , file_pos , 0 ) ;
}
2015-10-01 18:19:48 +02:00
/**
* Get the block from the parity position .
2016-01-16 14:26:05 +01:00
* Return BLOCK_NULL = = 0 if the block is over the end of the disk or not used .
2015-10-01 18:19:48 +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 ) ;
2016-01-15 20:32:49 +01:00
/**
* Get the block from the parity position .
*/
static inline struct snapraid_block * fs_par2block_get ( struct snapraid_disk * disk , block_off_t parity_pos )
{
struct snapraid_block * ret ;
2016-01-16 14:26:05 +01:00
ret = fs_par2block_find ( disk , parity_pos ) ;
if ( ret = = BLOCK_NULL ) {
2016-01-15 20:32:49 +01:00
/* LCOV_EXCL_START */
2026-06-03 23:06:27 +02:00
log_fatal ( EINTERNAL , " Internal inconsistency: Deresolving parity to block at position '% " PRIu64 " ' in disk '%s' \n " , parity_pos , disk - > name ) ;
2016-01-15 20:32:49 +01:00
os_abort ( ) ;
/* LCOV_EXCL_STOP */
}
return ret ;
}
2011-03-04 20:59:21 +01:00
2011-10-01 19:18:32 +02:00
/**
2015-10-07 22:07:20 +02:00
* Allocate a disk mapping .
2013-03-03 22:39:46 +01:00
* Uses uuid = " " if not available .
2011-10-01 19:18:32 +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
/**
2015-10-07 22:07:20 +02:00
* Deallocate a disk mapping .
2011-10-01 19:18:32 +02:00
*/
2026-08-24 23:03:00 +02:00
void map_free ( void * void_map ) ;
2011-10-01 19:18:32 +02:00
2015-08-27 18:02:12 +02:00
/**
* Mask used to store additional information in the info bits .
*
2016-01-02 16:52:20 +01:00
* These bits reduce the granularity of the time in the memory representation .
2015-08-27 18:02:12 +02:00
*/
2025-10-08 12:42:40 +02:00
# define INFO_MASK ((snapraid_info)0x7)
2015-08-27 18:02:12 +02:00
2013-06-22 18:13:19 +02:00
/**
2015-10-07 22:07:20 +02:00
* Make an info .
2013-06-22 18:13:19 +02:00
*/
2015-08-27 18:02:12 +02:00
static inline snapraid_info info_make ( time_t last_access , int error , int rehash , int justsynced )
2013-06-22 18:13:19 +02:00
{
2013-06-29 17:53:40 +02:00
/* clear the lowest bits as reserved for other information */
2015-08-27 18:02:12 +02:00
snapraid_info info = last_access & ~ INFO_MASK ;
2014-09-27 00:32:39 +02:00
2013-06-29 17:53:40 +02:00
if ( error ! = 0 )
2013-07-01 23:08:25 +02:00
info | = 0x1 ;
if ( rehash ! = 0 )
info | = 0x2 ;
2015-08-27 18:02:12 +02:00
if ( justsynced ! = 0 )
info | = 0x4 ;
2013-06-29 17:53:40 +02:00
return info ;
}
/**
2015-10-07 22:07:20 +02:00
* Extract the time information .
2013-06-29 17:53:40 +02:00
* This is the last time when the block was know to be correct .
2020-05-02 14:21:40 +02:00
* The " scrubbed " info tells if the time is referring at the latest sync or scrub .
2013-06-29 17:53:40 +02:00
*/
static inline time_t info_get_time ( snapraid_info info )
{
2015-08-27 18:02:12 +02:00
return info & ~ INFO_MASK ;
2013-06-29 17:53:40 +02:00
}
/**
2015-10-07 22:07:20 +02:00
* Extract the error information .
* Report if the block address had some problem .
2013-06-29 17:53:40 +02:00
*/
2013-07-01 23:08:25 +02:00
static inline int info_get_bad ( snapraid_info info )
2013-06-29 17:53:40 +02:00
{
return ( info & 0x1 ) ! = 0 ;
}
2013-07-01 23:08:25 +02:00
/**
2015-10-07 22:07:20 +02:00
* Extract the rehash information .
* Report if the block address is using the old hash and needs to be rehashed .
2013-07-01 23:08:25 +02:00
*/
static inline int info_get_rehash ( snapraid_info info )
{
return ( info & 0x2 ) ! = 0 ;
}
2015-08-27 18:02:12 +02:00
/**
2015-10-07 22:07:20 +02:00
* Extract the scrubbed information .
* Report if the block address was never scrubbed .
2015-08-27 18:02:12 +02:00
*/
static inline int info_get_justsynced ( snapraid_info info )
{
return ( info & 0x4 ) ! = 0 ;
}
2013-06-29 17:53:40 +02:00
/**
2015-10-07 22:07:20 +02:00
* Mark the block address as with error .
2013-06-29 17:53:40 +02:00
*/
2013-07-01 23:08:25 +02:00
static inline snapraid_info info_set_bad ( snapraid_info info )
2013-06-29 17:53:40 +02:00
{
return info | 0x1 ;
2013-06-23 22:54:54 +02:00
}
2013-07-01 23:08:25 +02:00
/**
2015-10-07 22:07:20 +02:00
* Mark the block address as with rehash .
2013-07-01 23:08:25 +02:00
*/
static inline snapraid_info info_set_rehash ( snapraid_info info )
{
return info | 0x2 ;
}
2013-06-23 22:54:54 +02:00
/**
2015-10-07 22:07:20 +02:00
* Set the info at the specified position .
2013-06-23 22:54:54 +02:00
* The position is allocated if not yet done .
*/
2016-01-16 14:26:05 +01:00
static inline void info_set ( tommy_arrayblkof * array , block_off_t pos , snapraid_info info )
2013-06-23 22:54:54 +02:00
{
2013-09-28 09:40:08 +02:00
tommy_arrayblkof_grow ( array , pos + 1 ) ;
2013-06-23 22:54:54 +02:00
2013-09-28 09:40:08 +02:00
memcpy ( tommy_arrayblkof_ref ( array , pos ) , & info , sizeof ( snapraid_info ) ) ;
2013-06-23 22:54:54 +02:00
}
/**
2015-10-07 22:07:20 +02:00
* Get the info at the specified position .
2013-06-23 22:54:54 +02:00
* For not allocated position , 0 is returned .
*/
2016-01-16 14:26:05 +01:00
static inline snapraid_info info_get ( tommy_arrayblkof * array , block_off_t pos )
2013-06-23 22:54:54 +02:00
{
snapraid_info info ;
2014-09-27 00:32:39 +02:00
2013-09-28 09:40:08 +02:00
if ( pos > = tommy_arrayblkof_size ( array ) )
2013-06-23 22:54:54 +02:00
return 0 ;
2013-09-28 09:40:08 +02:00
memcpy ( & info , tommy_arrayblkof_ref ( array , pos ) , sizeof ( snapraid_info ) ) ;
2013-06-23 22:54:54 +02:00
return info ;
2013-06-22 18:13:19 +02:00
}
2026-09-10 00:08:58 +02:00
/**
* Set a run of info values .
*
* Grow the array once and process each internal block directly , avoiding the
* per - position grow and lookup performed by info_set ( ) .
*/
2026-10-05 11:32:55 +02:00
__aligned_loops ( 64 )
2026-09-10 00:08:58 +02:00
static inline void info_set_run ( tommy_arrayblkof * array , block_off_t pos , block_off_t count , snapraid_info info )
{
tommy_arrayblkof_grow ( array , pos + count ) ;
while ( count ) {
block_off_t offset = pos % TOMMY_ARRAYBLKOF_SIZE ;
block_off_t run = TOMMY_ARRAYBLKOF_SIZE - offset ;
snapraid_info * data ;
block_off_t i ;
if ( run > count )
run = count ;
data = tommy_arrayblkof_ref ( array , pos ) ;
for ( i = 0 ; i < run ; + + i )
data [ i ] = info ;
pos + = run ;
count - = run ;
}
}
/**
* Get the value and length of an info run , up to count positions .
*
* Unallocated positions have the same zero value returned by info_get ( ) .
* Process allocated storage a block at a time to avoid resolving every array
* position independently .
*/
static inline block_off_t info_get_run ( tommy_arrayblkof * array , block_off_t pos , block_off_t count , snapraid_info * info )
{
block_off_t size = tommy_arrayblkof_size ( array ) ;
block_off_t total = 0 ;
if ( pos > = size ) {
* info = 0 ;
return count ;
}
memcpy ( info , tommy_arrayblkof_ref ( array , pos ) , sizeof ( snapraid_info ) ) ;
while ( total < count & & pos + total < size ) {
block_off_t current = pos + total ;
block_off_t offset = current % TOMMY_ARRAYBLKOF_SIZE ;
block_off_t run = TOMMY_ARRAYBLKOF_SIZE - offset ;
snapraid_info * data ;
block_off_t i ;
if ( run > count - total )
run = count - total ;
if ( run > size - current )
run = size - current ;
data = tommy_arrayblkof_ref ( array , current ) ;
for ( i = 0 ; i < run ; + + i )
if ( data [ i ] ! = * info )
return total + i ;
total + = run ;
}
/* info_get() returns zero for the whole unallocated tail */
if ( total < count & & * info = = 0 )
return count ;
return total ;
}
2026-02-08 22:56:22 +01:00
/****************************************************************************/
/* bucket */
struct snapraid_bucket {
time_t time_at ; /**< Time of the scrub */
block_off_t count_scrubbed ; /**< Number of blocks scrubbed */
block_off_t count_justsynced ; /**< Number of blocks justsynced */
tommy_node node ;
} ;
2026-08-24 23:03:00 +02:00
void bucket_free ( void * void_bucket ) ;
2026-02-08 22:56:22 +01:00
2026-10-14 18:46:56 +02:00
/**
* Compute the hash of a bucket time .
*/
static inline tommy_hash_t bucket_time_hash ( time_t time_at )
{
# if TOMMY_SIZE_BIT == 64
return tommy_mulhash_u64 ( time_at ) ;
# else
/* avoid expensive 64-bit multiplications on 32-bit architectures */
return tommy_inthash_u64 ( time_at ) ;
# endif
}
2026-02-08 22:56:22 +01:00
/**
* Insert an bucket record into the hashtable
*/
void bucket_insert ( tommy_hashdyn * bucket_hash , time_t time_at , block_off_t count , int justsynced ) ;
2013-06-29 17:53:40 +02:00
/**
2026-02-08 22:56:22 +01:00
* Convert the bucket hashtable to a sorted list
2013-06-29 17:53:40 +02:00
*/
2026-02-08 22:56:22 +01:00
void bucket_to_list ( tommy_hashdyn * bucket_hash , tommy_list * bucket_list , block_off_t * bucketcount ) ;
2013-06-29 17:53:40 +02:00
2016-10-11 20:30:12 +02:00
/****************************************************************************/
/* format */
# define FMT_FILE 0 /**< Print only the file. */
# define FMT_DISK 1 /**< Print the disk name and the file. */
# define FMT_PATH 2 /**< Print the full path. */
extern int FMT_MODE ;
2016-05-29 19:23:42 +02:00
/**
* Format a file path for poll reference
*/
2026-05-29 11:01:44 +02:00
const char * fmt_poll ( const struct snapraid_disk * disk , const char * str ) ;
2016-05-29 19:23:42 +02:00
/**
* Format a path name for terminal reference
*/
2026-05-29 11:01:44 +02:00
const char * fmt_term ( const struct snapraid_disk * disk , const char * str ) ;
2016-05-29 19:23:42 +02:00
2026-02-02 11:19:51 +01:00
/**
* Format a size adding suffix K / M / G / T
*/
const char * fmt_size ( uint64_t size , char * buffer , size_t buffer_size ) ;
2011-03-04 20:59:21 +01:00
# endif