mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Auto detection of fake physical offsets.
Fixes hardlink detection with not persistent inodes.
This commit is contained in:
parent
f990c7106b
commit
e8ba8c435a
4 changed files with 102 additions and 15 deletions
1
elem.c
1
elem.c
|
|
@ -524,6 +524,7 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
|
||||||
disk->device = dev;
|
disk->device = dev;
|
||||||
disk->first_free_block = 0;
|
disk->first_free_block = 0;
|
||||||
disk->has_not_persistent_inodes = 0;
|
disk->has_not_persistent_inodes = 0;
|
||||||
|
disk->has_not_reliable_physical = 0;
|
||||||
disk->mapping = -1;
|
disk->mapping = -1;
|
||||||
tommy_list_init(&disk->filelist);
|
tommy_list_init(&disk->filelist);
|
||||||
tommy_list_init(&disk->deletedlist);
|
tommy_list_init(&disk->deletedlist);
|
||||||
|
|
|
||||||
1
elem.h
1
elem.h
|
|
@ -274,6 +274,7 @@ struct snapraid_disk {
|
||||||
uint64_t device; /**< Device identifier. */
|
uint64_t device; /**< Device identifier. */
|
||||||
block_off_t first_free_block; /**< First free searching block. */
|
block_off_t first_free_block; /**< First free searching block. */
|
||||||
int has_not_persistent_inodes; /**< If the underline filesystem has dynamic inodes. */
|
int has_not_persistent_inodes; /**< If the underline filesystem has dynamic inodes. */
|
||||||
|
int has_not_reliable_physical; /**< If the physical offset of files has duplicates. */
|
||||||
int mapping; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
|
int mapping; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
|
||||||
|
|
||||||
/**<
|
/**<
|
||||||
|
|
|
||||||
112
scan.c
112
scan.c
|
|
@ -277,11 +277,13 @@ static void scan_file_insert(struct snapraid_state* state, struct snapraid_disk*
|
||||||
static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state, int output, struct snapraid_disk* disk, const char* sub, const struct stat* st, uint64_t physical)
|
static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state, int output, struct snapraid_disk* disk, const char* sub, const struct stat* st, uint64_t physical)
|
||||||
{
|
{
|
||||||
struct snapraid_file* file;
|
struct snapraid_file* file;
|
||||||
|
uint64_t inode;
|
||||||
|
|
||||||
file = 0;
|
file = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the disk has persistent inodes, try a search by inode.
|
* If the disk has persistent inodes, try a search by inode,
|
||||||
|
* to detect moved files.
|
||||||
*
|
*
|
||||||
* For persistent inodes we mean inodes that keep their values when the filesystem
|
* For persistent inodes we mean inodes that keep their values when the filesystem
|
||||||
* is unmounted and remounted. This don't always happen.
|
* is unmounted and remounted. This don't always happen.
|
||||||
|
|
@ -293,15 +295,18 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
|
||||||
* making inode collision more easy (exFAT by design supports 10ms precision).
|
* making inode collision more easy (exFAT by design supports 10ms precision).
|
||||||
* - Linux VFAT kernel (3.2) driver. Inodes are fully reassigned at every mount.
|
* - Linux VFAT kernel (3.2) driver. Inodes are fully reassigned at every mount.
|
||||||
*
|
*
|
||||||
* In such cases, to avoid possible random collisions, it's better to just avoid
|
* In such cases, to avoid possible random collisions, it's better to disable the moved
|
||||||
* to use inodes at all.
|
* file recognizition.
|
||||||
|
*
|
||||||
|
* We do this implicitely removing all the inode before searching for files.
|
||||||
|
* This ensure that no file is found with an old inode, but at the same time,
|
||||||
|
* it allows to find new files with the same inode, and to identify them as hardlinks.
|
||||||
*/
|
*/
|
||||||
if (!disk->has_not_persistent_inodes) {
|
|
||||||
/* first try finding by inode */
|
|
||||||
uint64_t inode = st->st_ino;
|
|
||||||
file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
inode = st->st_ino;
|
||||||
|
file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
|
||||||
|
|
||||||
|
/* identify moved files searching by inode */
|
||||||
if (file) {
|
if (file) {
|
||||||
/* check if the file is not changed */
|
/* check if the file is not changed */
|
||||||
if (file->size == st->st_size
|
if (file->size == st->st_size
|
||||||
|
|
@ -816,6 +821,9 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
tommy_node* node;
|
tommy_node* node;
|
||||||
int ret;
|
int ret;
|
||||||
int has_persistent_inode;
|
int has_persistent_inode;
|
||||||
|
unsigned phy_count;
|
||||||
|
unsigned phy_dup;
|
||||||
|
uint64_t phy_last;
|
||||||
|
|
||||||
scan = malloc_nofail(sizeof(struct snapraid_scan));
|
scan = malloc_nofail(sizeof(struct snapraid_scan));
|
||||||
scan->count_equal = 0;
|
scan->count_equal = 0;
|
||||||
|
|
@ -838,10 +846,29 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
fprintf(stderr, "Error accessing disk '%s' to get filesystem info. %s.\n", disk->dir, strerror(errno));
|
fprintf(stderr, "Error accessing disk '%s' to get filesystem info. %s.\n", disk->dir, strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
/* mark the disk if required */
|
|
||||||
if (!has_persistent_inode) {
|
if (!has_persistent_inode) {
|
||||||
fprintf(stderr, "WARNING! Inodes use disabled for disk '%s' because they are not persistent.\n", disk->dir);
|
/* mask the disk */
|
||||||
disk->has_not_persistent_inodes = 1;
|
disk->has_not_persistent_inodes = 1;
|
||||||
|
|
||||||
|
/* removes 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 */
|
||||||
|
node = disk->filelist;
|
||||||
|
while (node) {
|
||||||
|
struct snapraid_file* file = node->data;
|
||||||
|
|
||||||
|
node = node->next;
|
||||||
|
|
||||||
|
/* remove from the inode set */
|
||||||
|
tommy_hashdyn_remove_existing(&disk->inodeset, &file->nodeset);
|
||||||
|
|
||||||
|
/* clear the inode */
|
||||||
|
file->inode = 0;
|
||||||
|
|
||||||
|
/* mark as missing inode */
|
||||||
|
file_flag_set(file, FILE_IS_WITHOUT_INODE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_dir(scan, state, output, disk, disk->dir, "");
|
scan_dir(scan, state, output, disk, disk->dir, "");
|
||||||
|
|
@ -939,9 +966,20 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
/* insert all the new files, we insert them only after the deletion */
|
/* insert all the new files, we insert them only after the deletion */
|
||||||
/* to reuse the just freed space */
|
/* to reuse the just freed space */
|
||||||
node = scan->file_insert_list;
|
node = scan->file_insert_list;
|
||||||
|
phy_count = 0;
|
||||||
|
phy_dup = 0;
|
||||||
|
phy_last = -1;
|
||||||
while (node) {
|
while (node) {
|
||||||
struct snapraid_file* file = node->data;
|
struct snapraid_file* file = node->data;
|
||||||
|
|
||||||
|
/* if the file is not empty, count duplicate physical offsets */
|
||||||
|
if (state->opt.force_order == SORT_PHYSICAL && file->size != 0) {
|
||||||
|
if (phy_count > 0 && file->physical == phy_last)
|
||||||
|
++phy_dup;
|
||||||
|
phy_last = file->physical;
|
||||||
|
++phy_count;
|
||||||
|
}
|
||||||
|
|
||||||
/* next node */
|
/* next node */
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
|
||||||
|
|
@ -949,6 +987,12 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
scan_file_insert(state, disk, file);
|
scan_file_insert(state, disk, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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_not_reliable_physical = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* insert all the new links */
|
/* insert all the new links */
|
||||||
node = scan->link_insert_list;
|
node = scan->link_insert_list;
|
||||||
while (node) {
|
while (node) {
|
||||||
|
|
@ -976,21 +1020,21 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
|
|
||||||
/* checks for disks where all the previously existing files where removed */
|
/* checks for disks where all the previously existing files where removed */
|
||||||
if (!state->opt.force_empty) {
|
if (!state->opt.force_empty) {
|
||||||
int has_empty = 0;
|
int done = 0;
|
||||||
for(i=state->disklist,j=scanlist;i!=0;i=i->next,j=j->next) {
|
for(i=state->disklist,j=scanlist;i!=0;i=i->next,j=j->next) {
|
||||||
struct snapraid_disk* disk = i->data;
|
struct snapraid_disk* disk = i->data;
|
||||||
struct snapraid_scan* scan = j->data;
|
struct snapraid_scan* scan = j->data;
|
||||||
|
|
||||||
if (scan->count_equal == 0 && scan->count_move == 0 && scan->count_restore == 0 && (scan->count_remove != 0 || scan->count_change != 0)) {
|
if (scan->count_equal == 0 && scan->count_move == 0 && scan->count_restore == 0 && (scan->count_remove != 0 || scan->count_change != 0)) {
|
||||||
if (!has_empty) {
|
if (!done) {
|
||||||
has_empty = 1;
|
done = 1;
|
||||||
fprintf(stderr, "All the files previously present in disk '%s' at dir '%s'", disk->name, disk->dir);
|
fprintf(stderr, "All the files previously present in disk '%s' at dir '%s'", disk->name, disk->dir);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, ", disk '%s' at dir '%s'", disk->name, disk->dir);
|
fprintf(stderr, ", disk '%s' at dir '%s'", disk->name, disk->dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (has_empty) {
|
if (done) {
|
||||||
fprintf(stderr, " are now missing or rewritten!\n");
|
fprintf(stderr, " are now missing or rewritten!\n");
|
||||||
fprintf(stderr, "This could happen when deleting all the files from a disk,\n");
|
fprintf(stderr, "This could happen when deleting all the files from a disk,\n");
|
||||||
fprintf(stderr, "and restoring them with a program not setting correctly the timestamps.\n");
|
fprintf(stderr, "and restoring them with a program not setting correctly the timestamps.\n");
|
||||||
|
|
@ -1001,6 +1045,46 @@ void state_scan(struct snapraid_state* state, int output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* checks for disks without the physical offset support */
|
||||||
|
if (state->opt.force_order == SORT_PHYSICAL) {
|
||||||
|
int done = 0;
|
||||||
|
for(i=state->disklist;i!=0;i=i->next) {
|
||||||
|
struct snapraid_disk* disk = i->data;
|
||||||
|
|
||||||
|
if (disk->has_not_reliable_physical) {
|
||||||
|
if (!done) {
|
||||||
|
done = 1;
|
||||||
|
fprintf(stderr, "WARNING! Physical offsets not supported for disk '%s'", disk->name);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, ", '%s", disk->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
fprintf(stderr, ". Performance won't be optimal.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for disks without persisten inodes */
|
||||||
|
{
|
||||||
|
int done = 0;
|
||||||
|
for(i=state->disklist;i!=0;i=i->next) {
|
||||||
|
struct snapraid_disk* disk = i->data;
|
||||||
|
|
||||||
|
if (disk->has_not_persistent_inodes) {
|
||||||
|
if (!done) {
|
||||||
|
done = 1;
|
||||||
|
fprintf(stderr, "WARNING! Inodes are not persistent for disk '%s'", disk->name);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, ", '%s", disk->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
fprintf(stderr, ". Move operations won't be optimized.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state->opt.verbose || output) {
|
if (state->opt.verbose || output) {
|
||||||
struct snapraid_scan total;
|
struct snapraid_scan total;
|
||||||
|
|
||||||
|
|
|
||||||
1
unix.c
1
unix.c
|
|
@ -186,6 +186,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical)
|
||||||
*physical = 0;
|
*physical = 0;
|
||||||
|
|
||||||
(void)path; /* not used here */
|
(void)path; /* not used here */
|
||||||
|
(void)st;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue