Change commenting style

This commit is contained in:
Andrea Mazzoleni 2026-04-27 15:43:06 +02:00
parent 20d7a9d513
commit 21673eb805
22 changed files with 1044 additions and 603 deletions

View file

@ -115,17 +115,21 @@ static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned d
}
}
/* if nothing checked, we reject it */
/* note that we are excluding this case at upper level */
/* but checking again doesn't hurt */
/*
* If nothing checked, we reject it
* note that we are excluding this case at upper level
* but checking again doesn't hurt
*/
if (!hash_checked) {
/* LCOV_EXCL_START */
return 0;
/* LCOV_EXCL_STOP */
}
/* if we checked something, and no block failed the check */
/* recompute all the redundancy information */
/*
* If we checked something, and no block failed the check
* recompute all the redundancy information
*/
raid_gen(diskmax, state->level, state->block_size, buffer);
return 1;
}
@ -184,8 +188,10 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
for (i = 0; i < failed_count; ++i)
id[i] = failed[failed_map[i]].index;
/* check if there is at least a failed block that can be checked for correctness using the hash */
/* if there isn't, we have to sacrifice a parity block to check that the result is correct */
/*
* Check if there is at least a failed block that can be checked for correctness using the hash
* if there isn't, we have to sacrifice a parity block to check that the result is correct
*/
has_hash = 0;
for (i = 0; i < failed_count; ++i) {
/* if we are expected to recover this block */
@ -196,8 +202,10 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
has_hash = 1;
}
/* if we don't have a hash, but we have an extra parity */
/* (strictly-less failures than number of parities) */
/*
* If we don't have a hash, but we have an extra parity
* (strictly-less failures than number of parities)
*/
if (!has_hash && failed_count < n) {
/* number of parity to use, one more to check the recovering */
unsigned r = failed_count + 1;
@ -236,8 +244,10 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
} while (combination_next(r, n, ip));
}
/* if we have a hash, and enough parities */
/* (less-or-equal failures than number of parities) */
/*
* If we have a hash, and enough parities
* (less-or-equal failures than number of parities)
*/
if (has_hash && failed_count <= n) {
/* number of parities to use equal to the number of failures */
unsigned r = failed_count;
@ -343,21 +353,27 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
}
}
/* Here we have to try two different strategies to recover, because in case the 'sync' */
/* process is aborted, we don't know if the parity data is really updated just like after 'sync', */
/* or if it still represents the state before the 'sync'. */
/*
* Here we have to try two different strategies to recover, because in case the 'sync'
* process is aborted, we don't know if the parity data is really updated just like after 'sync',
* or if it still represents the state before the 'sync'.
*/
/* Note that if the 'sync' ends normally, we don't have any DELETED, REP and CHG blocks */
/* and the two strategies are identical */
/*
* Note that if the 'sync' ends normally, we don't have any DELETED, REP and CHG blocks
* and the two strategies are identical
*/
/* As first, we assume that the parity IS updated for the current state */
/* and that we are going to recover the state after the last 'sync'. */
/* In this case, parity contains info from BLK, REP and CHG blocks, */
/* but not for DELETED. */
/* We need to put in the recovering process only the bad blocks, because all the */
/* others already contains the correct data read from disk, and the parity is correctly computed for them. */
/* We are interested to recover BLK, REP and CHG blocks if they are marked as bad, */
/* but we are not interested in DELETED ones. */
/*
* As first, we assume that the parity IS updated for the current state
* and that we are going to recover the state after the last 'sync'.
* In this case, parity contains info from BLK, REP and CHG blocks,
* but not for DELETED.
* We need to put in the recovering process only the bad blocks, because all the
* others already contains the correct data read from disk, and the parity is correctly computed for them.
* We are interested to recover BLK, REP and CHG blocks if they are marked as bad,
* but we are not interested in DELETED ones.
*/
n = 0;
something_to_recover = 0; /* keep track if there is at least one block to fix */
@ -397,17 +413,21 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
if (ret == 0) {
/* reprocess the CHG blocks, for which we don't have a hash to check */
/* if they were BAD we have to use some heuristics to ensure that we have recovered */
/* the state after the sync. If unsure, we assume the worst case */
/*
* Reprocess the CHG blocks, for which we don't have a hash to check
* if they were BAD we have to use some heuristics to ensure that we have recovered
* the state after the sync. If unsure, we assume the worst case
*/
for (j = 0; j < failed_count; ++j) {
/* we take care only of BAD blocks we have to write back */
if (failed[j].is_bad) {
unsigned block_state = block_state_get(failed[j].block);
/* BLK and REP blocks are always OK, because at this point */
/* we have already checked their hash */
/*
* BLK and REP blocks are always OK, because at this point
* we have already checked their hash
*/
if (block_state != BLOCK_STATE_CHG) {
assert(block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP);
continue;
@ -415,20 +435,24 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
/* for CHG blocks we have to 'guess' if they are correct or not */
/* if the hash is invalid we cannot check the result */
/* this could happen if we have lost this information */
/* after an aborted sync */
/*
* If the hash is invalid we cannot check the result
* this could happen if we have lost this information
* after an aborted sync
*/
if (hash_is_invalid(failed[j].block->hash)) {
/* it may contain garbage */
failed[j].is_outofdate = 1;
log_tag("repair:hash_unknown:%u: Unknown hash\n", j);
} else if (hash_is_zero(failed[j].block->hash)) {
/* if the block is not filled with 0, we are sure to have */
/* restored it to the state after the 'sync' */
/* instead, if the block is filled with 0, it could be either that the */
/* block after the sync is really filled by 0, or that */
/* we restored the block before the 'sync'. */
/*
* If the block is not filled with 0, we are sure to have
* restored it to the state after the 'sync'
* instead, if the block is filled with 0, it could be either that the
* block after the sync is really filled by 0, or that
* we restored the block before the 'sync'.
*/
if (memcmp(buffer[failed[j].index], buffer_zero, state->block_size) == 0) {
/* it may contain garbage */
failed[j].is_outofdate = 1;
@ -436,11 +460,13 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
log_tag("repair_hash_unknown:%u: Maybe old zero\n", j);
}
} else {
/* if the hash is different than the previous one, we are sure to have */
/* restored it to the state after the 'sync' */
/* instead, if the hash matches, it could be either that the */
/* block after the sync has this hash, or that */
/* we restored the block before the 'sync'. */
/*
* If the hash is different than the previous one, we are sure to have
* restored it to the state after the 'sync'
* instead, if the hash matches, it could be either that the
* block after the sync has this hash, or that
* we restored the block before the 'sync'.
*/
unsigned pos_size = file_block_size(failed[j].file, failed[j].file_pos, state->block_size);
if (blockcmp(state, rehash, failed[j].block, pos_size, buffer[failed[j].index], buffer_zero) == 0) {
/* it may contain garbage */
@ -462,14 +488,16 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
else
log_tag("recover_sync:%u:%u: Failed with %d attempts\n", pos, n, ret);
/* Now assume that the parity IS NOT updated at the current state, */
/* but still represent the state before the last 'sync' process. */
/* In this case, parity contains info from BLK, REP (old version), CHG (old version) and DELETED blocks, */
/* but not for REP (new version) and CHG (new version). */
/* We are interested to recover BLK ones marked as bad, */
/* but we are not interested to recover CHG (new version) and REP (new version) blocks, */
/* even if marked as bad, because we don't have parity for them and it's just impossible, */
/* and we are not interested to recover DELETED ones. */
/*
* Now assume that the parity IS NOT updated at the current state,
* but still represent the state before the last 'sync' process.
* In this case, parity contains info from BLK, REP (old version), CHG (old version) and DELETED blocks,
* but not for REP (new version) and CHG (new version).
* We are interested to recover BLK ones marked as bad,
* but we are not interested to recover CHG (new version) and REP (new version) blocks,
* even if marked as bad, because we don't have parity for them and it's just impossible,
* and we are not interested to recover DELETED ones.
*/
n = 0;
something_to_recover = 0; /* keep track if there is at least one block to fix */
something_unsynced = 0; /* keep track if we have some unsynced info to process */
@ -480,49 +508,63 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
|| block_state == BLOCK_STATE_CHG
|| block_state == BLOCK_STATE_REP
) {
/* If the block is CHG, REP or DELETED, we don't have the original content of block, */
/* and we must try to recover it. */
/* This applies to CHG and REP blocks even if they are not marked bad, */
/* because the parity is computed with old content, and not with the new one. */
/* Note that this recovering is done just to make it possible to recover any other BLK one, */
/* we are not really interested in DELETED, CHG (old version) and REP (old version). */
/*
* If the block is CHG, REP or DELETED, we don't have the original content of block,
* and we must try to recover it.
* This applies to CHG and REP blocks even if they are not marked bad,
* because the parity is computed with old content, and not with the new one.
* Note that this recovering is done just to make it possible to recover any other BLK one,
* we are not really interested in DELETED, CHG (old version) and REP (old version).
*/
something_unsynced = 1;
if (block_state == BLOCK_STATE_CHG
&& hash_is_zero(failed[j].block->hash)
) {
/* If the block was a ZERO block, restore it to the original 0 as before the 'sync' */
/* We do this to just allow recovering of other BLK ones */
/*
* If the block was a ZERO block, restore it to the original 0 as before the 'sync'
* We do this to just allow recovering of other BLK ones
*/
memset(buffer[failed[j].index], 0, state->block_size);
/* note that from now the buffer is definitely lost */
/* we can do this only because it's the last retry of recovering */
/*
* Note that from now the buffer is definitely lost
* we can do this only because it's the last retry of recovering
*/
/* try to fetch the old block using the old hash for CHG and DELETED blocks */
} else if ((block_state == BLOCK_STATE_CHG || block_state == BLOCK_STATE_DELETED)
&& hash_is_unique(failed[j].block->hash)
&& state_import_fetch(state, rehash, failed[j].block, buffer[failed[j].index]) == 0) {
/* note that from now the buffer is definitely lost */
/* we can do this only because it's the last retry of recovering */
/*
* Note that from now the buffer is definitely lost
* we can do this only because it's the last retry of recovering
*/
} else {
/* otherwise try to recover it */
failed_map[n] = j;
++n;
/* note that we don't set something_to_recover, because we are */
/* not really interested to recover *only* old blocks. */
/*
* Note that we don't set something_to_recover, because we are
* not really interested to recover *only* old blocks.
*/
}
/* avoid using the hash of this block to verify the recovering */
/* this applies to REP blocks because we are going to recover the old state */
/* and the REP hash represents the new one */
/* it also applies to CHG and DELETE blocks because we want to have */
/* a successful recovering only if a BLK one is matching */
/*
* Avoid using the hash of this block to verify the recovering
* this applies to REP blocks because we are going to recover the old state
* and the REP hash represents the new one
* it also applies to CHG and DELETE blocks because we want to have
* a successful recovering only if a BLK one is matching
*/
failed[j].is_outofdate = 1;
} else if (failed[j].is_bad) {
/* If the block is bad we don't know its content, and we try to recover it */
/* At this point, we can have only BLK ones */
/*
* If the block is bad we don't know its content, and we try to recover it
* At this point, we can have only BLK ones
*/
assert(block_state == BLOCK_STATE_BLK);
@ -535,14 +577,18 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
}
}
/* if nothing to fix, we just don't try */
/* if nothing unsynced we also don't retry, because it's the same try as before */
/*
* If nothing to fix, we just don't try
* if nothing unsynced we also don't retry, because it's the same try as before
*/
if (something_to_recover && something_unsynced) {
ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
if (ret == 0) {
/* reprocess the REP and CHG blocks, for which we have recovered an old state */
/* that we don't want to save into disk */
/* we have already marked them, but we redo it for logging */
/*
* Reprocess the REP and CHG blocks, for which we have recovered an old state
* that we don't want to save into disk
* we have already marked them, but we redo it for logging
*/
for (j = 0; j < failed_count; ++j) {
/* we take care only of BAD blocks we have to write back */
@ -552,8 +598,10 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
if (block_state == BLOCK_STATE_CHG
|| block_state == BLOCK_STATE_REP
) {
/* mark that we have restored an old state */
/* and we don't want to write it to the disk */
/*
* Mark that we have restored an old state
* and we don't want to write it to the disk
*/
failed[j].is_outofdate = 1;
log_tag("repair_hash_unknown:%u: Surely old data\n", j);
@ -599,8 +647,11 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
{
unsigned j;
int ret;
/* for all the files print the final status, and do the final time fix */
/* we also ensure to close files after processing the last block */
/*
* For all the files print the final status, and do the final time fix
* we also ensure to close files after processing the last block
*/
for (j = 0; j < diskmax; ++j) {
struct snapraid_block* block;
struct snapraid_disk* disk;
@ -638,8 +689,10 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
/* finish the fix process if it's the last block of the files */
if (fix) {
/* mark that we finished with this file */
/* to identify later any NOT finished ones */
/*
* Mark that we finished with this file
* to identify later any NOT finished ones
*/
file_flag_set(file, FILE_IS_FINISHED);
/* if the file is damaged, meaning that a fix failed */
@ -686,8 +739,10 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
goto close_and_continue;
}
/* if the file is closed or different than the one expected, reopen it */
/* a different open file could happen when filtering for bad blocks */
/*
* If the file is closed or different than the one expected, reopen it
* a different open file could happen when filtering for bad blocks
*/
if (handle[j].file != file) {
/* keep a pointer at the file we are going to close for error reporting */
struct snapraid_file* report = handle[j].file;
@ -700,8 +755,10 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
/* LCOV_EXCL_STOP */
}
/* reopen it as readonly, as to set the mtime readonly access it's enough */
/* we know that the file exists because it has the FILE_IS_FIXED tag */
/*
* Reopen it as readonly, as to set the mtime readonly access it's enough
* we know that the file exists because it has the FILE_IS_FIXED tag
*/
ret = handle_open(&handle[j], file, state->file_mode, 0);
if (ret != 0) {
/* LCOV_EXCL_START */
@ -720,14 +777,16 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
/* search for the corresponding inode */
collide_file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
/* if the inode is already in the database and it refers to a different file name, */
/* we can fix the file time ONLY if the time and size allow to differentiate */
/* between the two files */
/* for example, suppose we delete a bunch of files with all the same size and time, */
/* when recreating them the inodes may be reused in a different order, */
/* and at the next sync some files may have matching inode/size/time even if different name */
/* not allowing sync to detect that the file is changed and not renamed */
/*
* If the inode is already in the database and it refers to a different file name,
* we can fix the file time ONLY if the time and size allow to differentiate
* between the two files
*
* For example, suppose we delete a bunch of files with all the same size and time,
* when recreating them the inodes may be reused in a different order,
* and at the next sync some files may have matching inode/size/time even if different name
* not allowing sync to detect that the file is changed and not renamed
*/
if (!collide_file /* if not in the database, there is no collision */
|| strcmp(collide_file->sub, file->sub) == 0 /* if the name is the same, it's the right collision */
|| collide_file->size != file->size /* if the size is different, the collision is identified */
@ -750,8 +809,10 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
log_tag("collision:%s:%s:%s: Not setting modification time to avoid inode collision\n", disk->name, esc_tag(file->sub), esc_tag(collide_file->sub));
}
} else {
/* we are not fixing, but only checking */
/* print just the final status */
/*
* We are not fixing, but only checking
* print just the final status
*/
if (file_flag_has(file, FILE_IS_DAMAGED)) {
log_tag("status:unrecoverable:%s:%s\n", disk->name, esc_tag(file->sub));
msg_info("unrecoverable %s\n", fmt_term(disk, file->sub));
@ -768,12 +829,16 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s
}
close_and_continue:
/* if the opened file is the correct one, close it */
/* in case of excluded and fragmented files it's possible */
/* that the opened file is not the current one */
/*
* If the opened file is the correct one, close it
* in case of excluded and fragmented files it's possible
* that the opened file is not the current one
*/
if (handle[j].file == file) {
/* ensure to close the file just after finishing with it */
/* to avoid keeping it open without any possible use */
/*
* Ensure to close the file just after finishing with it
* to avoid keeping it open without any possible use
*/
ret = handle_close(&handle[j]);
if (ret != 0) {
/* LCOV_EXCL_START */
@ -848,8 +913,10 @@ static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct
block = fs_par2block_find(handle[j].disk, i);
/* try to recover all files, even the ones without hash */
/* because in some cases we can recover also them */
/*
* Try to recover all files, even the ones without hash
* because in some cases we can recover also them
*/
if (block_has_file(block)) {
struct snapraid_file* file = fs_par2file_get(handle[j].disk, i, 0);
if (!file_flag_has(file, FILE_IS_EXCLUDED)) { /* only if the file is not filtered out */
@ -958,11 +1025,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
continue;
}
/* If we have valid parity, and it makes sense to check its content. */
/* If we already know that the parity is invalid, we just read the file */
/* but we don't report parity errors */
/* Note that with auditonly, we anyway skip the full parity check, */
/* because we also don't read it at all */
/*
* If we have valid parity, and it makes sense to check its content.
* If we already know that the parity is invalid, we just read the file
* but we don't report parity errors
* Note that with auditonly, we anyway skip the full parity check,
* because we also don't read it at all
*/
valid_parity = 1;
/* If the parity is used by at least one file */
@ -1008,8 +1077,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
/* if the parity is not valid */
if (block_has_invalid_parity(block)) {
/* mark the parity as invalid, and don't try to check/fix it */
/* because it will be recomputed at the next sync */
/*
* Mark the parity as invalid, and don't try to check/fix it
* because it will be recomputed at the next sync
*/
valid_parity = 0;
/* follow */
}
@ -1019,8 +1090,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
/* use an empty block */
memset(buffer[j], 0, state->block_size);
/* store it in the failed set, because potentially */
/* the parity may be still computed with the previous content */
/*
* Store it in the failed set, because potentially
* the parity may be still computed with the previous content
*/
failed[failed_count].is_bad = 0; /* note that is_bad==0 <=> file==0 */
failed[failed_count].is_outofdate = 0;
failed[failed_count].index = j;
@ -1041,9 +1114,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
/* if we are only hashing, we can skip excluded files and don't even read them */
if (state->opt.auditonly && file_flag_has(file, FILE_IS_EXCLUDED)) {
/* use an empty block */
/* in true, this is unnecessary, because we are not checking any parity */
/* but we keep it for completeness */
/*
* Use an empty block
* in true, this is unnecessary, because we are not checking any parity
* but we keep it for completeness
*/
memset(buffer[j], 0, state->block_size);
continue;
}
@ -1081,8 +1156,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
/* check if the file was just created */
if (handle[j].created != 0) {
/* if fragmented, it may be reopened, so remember that the file */
/* was originally missing */
/*
* If fragmented, it may be reopened, so remember that the file
* was originally missing
*/
file_flag_set(file, FILE_IS_CREATED);
}
} else {
@ -1113,9 +1190,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
++soft_error;
}
/* mark the file as missing, to avoid to retry to open it again */
/* note that this can be done only if we are not fixing it */
/* otherwise, it could be recreated */
/*
* Mark the file as missing, to avoid to retry to open it again
* note that this can be done only if we are not fixing it
* otherwise, it could be recreated
*/
file_flag_set(file, FILE_IS_MISSING);
continue;
}
@ -1164,9 +1243,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
}
}
/* mark the file as opened at least one time */
/* this is used to avoid to check the unsynced and size */
/* more than one time, in case the file is reopened later */
/*
* Mark the file as opened at least one time
* this is used to avoid to check the unsynced and size
* more than one time, in case the file is reopened later
*/
file_flag_set(file, FILE_IS_OPENED);
}
@ -1207,12 +1288,16 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
countsize += read_size;
/* always insert CHG blocks, the repair functions needs all of them */
/* because the parity may be still referring at the old state */
/* and the repair must be aware of it */
/*
* Always insert CHG blocks, the repair functions needs all of them
* because the parity may be still referring at the old state
* and the repair must be aware of it
*/
if (block_state == BLOCK_STATE_CHG) {
/* we DO NOT mark them as bad to avoid to overwrite them with wrong data. */
/* if we don't have a hash, we always assume the first read of the block correct. */
/*
* We DO NOT mark them as bad to avoid to overwrite them with wrong data.
* if we don't have a hash, we always assume the first read of the block correct.
*/
failed[failed_count].is_bad = 0; /* we assume the CHG block correct */
failed[failed_count].is_outofdate = 0;
failed[failed_count].index = j;
@ -1254,9 +1339,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
continue;
}
/* always insert REP blocks, the repair functions needs all of them */
/* because the parity may be still referring at the old state */
/* and the repair must be aware of it */
/*
* Always insert REP blocks, the repair functions needs all of them
* because the parity may be still referring at the old state
* and the repair must be aware of it
*/
if (block_state == BLOCK_STATE_REP) {
failed[failed_count].is_bad = 0; /* it's not bad */
failed[failed_count].is_outofdate = 0;
@ -1325,9 +1412,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
file_flag_set(failed[j].file, FILE_IS_DAMAGED);
}
} else {
/* now counts partial recovers */
/* note that this could happen only when we have an incomplete 'sync' */
/* and that we have recovered is the state before the 'sync' */
/*
* Now counts partial recovers
* note that this could happen only when we have an incomplete 'sync'
* and that we have recovered is the state before the 'sync'
*/
int partial_recover_error = 0;
/* print a list of all the errors in files */
@ -1401,8 +1490,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
continue;
}
/* mark the file as containing some fixes */
/* note that it could be also marked as damaged in other iterations */
/*
* Mark the file as containing some fixes
* note that it could be also marked as damaged in other iterations
*/
file_flag_set(failed[j].file, FILE_IS_FIXED);
log_tag("fixed:%u:%s:%s: Fixed data error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub), failed[j].file_pos);
@ -1447,8 +1538,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
}
}
} else {
/* if we are not fixing, we just set the FIXED flag */
/* meaning that we could fix this file if we try */
/*
* If we are not fixing, we just set the FIXED flag
* meaning that we could fix this file if we try
*/
for (j = 0; j < failed_count; ++j) {
if (failed[j].is_bad) {
file_flag_set(failed[j].file, FILE_IS_FIXED);
@ -1457,8 +1550,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
}
}
} else {
/* if we are not checking, we just set the DAMAGED flag */
/* to report that the file is damaged, and we don't know if we can fix it */
/*
* If we are not checking, we just set the DAMAGED flag
* to report that the file is damaged, and we don't know if we can fix it
*/
for (j = 0; j < failed_count; ++j) {
if (failed[j].is_bad) {
file_flag_set(failed[j].file, FILE_IS_DAMAGED);
@ -1578,8 +1673,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
/* LCOV_EXCL_STOP */
}
/* create it */
/* O_NOFOLLOW: do not follow links to ensure to open the real file */
/*
* Create it
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600);
if (f == -1) {
/* LCOV_EXCL_START */
@ -1684,11 +1781,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
if (errno == ENOENT) {
unrecoverable = 1;
if (fix) {
/* if the target doesn't exist, it's unrecoverable */
/* because we cannot create an hardlink of a file that */
/* doesn't exists */
/* but in check, we can assume that fixing will recover */
/* such missing file, so we assume a less drastic error */
/*
* If the target doesn't exist, it's unrecoverable
* because we cannot create an hardlink of a file that
* doesn't exists
* but in check, we can assume that fixing will recover
* such missing file, so we assume a less drastic error
*/
++unrecoverable_error;
}
}
@ -1914,8 +2013,10 @@ bail:
}
}
/* remove all the files created from scratch that have not finished the processing */
/* it happens only when aborting pressing Ctrl+C or other reason. */
/*
* Remove all the files created from scratch that have not finished the processing
* it happens only when aborting pressing Ctrl+C or other reason.
*/
if (fix) {
/* for each disk */
for (i = 0; i < diskmax; ++i) {
@ -1947,9 +2048,11 @@ bail:
continue;
}
/* if the file was originally missing, and processing not yet finished */
/* we have to throw it away to ensure that at the next run we will retry */
/* to fix it, in case we select to undelete missing files */
/*
* If the file was originally missing, and processing not yet finished
* we have to throw it away to ensure that at the next run we will retry
* to fix it, in case we select to undelete missing files
*/
pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
ret = remove(path);
@ -2097,8 +2200,10 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
}
if (fix) {
/* if fixing, create the file and open for writing */
/* if it fails, we cannot continue */
/*
* If fixing, create the file and open for writing
* if it fails, we cannot continue
*/
for (l = 0; l < state->level; ++l) {
/* skip parity disks that are not accessible */
if (state->parity[l].skip_access) {
@ -2144,8 +2249,10 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
}
}
} else if (!state->opt.auditonly) {
/* if checking, open the file for reading */
/* it may fail if the file doesn't exist, in this case we continue to check the files */
/*
* If checking, open the file for reading
* it may fail if the file doesn't exist, in this case we continue to check the files
*/
for (l = 0; l < state->level; ++l) {
parity_ptr[l] = &parity[l];
ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);

View file

@ -413,8 +413,10 @@ static double smart_afr(devinfo_t* devinfo)
}
if (smart[187].raw != SMART_UNASSIGNED) {
/* with some disks, only the lower 16 bits are significant */
/* See: http://web.archive.org/web/20130507072056/http://media.kingston.com/support/downloads/MKP_306_SMART_attribute.pdf */
/*
* With some disks, only the lower 16 bits are significant
* See: http://web.archive.org/web/20130507072056/http://media.kingston.com/support/downloads/MKP_306_SMART_attribute.pdf
*/
double r = smart_afr_value(SMART_187_R, SMART_187_STEP, smart[187].raw & mask16);
if (afr < r)
afr = r;
@ -430,8 +432,10 @@ static double smart_afr(devinfo_t* devinfo)
*/
strncmp(devinfo->model, "ST", 2) != 0 && smart[188].raw != SMART_UNASSIGNED
) {
/* with Seagate disks, there are three different 16 bits value reported */
/* the lowest one is the most significant */
/*
* With Seagate disks, there are three different 16 bits value reported
* the lowest one is the most significant
*/
double r = smart_afr_value(SMART_188_R, SMART_188_STEP, smart[188].raw & mask16);
if (afr < r)
afr = r;
@ -488,12 +492,16 @@ static double raid_prob_of_one_or_more_failures(double array_failure_rate, doubl
if (array_failure_rate == 0)
return 0;
/* get the Mean Time Between Failure of a single disk */
/* from the array failure rate */
/*
* Get the Mean Time Between Failure of a single disk
* from the array failure rate
*/
MTBF = n / array_failure_rate;
/* get the Mean Time Between Repair (the time that a failed disk is replaced) */
/* from the repair rate */
/*
* Get the Mean Time Between Repair (the time that a failed disk is replaced)
* from the repair rate
*/
MTTR = 1.0 / replace_rate;
/* use the approximated MTTDL equation */
@ -697,8 +705,10 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
if (flag & (SMARTCTL_FLAG_FAIL | SMARTCTL_FLAG_PREFAIL))
make_it_fail = 1;
/* note that in older smartmontools, like 5.x, rotation rate is not present */
/* and then it could remain unassigned */
/*
* Note that in older smartmontools, like 5.x, rotation rate is not present
* and then it could remain unassigned
*/
if (flag & (SMARTCTL_FLAG_UNSUPPORTED | SMARTCTL_FLAG_OPEN)) {
/* if error running smartctl, skip AFR estimation */

View file

@ -60,8 +60,10 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task
ret = handle_close(handle);
if (ret == -1) {
/* LCOV_EXCL_START */
/* This one is really an unexpected error, because we are only reading */
/* and closing a descriptor should never fail */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %u\n", blockcur);
@ -437,8 +439,10 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
blockmax = blockstart + blockcount;
}
/* open the file for reading */
/* it may fail if the file doesn't exist, in this case we continue to dry the files */
/*
* Open the file for reading
* it may fail if the file doesn't exist, in this case we continue to dry the files
*/
for (l = 0; l < state->level; ++l) {
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {

View file

@ -274,8 +274,10 @@ static int filter_element(tommy_list* filterlist, struct snapraid_filter** reaso
}
}
/* directories are always included by default, otherwise we cannot apply rules */
/* to the contained files */
/*
* Directories are always included by default, otherwise we cannot apply rules
* to the contained files
*/
if (is_def_include)
return 0;
@ -897,8 +899,10 @@ int fs_is_empty(struct snapraid_disk* disk, block_off_t blockmax)
{
struct extent_disk_empty arg = { blockmax };
/* if there is an element, it's not empty */
/* even if links and dirs have no block allocation */
/*
* 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))

View file

@ -33,9 +33,11 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file, in
/* initial values, changed later if required */
handle->created = 0;
/* flags for opening */
/* O_BINARY: open as binary file (Windows only) */
/* O_NOFOLLOW: do not follow links to ensure to open the real file */
/*
* Flags for opening
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
/* open for read write */
@ -144,9 +146,11 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int
/* for sure not created */
handle->created = 0;
/* flags for opening */
/* O_BINARY: open as binary file (Windows only) */
/* O_NOFOLLOW: do not follow links to ensure to open the real file */
/*
* Flags for opening
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
/* open for read */

View file

@ -248,11 +248,13 @@ static void import_dir(struct snapraid_state* state, const char* dir)
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/* if the st_mode field is missing, takes care to fill it using normal lstat() */
/* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined), */
/* because we use a directory reading method that doesn't read info about ReparsePoint. */
/* Note that here we cannot call here lstat_sync(), because we don't know what kind */
/* of file is it, and lstat_sync() doesn't always work */
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined),
* because we use a directory reading method that doesn't read info about ReparsePoint.
* Note that here we cannot call here lstat_sync(), because we don't know what kind
* of file is it, and lstat_sync() doesn't always work
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */

View file

@ -287,8 +287,10 @@ static struct snapraid_task* io_reader_step(struct snapraid_worker* worker)
while (1) {
unsigned next_index;
/* check if the worker has to exit */
/* even if there is work to do */
/*
* Check if the worker has to exit
* even if there is work to do
*/
if (io->done) {
thread_mutex_unlock(&io->io_mutex);
return 0;
@ -378,8 +380,10 @@ static struct snapraid_task* io_writer_step(struct snapraid_worker* worker, int
return task;
}
/* check if the worker has to exit */
/* but only if there is no work to do */
/*
* Check if the worker has to exit
* but only if there is no work to do
*/
if (io->done) {
thread_mutex_unlock(&io->io_mutex);
return 0;
@ -503,8 +507,10 @@ static void io_refresh_thread(struct snapraid_io* io)
worker->handle->disk->cached_blocks = cached;
}
/* for all writers, count the number of written blocks */
/* note that this is a kind of "opposite" of cached blocks */
/*
* For all writers, count the number of written blocks
* note that this is a kind of "opposite" of cached blocks
*/
for (i = 0; i < io->writer_max; ++i) {
unsigned begin, end, cached;
struct snapraid_worker* worker = &io->writer_map[i];
@ -573,9 +579,11 @@ static struct snapraid_task* io_task_read_thread(struct snapraid_io* io, unsigne
unsigned* let;
unsigned busy_index;
/* get the index the IO is using */
/* we must ensure that this index has not a read in progress */
/* to avoid a concurrent access */
/*
* Get the index the IO is using
* we must ensure that this index has not a read in progress
* to avoid a concurrent access
*/
busy_index = io->reader_index;
/* search for a worker that has already finished */
@ -605,8 +613,10 @@ static struct snapraid_task* io_task_read_thread(struct snapraid_io* io, unsigne
task = &worker->task_map[io->reader_index];
/* mark the worker as processed */
/* setting the previous one to point at the next one */
/*
* Mark the worker as processed
* setting the previous one to point at the next one
*/
*let = io->reader_list[i + 1];
thread_mutex_unlock(&io->io_mutex);
@ -661,11 +671,13 @@ static void io_parity_write_thread(struct snapraid_io* io, unsigned* pos, unsign
unsigned* let;
unsigned busy_index;
/* get the next index the IO is going to use */
/* we must ensure that this index has not a write in progress */
/* to avoid a concurrent access */
/* note that we are already sure that a write is not in progress */
/* at the index the IO is using at now */
/*
* Get the next index the IO is going to use
* we must ensure that this index has not a write in progress
* to avoid a concurrent access
* note that we are already sure that a write is not in progress
* at the index the IO is using at now
*/
busy_index = (io->writer_index + 1) % io->io_max;
/* search for a worker that has already finished */
@ -691,8 +703,10 @@ static void io_parity_write_thread(struct snapraid_io* io, unsigned* pos, unsign
/* if the worker has finished this index */
if (busy_index != worker->index) {
/* mark the worker as processed */
/* setting the previous one to point at the next one */
/*
* Mark the worker as processed
* setting the previous one to point at the next one
*/
*let = io->writer_list[i + 1];
thread_mutex_unlock(&io->io_mutex);
@ -822,8 +836,10 @@ static void io_start_thread(struct snapraid_io* io,
for (i = 0; i < IO_WRITER_ERROR_MAX; ++i)
io->writer_error[i] = 0;
/* setup the initial read pending tasks, except the latest one, */
/* the latest will be initialized at the fist io_read_next() call */
/*
* Setup the initial read pending tasks, except the latest one,
* the latest will be initialized at the fist io_read_next() call
*/
for (i = 0; i < io->io_max - 1; ++i) {
block_off_t blockcur = io_position_next(io);
@ -920,8 +936,10 @@ void io_init(struct snapraid_io* io, struct snapraid_state* state,
#if HAVE_THREAD
if (io_cache == 0) {
/* default is 16 MiB of cache */
/* this seems to be a good tradeoff between speed and memory usage */
/*
* Default is 16 MiB of cache
* this seems to be a good tradeoff between speed and memory usage
*/
io->io_max = 16 * 1024 * 1024 / state->block_size;
if (io->io_max < IO_MIN)
io->io_max = IO_MIN;

View file

@ -227,10 +227,12 @@ void state_locate_mark_tail_blocks_for_resync(struct snapraid_state* state, uint
struct snapraid_file* file = entry->file;
struct snapraid_disk* disk = entry->disk;
/* reallocate the full file, not only the part of in the free zone */
/* this is required because the files blocks have to be in order in */
/* in the parity file. */
/* not reallocating the file head will prevent the reallocation of the file tail */
/*
* Reallocate the full file, not only the part of in the free zone
* this is required because the files blocks have to be in order in
* in the parity file.
* not reallocating the file head will prevent the reallocation of the file tail
*/
for (block_off_t f = 0; f < file->blockmax; ++f) {
block_off_t parity_pos = fs_file2par_find(disk, file, f);

View file

@ -161,8 +161,10 @@ void os_init(int opt)
/* get pointer to RtlGenRandom, note that it was reported missing in some cases */
ptr_RtlGenRandom = (void*)GetProcAddress(dll_advapi32, "SystemFunction036");
/* set the thread execution level to avoid sleep */
/* first try for Windows 7 */
/*
* Set the thread execution level to avoid sleep
* first try for Windows 7
*/
if (SetThreadExecutionState(WIN32_ES_CONTINUOUS | WIN32_ES_SYSTEM_REQUIRED | WIN32_ES_AWAYMODE_REQUIRED) == 0) {
/* retry with the XP variant */
SetThreadExecutionState(WIN32_ES_CONTINUOUS | WIN32_ES_SYSTEM_REQUIRED);
@ -348,13 +350,17 @@ static wchar_t* convert_arg(wchar_t* conv_buf, const char* src, int only_if_requ
dst = conv_buf;
/* note that we always check for both / and \ because the path is blindly */
/* converted to unix format by path_import() */
/*
* Note that we always check for both / and \ because the path is blindly
* converted to unix format by path_import()
*/
if (only_if_required && strlen(src) < 260 - 12) {
/* it's a short path */
/* 260 is the MAX_PATH, note that it includes the space for the terminating NUL */
/* 12 is an additional space for filename, required when creating directory */
/*
* It's a short path
* 260 is the MAX_PATH, note that it includes the space for the terminating NUL
* 12 is an additional space for filename, required when creating directory
*/
/* do nothing */
} else if (is_slash(src[0]) && is_slash(src[1]) && (src[2] == '?' || src[2] == '.') && is_slash(src[3])) {
@ -400,10 +406,12 @@ static wchar_t* convert_arg(wchar_t* conv_buf, const char* src, int only_if_requ
os_abort();
}
/* convert any / to \ */
/* note that in UTF-16, it's not possible to have '/' used as part */
/* of a pair of codes representing a single UNICODE char */
/* See: http://en.wikipedia.org/wiki/UTF-16 */
/*
* Convert any / to \
* note that in UTF-16, it's not possible to have '/' used as part
* of a pair of codes representing a single UNICODE char
* See: http://en.wikipedia.org/wiki/UTF-16
*/
while (*dst) {
if (*dst == L'/')
*dst = L'\\';
@ -571,9 +579,11 @@ static int windows_stream2stat(const BY_HANDLE_FILE_INFORMATION* info, const FIL
{
int64_t mtime;
/* The FILE_ID_BOTH_DIR_INFO doesn't have the ReparseTag information */
/* we could use instead FILE_ID_EXTD_DIR_INFO, but it's available only */
/* from Windows Server 2012 */
/*
* The FILE_ID_BOTH_DIR_INFO doesn't have the ReparseTag information
* we could use instead FILE_ID_EXTD_DIR_INFO, but it's available only
* from Windows Server 2012
*/
windows_attr2stat(stream->FileAttributes, 0, st);
st->st_size = stream->EndOfFile.QuadPart;
@ -694,9 +704,11 @@ static void windows_errno(DWORD error)
{
switch (error) {
case ERROR_INVALID_HANDLE :
/* we check for a bad handle calling _get_osfhandle() */
/* and in such case we return EBADF */
/* Other cases are here identified with EINVAL */
/*
* We check for a bad handle calling _get_osfhandle()
* and in such case we return EBADF
* Other cases are here identified with EINVAL
*/
errno = EINVAL;
break;
case ERROR_HANDLE_EOF : /* in ReadFile() over the end of the file */
@ -866,13 +878,17 @@ static BOOL GetFilePhysicalOffset(HANDLE h, uint64_t* physical)
if (!ret) {
DWORD error = GetLastError();
if (error == ERROR_MORE_DATA) {
/* we ignore ERROR_MODE_DATA because we are interested only at the first entry */
/* and this is the expected error if the files has more entries */
/*
* We ignore ERROR_MODE_DATA because we are interested only at the first entry
* and this is the expected error if the files has more entries
*/
} else if (error == ERROR_HANDLE_EOF) {
/* if the file is small, it can be stored in the Master File Table (MFT) */
/* and then it doesn't have a physical address */
/* In such case we report a specific fake address, to report this special condition */
/* that it's different from the 0 offset reported by the underline file system */
/*
* If the file is small, it can be stored in the Master File Table (MFT)
* and then it doesn't have a physical address
* In such case we report a specific fake address, to report this special condition
* that it's different from the 0 offset reported by the underline file system
*/
*physical = FILEPHY_WITHOUT_OFFSET;
return TRUE;
} else if (error == ERROR_NOT_SUPPORTED) {
@ -1649,8 +1665,10 @@ static windows_dir* windows_opendir_stream(const char* dir)
return 0;
}
/* get dir information for the VolumeSerialNumber */
/* this value is used for all the files in the dir */
/*
* Get dir information for the VolumeSerialNumber
* this value is used for all the files in the dir
*/
if (!GetFileInformationByHandle(dirstream->h, &dirstream->info)) {
DWORD error = GetLastError();
CloseHandle(dirstream->h);
@ -1789,10 +1807,12 @@ int windows_symlink(const char* existing, const char* file)
wchar_t conv_buf_file[CONV_MAX];
wchar_t conv_buf_existing[CONV_MAX];
/* We must convert to the extended-length \\?\ format if the path is too long */
/* otherwise the link creation fails. */
/* But we don't want to always convert it, to avoid to recreate */
/* user symlinks different than they were before */
/*
* We must convert to the extended-length \\?\ format if the path is too long
* otherwise the link creation fails.
* But we don't want to always convert it, to avoid to recreate
* user symlinks different than they were before
*/
if (!CreateSymbolicLinkW(convert(conv_buf_file, file), convert_if_required(conv_buf_existing, existing),
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
) {
@ -1971,8 +1991,10 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
return -1;
}
/* if it doesn't exist, we assume a file */
/* and we check for the containing dir */
/*
* If it doesn't exist, we assume a file
* and we check for the containing dir
*/
attr = 0;
}
@ -1994,8 +2016,10 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
slash[1] = 0;
}
/* get the free space of the directory */
/* note that it must be a directory */
/*
* Get the free space of the directory
* note that it must be a directory
*/
if (!GetDiskFreeSpaceExW(convert(conv_buf, dir), 0, &total_bytes, &total_free_bytes)) {
windows_errno(GetLastError());
return -1;
@ -2383,8 +2407,10 @@ static int devresolve(const char* mount, char* file, size_t file_size, char* wfi
return -1;
}
/* remove the final slash, otherwise CreateFile() opens the file-system */
/* and not the volume */
/*
* Remove the final slash, otherwise CreateFile() opens the file-system
* and not the volume
*/
i = 0;
while (volume_guid[i] != 0)
++i;

View file

@ -148,12 +148,14 @@ void cmd_generate_file(const char* path, int size)
data = malloc(size);
/* We don't write zero bytes because we want to test */
/* the recovering of new files, after an aborted sync */
/* If the files contains full blocks at zero */
/* this is an impossible condition to recover */
/* because we cannot differentiate between an unused block */
/* and a file filled with 0 */
/*
* We don't write zero bytes because we want to test
* the recovering of new files, after an aborted sync
* If the files contains full blocks at zero
* this is an impossible condition to recover
* because we cannot differentiate between an unused block
* and a file filled with 0
*/
rndnz_range(data, size);
f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600);
@ -351,8 +353,10 @@ void cmd_damage(const char* path, int size)
{
struct stat st;
/* here a 0 size means to change nothing */
/* as also the timestamp should not be changed */
/*
* Here a 0 size means to change nothing
* as also the timestamp should not be changed
*/
if (!size)
return;

View file

@ -31,9 +31,11 @@ block_off_t parity_allocated_size(struct snapraid_state* state)
/* start from the declared size */
block_off_t block = fs_size(disk);
/* decrease the block until an allocated one, but part of a file */
/* we don't stop at deleted blocks, because we want to have them cleared */
/* if they are at the end of the parity */
/*
* Decrease the block until an allocated one, but part of a file
* we don't stop at deleted blocks, because we want to have them cleared
* if they are at the end of the parity
*/
while (block > parity_block && !block_has_file(fs_par2block_find(disk, block - 1)))
--block;
@ -384,8 +386,10 @@ static int parity_handle_fill(struct snapraid_split_handle* split, data_off_t si
/* present size */
base = split->st.st_size;
/* truncate it to block size multiplier */
/* in case of damage the size may get wrong */
/*
* Truncate it to block size multiplier
* in case of damage the size may get wrong
*/
base &= ~block_mask;
/* size we have to increase */
@ -432,8 +436,10 @@ static int parity_handle_fill(struct snapraid_split_handle* split, data_off_t si
}
#endif
/* shrink to the expected size to ensure to throw away any extra */
/* data allocated when the grow operation fails */
/*
* Shrink to the expected size to ensure to throw away any extra
* data allocated when the grow operation fails
*/
return parity_handle_shrink(split, base);
}
@ -528,8 +534,10 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity*
data_off_t run;
if (is_fixed) {
/* if the required size is smaller, we have to reduce also the file */
/* ignoring the previous size */
/*
* If the required size is smaller, we have to reduce also the file
* ignoring the previous size
*/
if (size <= split->size) {
/* mark it as not fixed anymore for the later check */
is_fixed = 0;
@ -637,8 +645,10 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par
split->size = parity->split_map[s].size;
split->limit_size = PARITY_LIMIT(limit_size, s, level);
/* open for read */
/* O_NOATIME: do not change access time */
/*
* Open for read
* O_NOATIME: do not change access time
*/
flags = O_RDONLY | O_BINARY | advise_flags(&split->advise);
split->f = open_noatime(split->path, flags);
@ -712,9 +722,11 @@ int parity_sync(struct snapraid_parity_handle* handle)
struct snapraid_split_handle* split = &handle->split_map[s];
int ret;
/* Ensure that data changes are written to disk. */
/* This is required to ensure that parity is more updated than content */
/* in case of a system crash. */
/*
* Ensure that data changes are written to disk.
* This is required to ensure that parity is more updated than content
* in case of a system crash.
*/
ret = fsync(split->f);
if (ret != 0) {
/* LCOV_EXCL_START */
@ -766,9 +778,11 @@ int parity_close(struct snapraid_parity_handle* handle)
ret = close(split->f);
if (ret != 0) {
/* LCOV_EXCL_START */
/* This is a serious error, as it may be the result of a failed write */
/* identified at later time. */
/* In a normal file-system (not NFS) it should never happen */
/*
* This is a serious error, as it may be the result of a failed write
* identified at later time.
* In a normal file-system (not NFS) it should never happen
*/
log_fatal(errno, "Error closing parity file '%s'. %s.\n", split->path, strerror(errno));
f_ret = -1;
/* LCOV_EXCL_STOP */

View file

@ -95,8 +95,10 @@ static int clean_dir(const char* dir)
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/* if the st_mode field is missing, takes care to fill it using normal lstat() */
/* at now this can happen only in Windows */
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
@ -126,9 +128,11 @@ static int clean_dir(const char* dir)
if (ret < 0) {
#ifdef _WIN32
if (errno == EACCES) {
/* in Windows just ignore EACCES errors removing directories */
/* because it could happen that the directory is in use */
/* and it cannot be removed */
/*
* In Windows just ignore EACCES errors removing directories
* because it could happen that the directory is in use
* and it cannot be removed
*/
log_fatal(errno, "Directory '%s' not removed because it's in use.\n", path_next);
full = 1;
} else
@ -207,8 +211,10 @@ static void read_dir(tommy_hashdyn* poolset, const char* base_dir, const char* s
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/* if the st_mode field is missing, takes care to fill it using normal lstat() */
/* at now this can happen only in Windows */
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */

View file

@ -264,8 +264,10 @@ static void scan_file_allocate(struct snapraid_scan* scan, struct snapraid_file*
/* if the block is an empty one */
if (over_state == BLOCK_STATE_EMPTY) {
/* the block was empty and filled with zeros */
/* set the hash to the special ZERO value */
/*
* The block was empty and filled with zeros
* set the hash to the special ZERO value
*/
hash_zero_set(block->hash);
} else {
/* otherwise it's a DELETED one */
@ -325,10 +327,12 @@ static void scan_file_deallocate(struct snapraid_scan* scan, struct snapraid_fil
/* state changed */
scan->need_write = 1;
/* here we are supposed to adjust the ::first_free_block position */
/* with the parity position we are deleting */
/* but we also know that we do only delayed insert, after all the deletion, */
/* so at this point ::first_free_block is always at 0, and we don't need to update it */
/*
* Here we are supposed to adjust the ::first_free_block position
* with the parity position we are deleting
* but we also know that we do only delayed insert, after all the deletion,
* so at this point ::first_free_block is always at 0, and we don't need to update it
*/
if (disk->first_free_block != 0) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency for first free position at '%u' deallocating file '%s'\n", disk->first_free_block, file->sub);
@ -341,8 +345,10 @@ static void scan_file_deallocate(struct snapraid_scan* scan, struct snapraid_fil
struct snapraid_block* block = fs_file2block_get(file, i);
unsigned block_state;
/* in case we scan after an aborted sync, */
/* we could get also intermediate states */
/*
* In case we scan after an aborted sync,
* we could get also intermediate states
*/
block_state = block_state_get(block);
switch (block_state) {
case BLOCK_STATE_BLK :
@ -603,9 +609,11 @@ static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struc
log_fatal(ESOFT, "DANGER! Detected uncached inode change from %" PRIu64 " to %" PRIu64 " for file '%s'\n",
(uint64_t)st->st_ino, (uint64_t)synced_st.st_ino, sub);
log_fatal(ESOFT, "It's better if you run SnapRAID without other processes running.\n");
/* at this point, it's too late to change inode */
/* and having inconsistent inodes may result to internal failures */
/* so, it's better to abort */
/*
* At this point, it's too late to change inode
* and having inconsistent inodes may result to internal failures
* so, it's better to abort
*/
exit(EXIT_FAILURE);
}
}
@ -729,8 +737,10 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
*/
int has_past_inodes = !disk->has_volatile_inodes && !disk->has_different_uuid && !disk->has_unsupported_uuid;
/* always search with the new inode, in the all new inodes found until now, */
/* with the eventual presence of also the past inodes */
/*
* Always search with the new inode, in the all new inodes found until now,
* with the eventual presence of also the past inodes
*/
uint64_t inode = st->st_ino;
file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
@ -741,9 +751,11 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
if (file->size == st->st_size
&& file->mtime_sec == st->st_mtime
&& (file->mtime_nsec == STAT_NSEC(st)
/* always accept the stored value if it's STAT_NSEC_INVALID */
/* it happens when upgrading from an old version of SnapRAID */
/* not yet supporting the nanosecond field */
/*
* Always accept the stored value if it's STAT_NSEC_INVALID
* it happens when upgrading from an old version of SnapRAID
* not yet supporting the nanosecond field
*/
|| file->mtime_nsec == STAT_NSEC_INVALID
)
) {
@ -765,8 +777,10 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
/* mark as present */
file_flag_set(file, FILE_IS_PRESENT);
/* update the nanoseconds mtime only if different */
/* to avoid unneeded updates */
/*
* Update the nanoseconds mtime only if different
* to avoid unneeded updates
*/
if (file->mtime_nsec == STAT_NSEC_INVALID
&& STAT_NSEC(st) != file->mtime_nsec
) {
@ -858,18 +872,22 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
/* LCOV_EXCL_STOP */
}
/* assume a previously used inode, it's the worst case */
/* and we handle it removing the duplicate stored inode. */
/* If the file is found by name later, it will have the inode restored, */
/* otherwise, it will get removed */
/*
* Assume a previously used inode, it's the worst case
* and we handle it removing the duplicate stored inode.
* If the file is found by name later, it will have the inode restored,
* otherwise, it will get removed
*/
/* remove from the inode set */
tommy_hashdyn_remove_existing(&disk->inodeset, &file->nodeset);
/* clear the inode */
/* this is not really needed for correct functionality */
/* because we are going to set FILE_IS_WITHOUT_INODE */
/* but it's easier for debugging to have invalid inodes set to 0 */
/*
* Clear the inode
* this is not really needed for correct functionality
* because we are going to set FILE_IS_WITHOUT_INODE
* but it's easier for debugging to have invalid inodes set to 0
*/
file->inode = 0;
/* mark as missing inode */
@ -921,17 +939,21 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
if (file->size == st->st_size
&& file->mtime_sec == st->st_mtime
&& (file->mtime_nsec == STAT_NSEC(st)
/* always accept the stored value if it's STAT_NSEC_INVALID */
/* it happens when upgrading from an old version of SnapRAID */
/* not yet supporting the nanosecond field */
/*
* Always accept the stored value if it's STAT_NSEC_INVALID
* it happens when upgrading from an old version of SnapRAID
* not yet supporting the nanosecond field
*/
|| file->mtime_nsec == STAT_NSEC_INVALID
)
) {
/* mark as present */
file_flag_set(file, FILE_IS_PRESENT);
/* update the nano seconds mtime only if different */
/* to avoid unneeded updates */
/*
* Update the nano seconds mtime only if different
* to avoid unneeded updates
*/
if (file->mtime_nsec == STAT_NSEC_INVALID
&& STAT_NSEC(st) != STAT_NSEC_INVALID
) {
@ -943,11 +965,13 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
/* if when processing the disk we used the past inodes values */
if (has_past_inodes) {
/* if persistent inodes are supported, we are sure that the inode number */
/* is now different, because otherwise the file would have been found */
/* when searching by inode. */
/* if the inode is different, it means a rewritten file with the same path */
/* like when restoring a backup that restores also the timestamp */
/*
* If persistent inodes are supported, we are sure that the inode number
* is now different, because otherwise the file would have been found
* when searching by inode.
* if the inode is different, it means a rewritten file with the same path
* like when restoring a backup that restores also the timestamp
*/
++scan->count_restore;
log_tag("scan:restore:%s:%s\n", disk->name, esc_tag(sub));
@ -967,9 +991,11 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
/* we have to save the new inode */
scan->need_write = 1;
} else {
/* otherwise it's the case of not persistent inode, where doesn't */
/* matter if the inode is different or equal, because they have no */
/* meaning, and then we don't even save them */
/*
* Otherwise it's the case of not persistent inode, where doesn't
* matter if the inode is different or equal, because they have no
* meaning, and then we don't even save them
*/
++scan->count_equal;
if (state->opt.gui_verbose) {
@ -1004,15 +1030,19 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
file_already_present_mtime_nsec = 0;
}
/* refresh the info, to ensure that they are synced, */
/* note that we refresh only the info of the new or modified files */
/* because this is slow operation */
/*
* Refresh the info, to ensure that they are synced,
* note that we refresh only the info of the new or modified files
* because this is slow operation
*/
scan_file_refresh(scan, sub, st, &physical);
#ifndef _WIN32
/* do a safety check to ensure that the common ext4 case of zeroing */
/* the size of a file after a crash doesn't propagate to the backup */
/* this check is specific for Linux, so we disable it on Windows */
/*
* Do a safety check to ensure that the common ext4 case of zeroing
* the size of a file after a crash doesn't propagate to the backup
* this check is specific for Linux, so we disable it on Windows
*/
if (is_original_file_size_different_than_zero && st->st_size == 0) {
if (!state->opt.force_zero) {
/* LCOV_EXCL_START */
@ -1037,11 +1067,13 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
/* mark it as present */
file_flag_set(file, FILE_IS_PRESENT);
/* if copy detection is enabled */
/* note that the copy detection is tried also for updated files */
/* this makes sense because it may happen to have two different copies */
/* of the same file, and we move the right one over the wrong one */
/* in such case we have a "copy" over an "update" */
/*
* If copy detection is enabled
* note that the copy detection is tried also for updated files
* this makes sense because it may happen to have two different copies
* of the same file, and we move the right one over the wrong one
* in such case we have a "copy" over an "update"
*/
if (!state->opt.force_nocopy) {
tommy_uint32_t hash = file_stamp_hash(file->size, file->mtime_sec, file->mtime_nsec);
@ -1053,8 +1085,10 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
char sub_other[PATH_MAX];
stamp_lock(other_disk);
/* if the nanosecond part of the time stamp is valid, search */
/* for name and stamp, otherwise for path and stamp */
/*
* If the nanosecond part of the time stamp is valid, search
* for name and stamp, otherwise for path and stamp
*/
if (file->mtime_nsec != 0 && file->mtime_nsec != STAT_NSEC_INVALID)
other_file = tommy_hashdyn_search(&other_disk->stampset, file_namestamp_compare, file, hash);
else
@ -1105,8 +1139,10 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub,
}
}
/* if not yet reported, do it now */
/* we postpone this to avoid to print two times the copied files */
/*
* If not yet reported, do it now
* we postpone this to avoid to print two times the copied files
*/
if (!is_file_reported) {
if (is_file_already_present) {
++scan->count_change;
@ -1396,15 +1432,19 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
}
if (state->opt.force_order == SORT_ALPHA) {
/* if requested sort alphabetically */
/* this is mainly done for testing to ensure to always */
/* process in the same way in different platforms */
/*
* If requested sort alphabetically
* this is mainly done for testing to ensure to always
* process in the same way in different platforms
*/
tommy_list_sort(&list, dd_name_compare);
}
#if HAVE_STRUCT_DIRENT_D_INO
else if (!disk->has_volatile_inodes) {
/* if inodes are persistent */
/* sort the list of dir entries by inodes */
/*
* If inodes are persistent
* sort the list of dir entries by inodes
*/
tommy_list_sort(&list, dd_ino_compare);
}
/* otherwise just keep the insertion order */
@ -1446,11 +1486,13 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
st = DSTAT(path_next, dd, &st_buf);
#if HAVE_STRUCT_DIRENT_D_STAT
/* if the st_mode field is missing, takes care to fill it using normal lstat() */
/* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined), */
/* because we use a directory reading method that doesn't read info about ReparsePoint. */
/* Note that here we cannot call here lstat_sync(), because we don't know what kind */
/* of file is it, and lstat_sync() doesn't always work */
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined),
* because we use a directory reading method that doesn't read info about ReparsePoint.
* Note that here we cannot call here lstat_sync(), because we don't know what kind
* of file is it, and lstat_sync() doesn't always work
*/
if (st->st_mode == 0) {
if (lstat(path_next, st) != 0) {
/* LCOV_EXCL_START */
@ -1481,8 +1523,10 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
st = DSTAT(path_next, dd, &st_buf);
#if HAVE_LSTAT_SYNC
/* if the st_ino field is missing, takes care to fill it using the extended lstat() */
/* this can happen only in Windows */
/*
* If the st_ino field is missing, takes care to fill it using the extended lstat()
* this can happen only in Windows
*/
if (st->st_ino == 0 || st->st_nlink == 0) {
if (lstat_sync(path_next, st, 0) != 0) {
/* LCOV_EXCL_START */
@ -1632,10 +1676,12 @@ static void* scan_disk(void* arg)
/* if inodes or UUID are not persistent/changed/unsupported */
if (disk->has_volatile_inodes || disk->has_different_uuid || disk->has_unsupported_uuid) {
/* remove all the inodes from the inode collection */
/* if they are not persistent, all of them could be changed now */
/* and we don't want to find false matching ones */
/* see scan_file() for more details */
/*
* Remove all the inodes from the inode collection
* if they are not persistent, all of them could be changed now
* and we don't want to find false matching ones
* See scan_file() for more details
*/
tommy_node* node = disk->filelist;
while (node) {
struct snapraid_file* file = node->data;
@ -1716,9 +1762,11 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
}
#endif
/* we split the search in two phases because to detect files */
/* moved from one disk to another we have to start deletion */
/* only when all disks have all the new files found */
/*
* We split the search in two phases because to detect files
* moved from one disk to another we have to start deletion
* only when all disks have all the new files found
*/
/* now process all the new and deleted files */
for (i = scanlist; i != 0; i = i->next) {
@ -1788,9 +1836,11 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
}
}
/* sort the files before inserting them */
/* we use a stable sort to ensure that if the reported physical offset/inode */
/* are always 0, we keep at least the directory order */
/*
* Sort the files before inserting them
* we use a stable sort to ensure that if the reported physical offset/inode
* are always 0, we keep at least the directory order
*/
switch (state->opt.force_order) {
case SORT_PHYSICAL :
tommy_list_sort(&scan->file_insert_list, file_physical_compare);
@ -1806,9 +1856,11 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
break;
}
/* insert all the new files, we insert them only after the deletion */
/* to reuse the just freed space */
/* also check if the physical offset reported are fakes or not */
/*
* Insert all the new files, we insert them only after the deletion
* to reuse the just freed space
* also check if the physical offset reported are fakes or not
*/
node = scan->file_insert_list;
phy_dup = 0;
phy_last = FILEPHY_UNREAD_OFFSET;
@ -1822,8 +1874,10 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
/* files without offset are expected to have duplicates */
&& phy_last != FILEPHY_WITHOUT_OFFSET
) {
/* if verbose, print the list of duplicates real offsets */
/* other cases are for offsets not supported, so we don't need to report them file by file */
/*
* If verbose, print the list of duplicates real offsets
* other cases are for offsets not supported, so we don't need to report them file by file
*/
if (phy_last >= FILEPHY_REAL_OFFSET) {
log_error(ESOFT, "WARNING! Files '%s%s' and '%s%s' share the same physical offset %" PRId64 ".\n", disk->mount_point, phy_file_last->sub, disk->mount_point, file->sub, phy_last);
}
@ -1840,8 +1894,10 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
scan_file_allocate(scan, file);
}
/* mark the disk without reliable physical offset if it has duplicates */
/* here it should never happen because we already sorted out hardlinks */
/*
* Mark the disk without reliable physical offset if it has duplicates
* here it should never happen because we already sorted out hardlinks
*/
if (state->opt.force_order == SORT_PHYSICAL && phy_dup > 0) {
disk->has_unreliable_physical = 1;
}
@ -1969,10 +2025,12 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
/* don't print the message if the UUID changed because before */
/* it was no set. */
/* this is the normal condition for an empty disk because it */
/* isn't stored */
/*
* Don't print the message if the UUID changed because before
* it was no set.
* This is the normal condition for an empty disk because it
* isn't stored
*/
if (disk->has_different_uuid && !disk->had_empty_uuid) {
if (!done) {
done = 1;

View file

@ -79,8 +79,10 @@ static int block_is_enabled(struct snapraid_plan* plan, block_off_t* countlast,
return 0;
}
/* if the time is less than the limit, always include */
/* otherwise, check if we reached the last limit count */
/*
* If the time is less than the limit, always include
* otherwise, check if we reached the last limit count
*/
if (blocktime == plan->timelimit) {
/* if we reached the count limit */
if (*countlast >= plan->lastlimit) {
@ -132,8 +134,10 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta
ret = handle_close(handle);
if (ret == -1) {
/* LCOV_EXCL_START */
/* This one is really an unexpected error, because we are only reading */
/* and closing a descriptor should never fail */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %u\n", blockcur);
@ -175,9 +179,11 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta
/* follow */
}
/* note that we intentionally don't abort if the file has different attributes */
/* from the last sync, as we are expected to return errors if running */
/* in an unsynced array. This is just like the check command. */
/*
* Note that we intentionally don't abort if the file has different attributes
* from the last sync, as we are expected to return errors if running
* in an unsynced array. This is just like the check command.
*/
task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, 0);
if (task->read_size == -1) {
@ -288,9 +294,11 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
++countmax;
}
/* compute the autosave size for all disk, even if not read */
/* this makes sense because the speed should be almost the same */
/* if the disks are read in parallel */
/*
* Compute the autosave size for all disk, even if not read
* this makes sense because the speed should be almost the same
* if the disks are read in parallel
*/
autosavelimit = state->autosave / (diskmax * state->block_size);
autosavemissing = countmax; /* blocks to do */
autosavedone = 0; /* blocks done */
@ -340,8 +348,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
silent_error_on_this_block = 0;
io_error_on_this_block = 0;
/* if all the blocks at this address are synced */
/* if not, parity is not even checked */
/*
* If all the blocks at this address are synced
* if not, parity is not even checked
*/
block_is_unsynced = 0;
/* get block specific info */
@ -362,8 +372,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
block_off_t file_pos;
unsigned diskcur;
/* if the file on this disk is synced */
/* if not, silent errors are assumed as expected error */
/*
* If the file on this disk is synced
* if not, silent errors are assumed as expected error
*/
file_is_unsynced = 0;
/* until now is misc */
@ -586,8 +598,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
/* set the error status keeping other info */
info_set(&state->infoarr, blockcur, info_set_bad(info));
} else if (error_on_this_block) {
/* do nothing, as this is a generic error */
/* likely caused by a not synced array */
/*
* Do nothing, as this is a generic error
* likely caused by a not synced array
*/
} else {
/* if rehash is needed */
if (rehash) {
@ -598,8 +612,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
}
}
/* update the time info of the block */
/* and clear any other flag */
/*
* Update the time info of the block
* and clear any other flag
*/
info_set(&state->infoarr, blockcur, info_make(now, 0, 0, 0));
}

View file

@ -192,11 +192,13 @@ static void search_dir(struct snapraid_state* state, struct snapraid_disk* disk,
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/* if the st_mode field is missing, takes care to fill it using normal lstat() */
/* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined), */
/* because we use a directory reading method that doesn't read info about ReparsePoint. */
/* Note that here we cannot call here lstat_sync(), because we don't know what kind */
/* of file is it, and lstat_sync() doesn't always work */
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined),
* because we use a directory reading method that doesn't read info about ReparsePoint.
* Note that here we cannot call here lstat_sync(), because we don't know what kind
* of file is it, and lstat_sync() doesn't always work
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */

View file

@ -1036,15 +1036,19 @@ int snapraid_main(int argc, char* argv[])
opt.expected_missing = 1;
break;
case 'e' :
/* when processing only error, we filter files */
/* and we apply fixes only to synced ones */
/*
* When processing only error, we filter files
* and we apply fixes only to synced ones
*/
filter_error = 1;
opt.badfileonly = 1;
opt.syncedonly = 1;
break;
case 'b' :
/* when processing only block with error, we filter both files and blocks */
/* and we apply fixes only to synced ones */
/*
* When processing only block with error, we filter both files and blocks
* and we apply fixes only to synced ones
*/
filter_error = 1;
opt.badfileonly = 1;
opt.badblockonly = 1;
@ -1635,8 +1639,10 @@ int snapraid_main(int argc, char* argv[])
}
}
/* errors must be always fixed on all disks */
/* because we don't keep the information on what disk is the error */
/*
* Errors must be always fixed on all disks
* because we don't keep the information on what disk is the error
*/
if (filter_error != 0 && !tommy_list_empty(&filterlist_disk)) {
/* LCOV_EXCL_START */
log_fatal(EUSER, "You cannot use -e, --filter-error and -d, --filter-disk simultaneously\n");
@ -1798,8 +1804,10 @@ int snapraid_main(int argc, char* argv[])
} else if (operation == OPERATION_SYNC) {
state_read(&state);
/* mark the files that have to be reallocated */
/* it will happen in inside scan_file_keep() called in state_scan() */
/*
* Mark the files that have to be reallocated
* it will happen in inside scan_file_keep() called in state_scan()
*/
if (state.opt.force_realloc)
state_locate_mark_tail_blocks_for_resync(&state, opt.parity_tail);
@ -1853,13 +1861,15 @@ int snapraid_main(int argc, char* argv[])
}
#endif
/* waits some time to ensure that any concurrent modification done at the files, */
/* using the same mtime read by the scan process, will be read by sync. */
/* Note that any later modification done, potentially not read by sync, will have */
/* a different mtime, and it will be synchronized at the next sync. */
/* The worst case is the FAT file-system with a two seconds resolution for mtime. */
/* If you don't use FAT, the wait is not needed, because most file-systems have now */
/* at least microseconds resolution, but better to be safe. */
/*
* Waits some time to ensure that any concurrent modification done at the files,
* using the same mtime read by the scan process, will be read by sync.
* Note that any later modification done, potentially not read by sync, will have
* a different mtime, and it will be synchronized at the next sync.
* The worst case is the FAT file-system with a two seconds resolution for mtime.
* If you don't use FAT, the wait is not needed, because most file-systems have now
* at least microseconds resolution, but better to be safe.
*/
if (!opt.skip_self)
sleep(2);

View file

@ -287,9 +287,11 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
struct snapraid_disk* other = j->data;
if (disk->device == other->device) {
if (state->opt.force_device) {
/* note that we just ignore the issue */
/* and we DON'T mark the disk to be skipped */
/* because we want to use these disks */
/*
* Note that we just ignore the issue
* and we DON'T mark the disk to be skipped
* because we want to use these disks
*/
if (!state->opt.no_warnings)
log_fatal(EUSER, "DANGER! Ignoring that disks '%s' and '%s' are on the same device\n", disk->name, other->name);
} else {
@ -317,9 +319,11 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
for (s = 0; s < state->parity[l].split_mac; ++s) {
if (disk->device == state->parity[l].split_map[s].device) {
if (state->opt.force_device) {
/* note that we just ignore the issue */
/* and we DON'T mark the disk to be skipped */
/* because we want to use these disks */
/*
* Note that we just ignore the issue
* and we DON'T mark the disk to be skipped
* because we want to use these disks
*/
if (!state->opt.no_warnings)
log_fatal(EUSER, "DANGER! Ignoring that disks '%s' and %s '%s' are on the same device\n", disk->mount_point, lev_name(l), state->parity[l].split_map[s].path);
} else {
@ -378,9 +382,11 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
for (t = 0; t < state->parity[j].split_mac; ++t) {
if (state->parity[l].split_map[s].device == state->parity[j].split_map[t].device) {
if (state->opt.force_device) {
/* note that we just ignore the issue */
/* and we DON'T mark the disk to be skipped */
/* because we want to use these disks */
/*
* Note that we just ignore the issue
* and we DON'T mark the disk to be skipped
* because we want to use these disks
*/
if (!state->opt.no_warnings)
log_fatal(EUSER, "DANGER! Skipping parities '%s' and '%s' on the same device\n", lev_config_name(l), lev_config_name(j));
} else {
@ -1544,9 +1550,11 @@ static struct snapraid_disk* find_disk_by_uuid(struct snapraid_state* state, con
tommy_node* i;
struct snapraid_disk* found = 0;
/* special test case to find the first matching UUID */
/* when testing UUID are all equal or not supported */
/* and we should handle this case specifically */
/*
* Special test case to find the first matching UUID
* when testing UUID are all equal or not supported
* and we should handle this case specifically
*/
if (state->opt.match_first_uuid)
return state->disklist->data;
@ -1580,10 +1588,12 @@ static void state_map(struct snapraid_state* state)
unsigned diskcount;
unsigned l, s;
/* remove all the mapping without a disk */
/* this happens when a disk is removed from the configuration file */
/* From SnapRAID 4.0 mappings are automatically removed if a disk is not used */
/* when saving the content file, but we keep this code to import older content files. */
/*
* Remove all the mapping without a disk
* this happens when a disk is removed from the configuration file
* From SnapRAID 4.0 mappings are automatically removed if a disk is not used
* when saving the content file, but we keep this code to import older content files.
*/
for (i = state->maplist; i != 0; ) {
struct snapraid_map* map = i->data;
struct snapraid_disk* disk;
@ -1600,8 +1610,10 @@ static void state_map(struct snapraid_state* state)
}
}
/* maps each unmapped disk present in the configuration file in the first available hole */
/* this happens when you add disks for the first time in the configuration file */
/*
* Maps each unmapped disk present in the configuration file in the first available hole
* this happens when you add disks for the first time in the configuration file
*/
hole = 0; /* first position to try */
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
@ -1684,8 +1696,10 @@ static void state_map(struct snapraid_state* state)
++uuid_mismatch;
log_error(ESOFT, "UUID change for disk '%s' from '%s' to '%s'\n", disk->name, map->uuid, disk->uuid);
} else {
/* no message here, because having a disk without */
/* UUID is the normal state of an empty disk */
/*
* No message here, because having a disk without
* UUID is the normal state of an empty disk
*/
disk->had_empty_uuid = 1;
}
@ -1894,8 +1908,10 @@ void state_refresh(struct snapraid_state* state)
}
/* note what we don't set need_write = 1, because we don't want */
/* to update the content file only for the free space info. */
/*
* Note what we don't set need_write = 1, because we don't want
* to update the content file only for the free space info.
*/
}
/**
@ -2349,9 +2365,11 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
hash_zero_set(block->hash);
}
/* if we are disabling the copy optimization */
/* we want also to clear any already previously stored information */
/* in other sync commands */
/*
* If we are disabling the copy optimization
* we want also to clear any already previously stored information
* in other sync commands
*/
if (state->opt.force_nocopy && block_state_get(block) == BLOCK_STATE_REP) {
/* set the hash value to INVALID */
hash_invalid_set(block->hash);
@ -2471,8 +2489,10 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
/* LCOV_EXCL_STOP */
}
} else {
/* extra info are accepted for backward compatibility */
/* they are discarded at the first write */
/*
* Extra info are accepted for backward compatibility
* they are discarded at the first write
*/
}
if (fs_is_block_unsynced(state, v_pos))
@ -2956,8 +2976,10 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
tommy_array_set(&disk_mapping, mapping_max, disk);
++mapping_max;
} else if (c == 'P') {
/* from SnapRAID 7.0 the 'P' command includes the free space */
/* from SnapRAID 11.0 the 'P' command is deprecated by 'Q' */
/*
* From SnapRAID 7.0 the 'P' command includes the free space
* from SnapRAID 11.0 the 'P' command is deprecated by 'Q'
*/
char v_uuid[UUID_MAX];
uint32_t v_level;
uint32_t v_total_blocks;
@ -3667,8 +3689,10 @@ static void* state_write_thread(void* arg)
++begin;
}
} else {
/* write the run of blocks without hash */
/* they can be either used or empty blocks */
/*
* Write the run of blocks without hash
* they can be either used or empty blocks
*/
sputc('O', f);
/* next begin position */
@ -3784,8 +3808,10 @@ static void* state_write_thread(void* arg)
/* get the file crc */
crc = scrc(f);
/* compare the crc of the data written to file */
/* with the one of the data written to the stream */
/*
* Compare the crc of the data written to file
* with the one of the data written to the stream
*/
if (crc != scrc_stream(f)) {
/* LCOV_EXCL_START */
log_fatal(ECONTENT, "CRC mismatch while writing the content stream.\n");
@ -3861,8 +3887,10 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
/* check the file-system on all disks */
state_fscheck(state, "before write");
/* clear the info for unused blocks */
/* and get some other info */
/*
* Clear the info for unused blocks
* and get some other info
*/
info_oldest = 0; /* oldest time in info */
info_now = time(0); /* get the present time */
info_has_rehash = 0; /* if there is a rehash info */
@ -4002,8 +4030,10 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
} else {
STREAM* f = context->f;
/* Use the sequence fflush() -> fsync() -> fclose() -> rename() to ensure */
/* than even in a system crash event we have one valid copy of the file. */
/*
* Use the sequence fflush() -> fsync() -> fclose() -> rename() to ensure
* than even in a system crash event we have one valid copy of the file.
*/
if (sflush(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing the content file '%s', in flush(). %s.\n", serrorfile(f), strerror(errno));
@ -4130,8 +4160,10 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
/* LCOV_EXCL_STOP */
}
/* Use the sequence fflush() -> fsync() -> fclose() -> rename() to ensure */
/* than even in a system crash event we have one valid copy of the file. */
/*
* Use the sequence fflush() -> fsync() -> fclose() -> rename() to ensure
* than even in a system crash event we have one valid copy of the file.
*/
if (sflush(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing the content file '%s', in flush(). %s.\n", serrorfile(f), strerror(errno));
@ -4328,8 +4360,10 @@ void state_read(struct snapraid_state* state)
node = node->next;
}
/* start with a undefined default. */
/* it's for compatibility with version 1.0 where MD5 was implicit. */
/*
* Start with a undefined default.
* it's for compatibility with version 1.0 where MD5 was implicit.
*/
state->hash = HASH_UNDEFINED;
/* start with a zero seed, it was the default in old versions */
@ -5152,14 +5186,18 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o
/* number of past measures */
past = state->progress_tick;
/* drop the oldest ones, to promptly */
/* skip the startup phase */
/*
* Drop the oldest ones, to promptly
* skip the startup phase
*/
past -= past / 5;
/* check how much we can go in the past */
if (past >= PROGRESS_MAX - 1) {
/* the vector is filled, so we are already in position */
/* to get the possible oldest one */
/*
* The vector is filled, so we are already in position
* to get the possible oldest one
*/
oldest = state->progress_ptr + 1;
} else {
/* go backward the number of positions selected */

View file

@ -176,18 +176,22 @@ int state_status(struct snapraid_state* state)
disk_block_max_by_space = disk_block_count + disk->free_blocks;
disk_block_max_by_parity = blockmax + parity_block_free;
/* the maximum usable space in a disk is limited by the smallest */
/* of the disk size and the parity size */
/* the wasted space is the space that we have to leave */
/* free on the data disk, when the parity is filled up */
/*
* The maximum usable space in a disk is limited by the smallest
* of the disk size and the parity size
* the wasted space is the space that we have to leave
* free on the data disk, when the parity is filled up
*/
if (disk_block_max_by_space < disk_block_max_by_parity) {
disk_block_max = disk_block_max_by_space;
} else {
disk_block_max = disk_block_max_by_parity;
}
/* wasted space is the difference of the two maximum size */
/* if negative, it's extra space available in parity */
/*
* Wasted space is the difference of the two maximum size
* if negative, it's extra space available in parity
*/
wasted = (int64_t)disk_block_max_by_space - (int64_t)disk_block_max_by_parity;
wasted *= state->block_size;

View file

@ -500,8 +500,10 @@ void msg_info(const char* format, ...)
lock_msg();
/* don't output in stdlog as these messages */
/* are always paired with a msg_tag() call */
/*
* Don't output in stdlog as these messages
* are always paired with a msg_tag() call
*/
if (msg_level >= MSG_INFO) {
va_start(ap, format);
@ -547,9 +549,11 @@ void msg_bar(const char* format, ...)
lock_msg();
/* don't output in stdlog as these messages */
/* are intended for screen only */
/* also don't flush stdout as they are intended to be partial messages */
/*
* Don't output in stdlog as these messages
* are intended for screen only
* also don't flush stdout as they are intended to be partial messages
*/
if (msg_level >= MSG_BAR) {
va_start(ap, format);
@ -1080,8 +1084,10 @@ void pathimport(char* dst, size_t size, const char* src)
pathcpy(dst, size, src);
#ifdef _WIN32
/* convert the Windows dir separator '\' to C '/', */
/* and the Windows escaping char '^' to the fnmatch '\' */
/*
* Convert the Windows dir separator '\' to C '/',
* and the Windows escaping char '^' to the fnmatch '\'
*/
while (*dst) {
switch (*dst) {
case '\\' :
@ -1429,8 +1435,10 @@ int advise_open(struct advise_struct* advise, int f)
) {
int ret;
/* advise noreuse access, this avoids to pollute the page cache */
/* supported from Linux Kernel 6.3 with this commit: https://github.com/torvalds/linux/commit/17e810229cb3068b692fa078bd9b3a6527e0866a */
/*
* Advise noreuse access, this avoids to pollute the page cache
* supported from Linux Kernel 6.3 with this commit: https://github.com/torvalds/linux/commit/17e810229cb3068b692fa078bd9b3a6527e0866a
*/
ret = posix_fadvise_wrapper(f, 0, 0, POSIX_FADV_NOREUSE);
if (ret == ENOSYS) {
/* call is not supported */
@ -1861,12 +1869,14 @@ void* malloc_nofail(size_t size)
}
#ifndef CHECKER /* Don't preinitialize when running for valgrind */
/* Here we preinitialize the memory to ensure that the OS is really allocating it */
/* and not only reserving the addressable space. */
/* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process. */
/* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to */
/* get a real error from malloc() instead than a process killed. */
/* Note that calloc() doesn't have the same effect. */
/*
* Here we preinitialize the memory to ensure that the OS is really allocating it
* and not only reserving the addressable space.
* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process.
* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to
* get a real error from malloc() instead than a process killed.
* Note that calloc() doesn't have the same effect.
*/
memset(ptr, 0xA5, size);
#endif
@ -2569,16 +2579,20 @@ int thread_cond_signal_outside = 0;
void thread_cond_signal_and_unlock(thread_cond_t* cond, thread_mutex_t* mutex)
{
if (thread_cond_signal_outside) {
/* without the thread checker unlock before signaling, */
/* this reduces the number of context switches */
/*
* Without the thread checker unlock before signaling,
* this reduces the number of context switches
*/
thread_mutex_unlock(mutex);
}
thread_cond_signal(cond);
if (!thread_cond_signal_outside) {
/* with the thread checker unlock after signaling */
/* to make explicit the condition and mutex relation */
/*
* With the thread checker unlock after signaling
* to make explicit the condition and mutex relation
*/
thread_mutex_unlock(mutex);
}
}
@ -2586,16 +2600,20 @@ void thread_cond_signal_and_unlock(thread_cond_t* cond, thread_mutex_t* mutex)
void thread_cond_broadcast_and_unlock(thread_cond_t* cond, thread_mutex_t* mutex)
{
if (thread_cond_signal_outside) {
/* without the thread checker unlock before signaling, */
/* this reduces the number of context switches */
/*
* Without the thread checker unlock before signaling,
* this reduces the number of context switches
*/
thread_mutex_unlock(mutex);
}
thread_cond_broadcast(cond);
if (!thread_cond_signal_outside) {
/* with the thread checker unlock after signaling */
/* to make explicit the condition and mutex relation */
/*
* With the thread checker unlock after signaling
* to make explicit the condition and mutex relation
*/
thread_mutex_unlock(mutex);
}
}

View file

@ -133,8 +133,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
/* This one is really an unexpected error, because we are only reading */
/* and closing a descriptor should never fail */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %u\n", blockcur);
@ -156,8 +158,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
log_error_errno(errno, disk->name);
++soft_error;
/* if the file is missing, it means that it was removed during sync */
/* this isn't a serious error, so we skip this block, and continue with others */
/*
* If the file is missing, it means that it was removed during sync
* this isn't a serious error, so we skip this block, and continue with others
*/
continue;
}
@ -204,8 +208,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
++soft_error;
/* if the file is changed, it means that it was modified during sync */
/* this isn't a serious error, so we skip this block, and continue with others */
/*
* If the file is changed, it means that it was modified during sync
* this isn't a serious error, so we skip this block, and continue with others
*/
continue;
}
@ -295,8 +301,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
/* This one is really an unexpected error, because we are only reading */
/* and closing a descriptor should never fail */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %u\n", blockmax);
@ -315,8 +323,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
end:
state_progress_end(state, countpos, countmax, countsize, "Nothing to hash.\n");
/* note that at this point no io_error is possible */
/* because at the first one we bail out */
/*
* Note that at this point no io_error is possible
* because at the first one we bail out
*/
assert(io_error == 0);
if (soft_error || io_error || silent_error) {
@ -471,8 +481,10 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
/* get the block */
task->block = fs_par2block_find(disk, blockcur);
/* if the block has no file, meaning that it's EMPTY or DELETED, */
/* it doesn't participate in the new parity computation */
/*
* If the block has no file, meaning that it's EMPTY or DELETED,
* it doesn't participate in the new parity computation
*/
if (!block_has_file(task->block)) {
/* use an empty block */
memset(buffer, 0, state->block_size);
@ -490,8 +502,10 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
ret = handle_close(handle);
if (ret == -1) {
/* LCOV_EXCL_START */
/* This one is really an unexpected error, because we are only reading */
/* and closing a descriptor should never fail */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %u\n", blockcur);
@ -512,8 +526,10 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
if (errno == ENOENT) {
log_error_errno(errno, disk->name);
/* if the file is missing, it means that it was removed during sync */
/* this isn't a serious error, so we skip this block, and continue with others */
/*
* If the file is missing, it means that it was removed during sync
* this isn't a serious error, so we skip this block, and continue with others
*/
task->state = TASK_STATE_ERROR_CONTINUE;
return;
}
@ -557,8 +573,10 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
}
log_error_errno(ENOENT, disk->name); /* same message for ENOENT */
/* if the file is changed, it means that it was modified during sync */
/* this isn't a serious error, so we skip this block, and continue with others */
/*
* If the file is changed, it means that it was modified during sync
* this isn't a serious error, so we skip this block, and continue with others
*/
task->state = TASK_STATE_ERROR_CONTINUE;
return;
}
@ -701,9 +719,11 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
++countmax;
}
/* compute the autosave size for all disk, even if not read */
/* this makes sense because the speed should be almost the same */
/* if the disks are read in parallel */
/*
* Compute the autosave size for all disk, even if not read
* this makes sense because the speed should be almost the same
* if the disks are read in parallel
*/
autosavelimit = state->autosave / (diskmax * state->block_size);
autosavemissing = countmax; /* blocks to do */
autosavedone = 0; /* blocks done */
@ -781,8 +801,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* if the parity is going to be updated */
parity_going_to_be_updated = 0;
/* if the block is marked as bad, we force the parity update */
/* because the bad block may be the result of a wrong parity */
/*
* If the block is marked as bad, we force the parity update
* because the bad block may be the result of a wrong parity
*/
if (info_get_bad(info))
parity_needs_to_be_updated = 1;
@ -825,26 +847,34 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* get the state of the block */
block_state = block_state_get(block);
/* if the block has invalid parity, */
/* we have to take care of it in case of recover */
/*
* If the block has invalid parity,
* we have to take care of it in case of recover
*/
if (block_has_invalid_parity(block)) {
/* store it in the failed set, because */
/* the parity may be still computed with the previous content */
/*
* Store it in the failed set, because
* the parity may be still computed with the previous content
*/
failed[failed_count].index = diskcur;
failed[failed_count].size = state->block_size;
failed[failed_count].block = block;
++failed_count;
/* if the block has invalid parity, we have to update the parity */
/* to include this block change */
/* This also apply to CHG blocks, but we are going to handle */
/* later this case to do the updates only if really needed */
/*
* If the block has invalid parity, we have to update the parity
* to include this block change
* This also apply to CHG blocks, but we are going to handle
* later this case to do the updates only if really needed
*/
if (block_state != BLOCK_STATE_CHG)
parity_needs_to_be_updated = 1;
/* note that DELETE blocks are skipped in the next check */
/* and we have to store them in the failed blocks */
/* before skipping */
/*
* Note that DELETE blocks are skipped in the next check
* and we have to store them in the failed blocks
* before skipping
*/
/* follow */
}
@ -928,8 +958,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
++soft_error;
/* if the file is changed, it means that it was modified during sync */
/* this isn't a serious error, so we skip this block, and continue with others */
/*
* If the file is changed, it means that it was modified during sync
* this isn't a serious error, so we skip this block, and continue with others
*/
error_on_this_block = 1;
continue;
} else { /* otherwise it's a BLK with silent error */
@ -943,9 +975,11 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
failed[failed_count].block = block;
++failed_count;
/* silent errors are very rare, and are not a signal that a disk */
/* is going to fail. So, we just continue marking the block as bad */
/* just like in scrub */
/*
* Silent errors are very rare, and are not a signal that a disk
* is going to fail. So, we just continue marking the block as bad
* just like in scrub
*/
++silent_error;
silent_error_on_this_block = 1;
continue;
@ -954,9 +988,11 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
} else {
/* if until now the parity doesn't need to be updated */
if (!parity_needs_to_be_updated) {
/* for sure it's a CHG block, because EMPTY are processed before with "continue" */
/* and BLK and REP have "block_has_updated_hash()" as 1, and all the others */
/* have "parity_needs_to_be_updated" already at 1 */
/*
* For sure it's a CHG block, because EMPTY are processed before with "continue"
* and BLK and REP have "block_has_updated_hash()" as 1, and all the others
* have "parity_needs_to_be_updated" already at 1
*/
assert(block_state_get(block) == BLOCK_STATE_CHG);
/*
@ -1003,25 +1039,33 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
}
}
/* copy the hash in the block, but doesn't mark the block as hashed */
/* this allow in case of skipped block to do not save the failed computation */
/*
* Copy the hash in the block, but doesn't mark the block as hashed
* this allow in case of skipped block to do not save the failed computation
*/
memcpy(block->hash, hash, BLOCK_HASH_SIZE);
/* note that in case of rehash, this is the wrong hash, */
/* but it will be overwritten later */
/*
* Note that in case of rehash, this is the wrong hash,
* but it will be overwritten later
*/
}
}
/* if we have only silent errors we can try to fix them on-the-fly */
/* note the fix is not written to disk, but used only to */
/* compute the new parity */
/*
* If we have only silent errors we can try to fix them on-the-fly
* note the fix is not written to disk, but used only to
* compute the new parity
*/
if (!error_on_this_block && !io_error_on_this_block && silent_error_on_this_block) {
unsigned failed_mac;
int something_to_recover = 0;
/* sort the failed vector */
/* because with threads it may be in any order */
/* but RAID requires the indexes to be sorted */
/*
* Sort the failed vector
* because with threads it may be in any order
* but RAID requires the indexes to be sorted
*/
qsort(failed, failed_count, sizeof(failed[0]), failed_compare_by_index);
/* setup the blocks to recover */
@ -1035,15 +1079,19 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
if (block_state == BLOCK_STATE_BLK)
something_to_recover = 1;
/* save a copy of the content just read */
/* that it's going to be overwritten by the recovering function */
/*
* Save a copy of the content just read
* that it's going to be overwritten by the recovering function
*/
memcpy(block_copy, block_buffer, state->block_size);
if (block_state == BLOCK_STATE_CHG
&& hash_is_zero(failed[j].block->hash)
) {
/* if the block was filled with 0, restore this state */
/* and avoid to recover it */
/*
* If the block was filled with 0, restore this state
* and avoid to recover it
*/
memset(block_buffer, 0, state->block_size);
} else {
/* if we have too many failures, we cannot recover */
@ -1060,9 +1108,11 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* until now is misc */
state_usage_misc(state);
/* read the parity */
/* we are sure that parity exists because */
/* we have at least one BLK block */
/*
* Read the parity
* we are sure that parity exists because
* we have at least one BLK block
*/
for (l = 0; l < state->level; ++l) {
ret = parity_read(&parity_handle[l], blockcur, buffer[diskmax + l], state->block_size);
if (ret == -1) {
@ -1095,10 +1145,12 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* if no error in parity read */
if (!io_error_on_this_block) {
/* try to fix the data */
/* note that this is a simple fix algorithm, that doesn't take into */
/* account the case of a wrong parity */
/* only 'fix' supports the most advanced fixing */
/*
* Try to fix the data
* note that this is a simple fix algorithm, that doesn't take into
* account the case of a wrong parity
* only 'fix' supports the most advanced fixing
*/
raid_rec(failed_mac, failed_map, diskmax, state->level, state->block_size, buffer);
/* until now is raid */
@ -1134,9 +1186,11 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
if (size < state->block_size)
memset(block_buffer + size, 0, state->block_size - size);
} else {
/* otherwise restore the content */
/* because we are not interested in the old state */
/* that it's recovered for CHG, REP and DELETED blocks */
/*
* Otherwise restore the content
* because we are not interested in the old state
* that it's recovered for CHG, REP and DELETED blocks
*/
memcpy(block_buffer, block_copy, state->block_size);
}
}
@ -1189,11 +1243,13 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
block_state_set(block, BLOCK_STATE_BLK);
}
/* we update the info block only if we really have updated the parity */
/* because otherwise the time/justsynced info would be misleading as we didn't */
/* wrote the parity at this time */
/* we also update the info block only if no silent error was found */
/* because has no sense to refresh the time for data that we know bad */
/*
* We update the info block only if we really have updated the parity
* because otherwise the time/justsynced info would be misleading as we didn't
* wrote the parity at this time
* we also update the info block only if no silent error was found
* because has no sense to refresh the time for data that we know bad
*/
if (parity_needs_to_be_updated
&& !silent_error_on_this_block
) {
@ -1206,24 +1262,30 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
}
}
/* update the time info of the block */
/* we are also clearing any previous bad and rehash flag */
/*
* Update the time info of the block
* we are also clearing any previous bad and rehash flag
*/
info_set(&state->infoarr, blockcur, info_make(now, 0, 0, 1));
}
}
/* if a silent (even if corrected) or input/output error was found */
/* mark the block as bad to have check/fix to handle it */
/* because our correction is in memory only and not yet written */
/*
* If a silent (even if corrected) or input/output error was found
* mark the block as bad to have check/fix to handle it
* because our correction is in memory only and not yet written
*/
if (silent_error_on_this_block || io_error_on_this_block) {
/* set the error status keeping the other info */
info_set(&state->infoarr, blockcur, info_set_bad(info));
}
/* finally schedule parity write */
/* Note that the calls to io_parity_write() are mandatory */
/* even if the parity doesn't need to be updated */
/* This because we want to keep track of the time usage */
/*
* Finally schedule parity write
* Note that the calls to io_parity_write() are mandatory
* even if the parity doesn't need to be updated
* This because we want to keep track of the time usage
*/
state_usage_misc(state);
/* write start */
@ -1327,8 +1389,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
msg_progress("Autosaving...\n");
/* before writing the new content file we ensure that */
/* the parity is really written flushing the disk cache */
/*
* Before writing the new content file we ensure that
* the parity is really written flushing the disk cache
*/
ret = state_flush(state, &io, parity_handle, blockcur);
if (ret == -1) {
/* LCOV_EXCL_START */
@ -1351,8 +1415,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
end:
state_progress_end(state, countpos, countmax, countsize, "Nothing to sync.\n");
/* before returning we ensure that */
/* the parity is really written flushing the disk cache */
/*
* Before returning we ensure that
* the parity is really written flushing the disk cache
*/
ret = state_flush(state, &io, parity_handle, blockcur);
if (ret == -1) {
/* LCOV_EXCL_START */
@ -1558,9 +1624,11 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
for (l = 0; l < state->level; ++l) {
int is_modified;
/* change the size of the parity file, truncating or extending it */
/* from this point all the DELETED blocks after the end of the parity are invalid */
/* and they are automatically removed when we save the new content file */
/*
* Change the size of the parity file, truncating or extending it
* from this point all the DELETED blocks after the end of the parity are invalid
* and they are automatically removed when we save the new content file
*/
ret = parity_chsize(&parity_handle[l], &state->parity[l], &is_modified, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder);
if (ret == -1) {
/* LCOV_EXCL_START */

View file

@ -24,9 +24,11 @@ void state_touch(struct snapraid_state* state)
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
/* if the file has a zero nanosecond timestamp */
/* note that symbolic links are not in the file list */
/* and then are not processed */
/*
* If the file has a zero nanosecond timestamp
* note that symbolic links are not in the file list
* and then are not processed
*/
if (file->mtime_nsec == 0) {
char path[PATH_MAX];
struct stat st;
@ -52,8 +54,10 @@ void state_touch(struct snapraid_state* state)
nsec = nano % 1000000000;
} while (nsec == 0);
/* O_BINARY: open as binary file (Windows only) */
/* O_NOFOLLOW: do not follow links to ensure to open the real file */
/*
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW;
#ifdef _WIN32
/* in Windows we must have write access at the file */
@ -90,8 +94,10 @@ void state_touch(struct snapraid_state* state)
/* LCOV_EXCL_STOP */
}
/* get the present timestamp, that may be different than the one */
/* in the content file */
/*
* Get the present timestamp, that may be different than the one
* in the content file
*/
ret = fstat(f, &st);
if (ret == -1) {
/* LCOV_EXCL_START */
@ -111,9 +117,11 @@ void state_touch(struct snapraid_state* state)
/* LCOV_EXCL_STOP */
}
/* uses fstat again to get the present timestamp */
/* this is needed because the value read */
/* may be different than the written one */
/*
* Uses fstat again to get the present timestamp
* this is needed because the value read
* may be different than the written one
*/
ret = fstat(f, &st);
if (ret == -1) {
/* LCOV_EXCL_START */
@ -132,10 +140,12 @@ void state_touch(struct snapraid_state* state)
/* LCOV_EXCL_STOP */
}
/* set the same nanosecond value in the content file */
/* note that if the seconds value is already matching */
/* the file won't be synced because the content file will */
/* contain the new updated timestamp */
/*
* Set the same nanosecond value in the content file
* note that if the seconds value is already matching
* the file won't be synced because the content file will
* contain the new updated timestamp
*/
file->mtime_nsec = STAT_NSEC(&st);
/* state changed, we need to update it */

View file

@ -964,8 +964,10 @@ int devuuid(uint64_t device_id, const char* device_path, char* uuid, size_t uuid
int filephy(const char* path, uint64_t size, uint64_t* physical)
{
#if HAVE_LINUX_FIEMAP_H
/* In Linux get the real physical address of the file */
/* Note that FIEMAP doesn't require root permission */
/*
* In Linux get the real physical address of the file
* Note that FIEMAP doesn't require root permission
*/
int f;
struct fiemap* fiemap;
size_t fiemap_size;
@ -976,8 +978,10 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
return -1;
}
/* first try with FIEMAP */
/* if works for ext2, ext3, ext4, xfs, btrfs */
/*
* First try with FIEMAP
* if works for ext2, ext3, ext4, xfs, btrfs
*/
fiemap_size = sizeof(struct fiemap) + sizeof(struct fiemap_extent);
fiemap = malloc_nofail(fiemap_size);
memset(fiemap, 0, fiemap_size);
@ -998,8 +1002,10 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
/* if the offset is unknown, we don't have an offset to report */
*physical = FILEPHY_WITHOUT_OFFSET;
} else if (offset == 0) {
/* 0 is the general fallback for file-systems when */
/* they don't have an offset to report */
/*
* 0 is the general fallback for file-systems when
* they don't have an offset to report
*/
*physical = FILEPHY_WITHOUT_OFFSET;
} else {
/* finally report the real offset */
@ -1023,9 +1029,11 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
return 0;
}
/* then try with FIBMAP */
/* it works for jfs, reiserfs, ntfs-3g */
/* in exfat it always returns 0, that it's anyway better than the fake inodes */
/*
* Then try with FIBMAP
* it works for jfs, reiserfs, ntfs-3g
* in exfat it always returns 0, that it's anyway better than the fake inodes
*/
blknum = 0; /* first block */
if (ioctl(f, FIBMAP, &blknum) != -1) {
*physical = blknum + FILEPHY_REAL_OFFSET;
@ -1034,22 +1042,26 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
return 0;
}
/* otherwise don't use anything, and keep the directory traversal order */
/* at now this should happen only for vfat */
/* and it's surely better than using fake inodes */
/*
* Otherwise don't use anything, and keep the directory traversal order
* at now this should happen only for vfat
* and it's surely better than using fake inodes
*/
*physical = FILEPHY_UNREPORTED_OFFSET;
if (close(f) == -1)
return -1;
#else
/* In a generic Unix use a dummy value for all the files */
/* We don't want to risk to use the inode without knowing */
/* if it really improves performance. */
/* In this way we keep them in the directory traversal order */
/* that at least keeps files in the same directory together. */
/* Note also that in newer file-system with snapshot, like ZFS, */
/* the inode doesn't represent even more the disk position, because files */
/* are not overwritten in place, but rewritten in another location */
/* of the disk. */
/*
* In a generic Unix use a dummy value for all the files
* We don't want to risk to use the inode without knowing
* if it really improves performance.
* In this way we keep them in the directory traversal order
* that at least keeps files in the same directory together.
* Note also that in newer file-system with snapshot, like ZFS,
* the inode doesn't represent even more the disk position, because files
* are not overwritten in place, but rewritten in another location
* of the disk.
*/
*physical = FILEPHY_UNREPORTED_OFFSET;
(void)path; /* not used here */
@ -1267,8 +1279,10 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
return -1;
}
/* if it doesn't exist, we assume a file */
/* and we check for the containing dir */
/*
* If it doesn't exist, we assume a file
* and we check for the containing dir
*/
if (strlen(path) + 1 > sizeof(dir)) {
errno = ENAMETOOLONG;
return -1;
@ -1345,8 +1359,10 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
/* get the filesystem type directly from the struct (Mac OS X) */
ptype = st.f_fstypename;
#elif HAVE_STATFS && HAVE_STRUCT_STATFS_F_TYPE
/* get the filesystem type from f_type (Linux) */
/* from: https://github.com/influxdata/gopsutil/blob/master/disk/disk_linux.go */
/*
* Get the filesystem type from f_type (Linux)
* from: https://github.com/influxdata/gopsutil/blob/master/disk/disk_linux.go
*/
for (int i = 0; FILESYSTEMS[i].id != 0; ++i) {
if (st.f_type == FILESYSTEMS[i].id) {
ptype = FILESYSTEMS[i].name;