Fallback to FIBMAP if FIEMAP doesn't work.

This commit is contained in:
Andrea Mazzoleni 2013-09-23 23:58:19 +02:00
parent 90b4efdbba
commit ef969263cd
2 changed files with 35 additions and 14 deletions

View file

@ -4,8 +4,8 @@ SnapRAID HISTORY
4.1 2013/9
==========
* If the underline filesystem doesn't support the FIEMAP command,
automatically fallback to use the inode number for sorting files.
This happens with reiserfs and FUSE in Linux.
automatically fallback to use FIBMAP and then the inode number for sorting
files.
* Fixes the import of content files from previous version of SnapRAID that
are the result of an incomplete sync.
* Added a new -C, --gen-conf option to generate a dummy configuration

45
unix.c
View file

@ -129,43 +129,64 @@ int filephy(const char* path, struct stat* st, uint64_t* physical)
/* In Linux gets the real physical address of the file */
/* Note that FIEMAP doesn't require root permission */
int f;
struct {
struct fiemap fiemap;
struct fiemap_extent extent;
} fm;
unsigned int blknum;
f = open(path, O_RDONLY);
if (f == -1) {
return -1;
}
/* first try with FIEMAP */
memset(&fm, 0, sizeof(fm));
fm.fiemap.fm_start = 0;
fm.fiemap.fm_length = ~0ULL;
fm.fiemap.fm_flags = FIEMAP_FLAG_SYNC; /* required to ensure that just created files report a valid address and not 0 */
fm.fiemap.fm_extent_count = 1; /* we are interested only at the first block */
if (ioctl(f, FS_IOC_FIEMAP, &fm) == -1) {
/* if the underline filesystem doesn't support FS_IOC_FIEMAP */
/* fallback to use the inode */
if (errno == ENOTSUP) {
close(f);
*physical = st->st_ino;
return 0;
}
if (ioctl(f, FS_IOC_FIEMAP, &fm) == 0) {
*physical = fm.fiemap.fm_extents[0].fe_physical;
if (close(f) == -1)
return -1;
return 0;
}
/* if it's an unexpected error fails */
if (errno != ENOTSUP) {
close(f);
return -1;
}
*physical = fm.fiemap.fm_extents[0].fe_physical;
/* if empty, FIBMAP doesn't work */
if (st->st_size == 0) {
*physical = 0;
if (close(f) == -1)
return -1;
return 0;
}
if (close(f) == -1) {
/* then try with FIBMAP */
blknum = 0; /* first block */
if (ioctl(f, FIBMAP, &blknum) == 0) {
*physical = blknum;
if (close(f) == -1)
return -1;
return 0;
}
/* if it's an unexpected error fails */
if (errno != ENOTSUP && errno != EPERM) {
close(f);
return -1;
}
(void)st; /* not used here */
/* otherwise uses the inode */
*physical = st->st_ino;
if (close(f) == -1)
return -1;
#else
/* In a generic Unix uses the inode as fake physical address */
*physical = st->st_ino;