Avoids to use inodes in disk with UUID changed.

This commit is contained in:
Andrea Mazzoleni 2013-12-14 17:54:04 +01:00
parent 90d1cf01df
commit 7be2420cf3
5 changed files with 62 additions and 25 deletions

View file

@ -3,6 +3,10 @@ SnapRAID HISTORY
5.2 2013/12 (BETA)
==================
* If a disk changes UUID, automatically disable the inode
recognition, because this is likely a new filesystem with
all the inodes reassigned, and we don't want to risk a false
positive when searching for inode.
* Does not count empty dirs as files in the diff counters.
5.1 2013/12

5
elem.c
View file

@ -530,8 +530,9 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
disk->device = dev;
disk->first_free_block = 0;
disk->has_not_persistent_inodes = 0;
disk->has_not_reliable_physical = 0;
disk->has_volatile_inodes = 0;
disk->has_unreliable_physical = 0;
disk->has_different_uuid = 0;
disk->mapping = -1;
tommy_list_init(&disk->filelist);
tommy_list_init(&disk->deletedlist);

5
elem.h
View file

@ -283,8 +283,9 @@ struct snapraid_disk {
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
uint64_t device; /**< Device identifier. */
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_reliable_physical; /**< If the physical offset of files has duplicates. */
int has_volatile_inodes; /**< If the underline filesystem has not persistent inodes. */
int has_unreliable_physical; /**< If the physical offset of files has duplicates. */
int has_different_uuid; /**< If the disk has a different UUID, meaning that it is not the same filesystem. */
int mapping; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
/**<

65
scan.c
View file

@ -290,12 +290,9 @@ 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)
{
struct snapraid_file* file;
uint64_t inode;
file = 0;
/*
* If the disk has persistent inodes, try a search by inode,
* If the disk has persistent inodes and UUID, try a search on the past inodes,
* to detect moved files.
*
* For persistent inodes we mean inodes that keep their values when the filesystem
@ -311,15 +308,23 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
* In such cases, to avoid possible random collisions, it's better to disable the moved
* file recognition.
*
* We do this implicitely removing all the inode before searching for files.
* This ensures 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.
* For persistent UUID we mean that it has the same UUID as before.
* Otherwise, if the UUID is changed, likely it's a new recreated filesystem,
* and then the inode have no meaning.
*
* Note that to disable the search by past inode, we do this implicitely
* removing all the past inode before searching for files.
* This ensures that no file is found with a past inode, but at the same time,
* it allows to find new files with the same inode, to identify them as hardlinks.
*/
int has_past_inodes = !disk->has_volatile_inodes && !disk->has_different_uuid;
inode = st->st_ino;
/* 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));
/* identify moved files searching by inode */
/* identify moved files with past inodes and hardlinks with the new inodes */
if (file) {
/* check if the file is not changed */
if (file->size == st->st_size
@ -473,8 +478,8 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
state->need_write = 1;
}
/* if the disk support persistent inodes */
if (!disk->has_not_persistent_inodes) {
/* 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. */
@ -791,7 +796,7 @@ static int scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, in
#if HAVE_STRUCT_DIRENT_D_INO
/* if inodes are persistent */
if (!disk->has_not_persistent_inodes) {
if (!disk->has_volatile_inodes) {
/* sort the list of dir entries by inodes */
tommy_list_sort(&list, dd_ino_compare);
}
@ -999,9 +1004,11 @@ void state_scan(struct snapraid_state* state, int output)
exit(EXIT_FAILURE);
}
if (!has_persistent_inode) {
/* mask the disk */
disk->has_not_persistent_inodes = 1;
disk->has_volatile_inodes = 1;
}
/* if inodes or UUID are not persistent */
if (disk->has_volatile_inodes || disk->has_different_uuid) {
/* 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 */
@ -1138,7 +1145,7 @@ void state_scan(struct snapraid_state* state, int output)
/* 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;
disk->has_unreliable_physical = 1;
}
/* insert all the new links */
@ -1199,7 +1206,7 @@ void state_scan(struct snapraid_state* state, int output)
for(i=state->disklist;i!=0;i=i->next) {
struct snapraid_disk* disk = i->data;
if (disk->has_not_reliable_physical) {
if (disk->has_unreliable_physical) {
if (!done) {
done = 1;
fprintf(stderr, "WARNING! Physical offsets not supported for disk '%s'", disk->name);
@ -1213,16 +1220,36 @@ void state_scan(struct snapraid_state* state, int output)
}
}
/* Check for disks without persisten inodes */
/* Check for disks without persistent 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 (disk->has_volatile_inodes) {
if (!done) {
done = 1;
fprintf(stderr, "WARNING! Inodes are not persistent for disk '%s'", disk->name);
fprintf(stderr, "WARNING! Inodes are not persistent for disks: '%s'", disk->name);
} else {
fprintf(stderr, ", '%s", disk->name);
}
}
}
if (done) {
fprintf(stderr, ". Move operations won't be optimized.\n");
}
}
/* Check for disks with changed UUID */
{
int done = 0;
for(i=state->disklist;i!=0;i=i->next) {
struct snapraid_disk* disk = i->data;
if (disk->has_different_uuid) {
if (!done) {
done = 1;
fprintf(stderr, "WARNING! UUID is changed for disks: '%s'", disk->name);
} else {
fprintf(stderr, ", '%s", disk->name);
}

View file

@ -801,7 +801,7 @@ static void state_map(struct snapraid_state* state)
tommy_list_insert_tail(&state->maplist, &map->node, map);
}
/* without configuration don't check for number of data disks */
/* without configuration don't check for number of data disks or uuid changes */
if (state->no_conf)
return;
@ -829,12 +829,16 @@ static void state_map(struct snapraid_state* state)
ret = devuuid(disk->device, uuid, sizeof(uuid));
if (ret != 0) {
/* uuid not available, just ignore */
/* uuid not available, just ignore but marks the disk with not persistent UUID */
disk->has_different_uuid = 1;
continue;
}
/* if the uuid is changed */
if (strcmp(uuid, map->uuid) != 0) {
/* mark the disk as with an UUID change */
disk->has_different_uuid = 1;
/* if the previous uuid is available */
if (map->uuid[0] != 0) {
/* count the number of uuid change */