From ef969263cdfc4896857520273482cd2356ae6c9b Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 23 Sep 2013 23:58:19 +0200 Subject: [PATCH] Fallback to FIBMAP if FIEMAP doesn't work. --- HISTORY | 4 ++-- unix.c | 45 +++++++++++++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/HISTORY b/HISTORY index 5da8642b..8f670868 100644 --- a/HISTORY +++ b/HISTORY @@ -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 diff --git a/unix.c b/unix.c index ba1dfbee..abda84b3 100644 --- a/unix.c +++ b/unix.c @@ -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;