diff --git a/HISTORY b/HISTORY index c12e5306..4a171eba 100644 --- a/HISTORY +++ b/HISTORY @@ -14,8 +14,10 @@ SnapRAID HISTORY 4.1 2013/9 (BETA) ================= * If the underline filesystem doesn't support the FIEMAP command, - fallback to use the inode number for sorting files. - This happens with reiserfs 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 file from the info in the content file. Just in case that you lose everything, except the content file. @@ -38,7 +40,7 @@ SnapRAID HISTORY This happens only if the file has the same path, size and timestamp at nanosecond precision. * Added a hash seed to make harder intentional collision attacks. - * When insering files for the first time, sort them by their physical + * When inserting files for the first time, sort them by their physical address to improve read performance. * Optimized the cache use for the all the RAID computations. This improves a lot the RAID performance. diff --git a/elem.c b/elem.c index 75834998..e3735763 100644 --- a/elem.c +++ b/elem.c @@ -583,7 +583,7 @@ int disk_is_empty(struct snapraid_disk* disk, block_off_t blockmax) /* if there is a deleted block, the disk is not empty */ return 0; default: - fprintf(stderr, "Internal incosistency for used block in disk '%s' without files\n", disk->name); + fprintf(stderr, "Internal inconsistency for used block in disk '%s' without files\n", disk->name); exit(EXIT_FAILURE); } } diff --git a/rehash.c b/rehash.c index c557b507..261d7e2b 100644 --- a/rehash.c +++ b/rehash.c @@ -66,7 +66,7 @@ void state_rehash(struct snapraid_state* state) } if (info_get_rehash(info)) { - fprintf(stderr, "Internal incosistency for a rehash already in progress\n"); + fprintf(stderr, "Internal inconsistency for a rehash already in progress\n"); exit(EXIT_FAILURE); } diff --git a/scan.c b/scan.c index 34c51eb2..8aa58abc 100644 --- a/scan.c +++ b/scan.c @@ -919,6 +919,8 @@ void state_scan(struct snapraid_state* state, int output) } /* sort the files before inserting them */ + /* we use a stable sort to ensure that if the reported physical offset/inode */ + /* are always 0, we keep at least the directory order */ switch (state->opt.force_order) { case SORT_PHYSICAL : tommy_list_sort(&scan->file_insert_list, file_physical_compare); diff --git a/state.c b/state.c index 4c1e4caf..ac5cc3e2 100644 --- a/state.c +++ b/state.c @@ -770,7 +770,7 @@ static void state_map(struct snapraid_state* state) } if (j==0) { - fprintf(stderr, "Internal incosistency for mapping '%s'\n", map->name); + fprintf(stderr, "Internal inconsistency for mapping '%s'\n", map->name); exit(EXIT_FAILURE); } @@ -1075,7 +1075,7 @@ static void state_read_text(struct snapraid_state* state, const char* path, STRE rehash = 1; if (state->prevhash == HASH_UNDEFINED) { - fprintf(stderr, "Internal incosistency for missing previous checksum in '%s' at line %u\n", path, line); + fprintf(stderr, "Internal inconsistency for missing previous checksum in '%s' at line %u\n", path, line); exit(EXIT_FAILURE); } } else { @@ -1115,10 +1115,6 @@ static void state_read_text(struct snapraid_state* state, const char* path, STRE deleted->block.parity_pos = v_pos; - /* keep track of the max block number used in parity */ - if (v_pos + 1 > blockmax) - blockmax = v_pos + 1; - /* read the hash */ c = sgetc(f); if (c != ' ') { @@ -1638,7 +1634,7 @@ static void state_read_text(struct snapraid_state* state, const char* path, STRE /* check that the stored parity size matches the loaded state */ if (blockmax != parity_size(state)) { - fprintf(stderr, "Internal incosistency in parity size in '%s' at line %u\n", path, line); + fprintf(stderr, "Internal inconsistency in parity size in '%s' at line %u\n", path, line); exit(EXIT_FAILURE); } state->loaded_blockmax = blockmax; @@ -1746,7 +1742,7 @@ static void state_write_text(struct snapraid_state* state, STREAM* f) /* find the disk for this mapping */ disk = find_disk(state, map->name); if (!disk) { - fprintf(stderr, "Internal incosistency for unmapped disk '%s'\n", map->name); + fprintf(stderr, "Internal inconsistency for unmapped disk '%s'\n", map->name); exit(EXIT_FAILURE); } @@ -2305,7 +2301,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST if (rehash && state->prevhash == HASH_UNDEFINED) { decoding_error(path, f); - fprintf(stderr, "Internal incosistency for missing previous checksum!\n"); + fprintf(stderr, "Internal inconsistency for missing previous checksum!\n"); exit(EXIT_FAILURE); } @@ -2322,13 +2318,13 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST if (position_has_any_hash(state, v_pos)) { if (!info) { decoding_error(path, f); - fprintf(stderr, "Internal incosistency for missing info!\n"); + fprintf(stderr, "Internal inconsistency for missing info!\n"); exit(EXIT_FAILURE); } } else { if (info) { decoding_error(path, f); - fprintf(stderr, "Internal incosistency for unexpected info!\n"); + fprintf(stderr, "Internal inconsistency for unexpected info!\n"); exit(EXIT_FAILURE); } } @@ -2689,7 +2685,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST /* check that the stored parity size matches the loaded state */ if (blockmax != parity_size(state)) { - fprintf(stderr, "Internal incosistency in parity size in '%s' at offset %"PRIi64"\n", path, stell(f)); + fprintf(stderr, "Internal inconsistency in parity size in '%s' at offset %"PRIi64"\n", path, stell(f)); exit(EXIT_FAILURE); } state->loaded_blockmax = blockmax; @@ -2810,7 +2806,7 @@ static void state_write_binary(struct snapraid_state* state, STREAM* f) /* find the disk for this mapping */ disk = find_disk(state, map->name); if (!disk) { - fprintf(stderr, "Internal incosistency for unmapped disk '%s'\n", map->name); + fprintf(stderr, "Internal inconsistency for unmapped disk '%s'\n", map->name); exit(EXIT_FAILURE); } diff --git a/unix.c b/unix.c index ba1dfbee..f60b9d07 100644 --- a/unix.c +++ b/unix.c @@ -129,43 +129,57 @@ 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 */ + /* if works for ext2, ext3, ext4, xfs */ 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; - } - - close(f); - return -1; + if (ioctl(f, FS_IOC_FIEMAP, &fm) == 0) { + *physical = fm.fiemap.fm_extents[0].fe_physical; + if (close(f) == -1) + return -1; + return 0; } - *physical = fm.fiemap.fm_extents[0].fe_physical; - - if (close(f) == -1) { - return -1; + /* if empty, FIBMAP doesn't work */ + if (st->st_size == 0) { + *physical = 0; + if (close(f) == -1) + return -1; + return 0; } - (void)st; /* not used here */ + /* then try with FIBMAP */ + /* it works for jfs, reiserfs, ntfs-3g */ + /* in exfat it always returns 0, that it's anyway better than the fake inodes */ + blknum = 0; /* first block */ + if (ioctl(f, FIBMAP, &blknum) == 0) { + *physical = blknum; + if (close(f) == -1) + return -1; + return 0; + } + + /* otherwise don't use anything, and keep the existing order */ + /* at now this should happen only for vfat */ + /* and it's surely better than using fake inodes */ + *physical = 0; + if (close(f) == -1) + return -1; #else /* In a generic Unix uses the inode as fake physical address */ *physical = st->st_ino;