Reads the physical offset only for new files.

This commit is contained in:
Andrea Mazzoleni 2014-10-03 21:28:56 +02:00
parent 0f05d40f25
commit a0c6965959
4 changed files with 58 additions and 33 deletions

View file

@ -1339,7 +1339,7 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size)
return 0;
}
int filephy(const char* file, struct stat* st, uint64_t* physical)
int filephy(const char* file, uint64_t size, uint64_t* physical)
{
HANDLE h;
STARTING_VCN_INPUT_BUFFER svib;
@ -1348,9 +1348,11 @@ int filephy(const char* file, struct stat* st, uint64_t* physical)
BOOL ret;
DWORD n;
/* in Wine just uses the inode number because FSCTL_GET_RETRIVIAL_POINTERS is not supported */
(void)size;
/* in Wine FSCTL_GET_RETRIVIAL_POINTERS is not supported */
if (is_wine) {
*physical = st->st_ino;
*physical = FILEPHY_UNREPORTED_OFFSET;
return 0;
}

View file

@ -212,27 +212,32 @@ static inline int hardlink(const char* a, const char* b)
int devuuid(uint64_t device, char* uuid, size_t size);
/**
* Special value returned when the file doesn't have a real offset.
* For example, because it's stored in the NTFS MFT.
* Physical offset not yet read.
*/
#define FILEPHY_WITHOUT_OFFSET 0
#define FILEPHY_UNREAD_OFFSET 0
/**
* Special value returned when the filesystem doesn't report any offset for unknown reason.
*/
#define FILEPHY_UNREPORTED_OFFSET 1
/**
* Special value returned when the file doesn't have a real offset.
* For example, because it's stored in the NTFS MFT.
*/
#define FILEPHY_WITHOUT_OFFSET 2
/**
* Value indicating real offsets. All offsets greater or equal at this one are real.
*/
#define FILEPHY_REAL_OFFSET 2
#define FILEPHY_REAL_OFFSET 3
/**
* Get the physcal address of the specified file.
* This is expected to be just a hint and not necessarely correct or unique.
* Returns 0 on success.
*/
int filephy(const char* path, struct stat* st, uint64_t* physical);
int filephy(const char* path, uint64_t size, uint64_t* physical);
/**
* Checks if the underline filesystem support persistent inodes.
@ -251,7 +256,7 @@ uint64_t tick(void);
/**
* Initializes the system.
*/
void os_init(void);
void os_init(int opt);
/**
* Deintialize the system.

View file

@ -290,6 +290,28 @@ static int file_is_full_hashed_and_stable(struct snapraid_state* state, struct s
return 1;
}
static void scan_file_delayed_insert(struct snapraid_scan* scan, struct snapraid_file* file)
{
struct snapraid_state* state = scan->state;
struct snapraid_disk* disk = scan->disk;
/* if we sort for physical offsets we have to read them for the new files */
if (state->opt.force_order == SORT_PHYSICAL) {
char path_next[PATH_MAX];
pathprint(path_next, sizeof(path_next), "%s%s", disk->dir, file->sub);
if (filephy(path_next, file->size, &file->physical) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Error in getting the physical offset of file '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file);
}
/**
* Keeps the file as it's (or with only a name/inode modification).
*
@ -314,7 +336,7 @@ static void scan_file_keep(struct snapraid_scan* scan, struct snapraid_file* fil
tommy_list_remove_existing(&disk->filelist, &file->nodelist);
/* insert the file in the delayed block allocation */
tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file);
scan_file_delayed_insert(scan, file);
}
}
@ -789,7 +811,7 @@ static void scan_file(struct snapraid_scan* scan, int output, const char* sub, c
tommy_hashdyn_insert(&disk->stampset, &file->stampset, file, file_stamp_hash(file->size, file->mtime_sec, file->mtime_nsec));
/* insert the file in the delayed block allocation */
tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file);
scan_file_delayed_insert(scan, file);
}
/**
@ -1112,7 +1134,6 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con
if (type == 0) { /* REG */
if (filter_path(&state->filterlist, disk->name, sub_next) == 0) {
uint64_t physical;
/* late stat, if not yet called */
if (!st)
@ -1131,18 +1152,7 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con
}
#endif
if (state->opt.force_order == SORT_PHYSICAL) {
if (filephy(path_next, st, &physical) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Error in getting the physical offset of file '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
} else {
physical = 0;
}
scan_file(scan, output, sub_next, st, physical);
scan_file(scan, output, sub_next, st, FILEPHY_UNREAD_OFFSET);
processed = 1;
} else {
if (state->opt.verbose) {
@ -1326,6 +1336,9 @@ void state_scan(struct snapraid_state* state, int output)
uint64_t phy_last;
struct snapraid_file* phy_file_last;
if (!output)
printf("Mapping disk %s...\n", disk->name);
/* check for removed files */
node = disk->filelist;
while (node) {
@ -1402,20 +1415,24 @@ void state_scan(struct snapraid_state* state, int output)
/* insert all the new files, we insert them only after the deletion */
/* to reuse the just freed space */
/* also check if the physical offset reported are fakes or not */
node = scan->file_insert_list;
phy_count = 0;
phy_dup = 0;
phy_last = -1;
phy_last = FILEPHY_UNREAD_OFFSET;
phy_file_last = 0;
while (node) {
struct snapraid_file* file = node->data;
/* if the file is not empty, count duplicate physical offsets */
if (state->opt.force_order == SORT_PHYSICAL && file->size != 0) {
if (phy_file_last != 0 && file->physical == phy_last && phy_last != FILEPHY_WITHOUT_OFFSET) {
/* if verbose, prints the list of duplicates */
/* if they are supposed real offsets */
if (state->opt.verbose && phy_last != FILEPHY_UNREPORTED_OFFSET) {
if (phy_file_last != 0 && file->physical == phy_last
/* files without offset are expected to have duplicates */
&& phy_last != FILEPHY_WITHOUT_OFFSET
) {
/* if verbose, prints the list of duplicates real offsets */
/* other cases are for offsets not supported, so we don't need to report them file by file */
if (state->opt.verbose && phy_last >= FILEPHY_REAL_OFFSET) {
fprintf(stderr, "WARNING! Files '%s%s' and '%s%s' have the same physical offset %" PRId64 ".\n", disk->dir, phy_file_last->sub, disk->dir, file->sub, phy_last);
}
++phy_dup;

View file

@ -129,7 +129,7 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size)
}
#endif
int filephy(const char* path, struct stat* st, uint64_t* physical)
int filephy(const char* path, uint64_t size, uint64_t* physical)
{
#if HAVE_LINUX_FIEMAP_H
/* In Linux gets the real physical address of the file */
@ -162,7 +162,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical)
}
/* if the file is empty, FIBMAP doesn't work, and we don't even try to use it */
if (st->st_size == 0) {
if (size == 0) {
*physical = FILEPHY_WITHOUT_OFFSET;
if (close(f) == -1)
return -1;
@ -199,7 +199,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical)
*physical = FILEPHY_UNREPORTED_OFFSET;
(void)path; /* not used here */
(void)st;
(void)size;
#endif
return 0;
@ -267,8 +267,9 @@ uint64_t tick(void)
#endif
}
void os_init(void)
void os_init(int opt)
{
(void)opt;
}
void os_done(void)