Marks FUSE filesystem as with not persistent inodes,

disabling inode use in such case.
This commit is contained in:
Andrea Mazzoleni 2013-08-27 23:02:12 +02:00
parent 4fb96c0dec
commit e4e13a669b
8 changed files with 65 additions and 35 deletions

2
TODO
View file

@ -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
View file

@ -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
View file

@ -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. */
/**<

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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)