mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Marks FUSE filesystem as with not persistent inodes,
disabling inode use in such case.
This commit is contained in:
parent
4fb96c0dec
commit
e4e13a669b
8 changed files with 65 additions and 35 deletions
2
TODO
2
TODO
|
|
@ -3,6 +3,8 @@ SnapRAID TODO
|
|||
|
||||
This is the list of TODO items for SnapRAID.
|
||||
|
||||
+test with restore disk cp -a before and after rm
|
||||
|
||||
- v4.x
|
||||
|
||||
* Enable storing of creation time NTFS, crtime/birth time EXT4.
|
||||
|
|
|
|||
1
elem.c
1
elem.c
|
|
@ -523,6 +523,7 @@ 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->mapping = -1;
|
||||
tommy_list_init(&disk->filelist);
|
||||
tommy_list_init(&disk->deletedlist);
|
||||
|
|
|
|||
1
elem.h
1
elem.h
|
|
@ -273,6 +273,7 @@ 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 mapping; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
|
||||
|
||||
/**<
|
||||
|
|
|
|||
7
mingw.c
7
mingw.c
|
|
@ -1148,11 +1148,14 @@ int filephy(const char* file, struct stat* st, uint64_t* physical)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fstype(const char* path)
|
||||
int fsinfo(const char* path, int* has_persistent_inode)
|
||||
{
|
||||
(void)path;
|
||||
|
||||
return FSTYPE_UNKNOWN;
|
||||
/* all FAT/exFAT/NTFS when managed from Windows have persistent inodes */
|
||||
*has_persistent_inode = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef strerror
|
||||
|
|
|
|||
10
portable.h
10
portable.h
|
|
@ -181,15 +181,11 @@ int devuuid(uint64_t device, char* uuid, size_t size);
|
|||
*/
|
||||
int filephy(const char* path, struct stat* st, uint64_t* physical);
|
||||
|
||||
/* Types of filesystem */
|
||||
#define FSTYPE_UNKNOWN 0
|
||||
#define FSTYPE_FUSE 1
|
||||
|
||||
/**
|
||||
* Get the filesystem type.
|
||||
* Returns -1 on error or one of the FSTYPE define.
|
||||
* Checks if the underline filesystem support persistent inodes.
|
||||
* Returns -1 on error, 0 on success.
|
||||
*/
|
||||
int fstype(const char* path);
|
||||
int fsinfo(const char* path, int* has_persistent_inode);
|
||||
|
||||
/**
|
||||
* Initializes the system.
|
||||
|
|
|
|||
41
scan.c
41
scan.c
|
|
@ -277,10 +277,31 @@ 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 = st->st_ino;
|
||||
|
||||
/* first try finding by inode */
|
||||
file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
|
||||
file = 0;
|
||||
|
||||
/*
|
||||
* If the disk has persistent inodes, try a search by inode.
|
||||
*
|
||||
* For persistent inodes we mean inodes that keep their values when the filesystem
|
||||
* is unmounted and remounted. This don't always happen.
|
||||
*
|
||||
* Cases found are:
|
||||
* - Linux FUSE with exFAT driver from https://code.google.com/p/exfat/.
|
||||
* Inodes are reassigned at every mount restarting from 1 and incrementing.
|
||||
* As worse, the exFAT support in FUSE doesn't use subsecond precision in timestamps
|
||||
* making inode collision more easy (exFAT by design supports 10ms precision).
|
||||
* - 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
|
||||
* to use inodes at all.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
if (file) {
|
||||
/* check if the file is not changed */
|
||||
if (file->size == st->st_size
|
||||
|
|
@ -793,6 +814,8 @@ void state_scan(struct snapraid_state* state, int output)
|
|||
struct snapraid_disk* disk = i->data;
|
||||
struct snapraid_scan* scan;
|
||||
tommy_node* node;
|
||||
int ret;
|
||||
int has_persistent_inode;
|
||||
|
||||
scan = malloc_nofail(sizeof(struct snapraid_scan));
|
||||
scan->count_equal = 0;
|
||||
|
|
@ -809,6 +832,18 @@ void state_scan(struct snapraid_state* state, int output)
|
|||
|
||||
printf("Scanning disk %s...\n", disk->name);
|
||||
|
||||
/* check if the disk supports persistent inodes */
|
||||
ret = fsinfo(disk->dir, &has_persistent_inode);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error accessing disk '%s' to get filesystem info. %s.\n", disk->dir, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* mark the disk if required */
|
||||
if (!has_persistent_inode) {
|
||||
fprintf(stderr, "WARNING! Inodes use disabled for disk '%s' because they are not persistent.\n", disk->dir);
|
||||
disk->has_not_persistent_inodes = 1;
|
||||
}
|
||||
|
||||
scan_dir(scan, state, output, disk, disk->dir, "");
|
||||
|
||||
/* check for removed files */
|
||||
|
|
|
|||
20
state.c
20
state.c
|
|
@ -113,26 +113,6 @@ static void state_config_check(struct snapraid_state* state, const char* path)
|
|||
#endif
|
||||
|
||||
if (!state->opt.force_device) {
|
||||
int ret;
|
||||
|
||||
ret = fstype(disk->dir);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error accessing disk '%s' to get the filesystem type. %s.\n", disk->dir, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ret == FSTYPE_FUSE) {
|
||||
fprintf(stderr, "Disk '%s' has a filesystem managed by FUSE.\n", disk->dir);
|
||||
fprintf(stderr, "FUSE doesn't support persistent inodes, and it cannot be\n");
|
||||
fprintf(stderr, "used safely with SnapRAID.\n");
|
||||
|
||||
/* in "fix" we allow to continue anyway */
|
||||
if (strcmp(state->command, "fix") == 0) {
|
||||
fprintf(stderr, "You can '%s' anyway, using 'snapraid --force-device %s'.\n", state->command, state->command);
|
||||
}
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for(j=i->next;j!=0;j=j->next) {
|
||||
struct snapraid_disk* other = j->data;
|
||||
if (disk->device == other->device) {
|
||||
|
|
|
|||
18
unix.c
18
unix.c
|
|
@ -168,7 +168,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fstype(const char* path)
|
||||
int fsinfo(const char* path, int* has_persistent_inode)
|
||||
{
|
||||
/* statfs() is really not portable, and to limit possible incompatibility we limit it to Linux */
|
||||
/* for example, Solaris doesn't have the f_type field, BSD has it as "short" */
|
||||
|
|
@ -178,14 +178,26 @@ int fstype(const char* path)
|
|||
if (statfs(path, &st) != 0)
|
||||
return -1;
|
||||
|
||||
/* to get the fs type check "man stat" or "stat -f -t FILE" */
|
||||
|
||||
switch (st.f_type) {
|
||||
case 0x65735546 : return FSTYPE_FUSE;
|
||||
case 0x65735546 : /* FUSE, "fuseblk" in the stat command */
|
||||
case 0x4d44 : /* VFAT, "msdos" in the stat command */
|
||||
*has_persistent_inode = 0;
|
||||
break;
|
||||
default:
|
||||
/* by default assume yes */
|
||||
*has_persistent_inode = 1;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
(void)path;
|
||||
|
||||
/* by default assume yes */
|
||||
*has_persistent_inode = 1;
|
||||
#endif
|
||||
|
||||
return FSTYPE_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_init(void)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue