Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion fiemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,14 @@ struct fiemap_extent *get_extent(struct fiemap *fiemap, size_t loff,
{
struct fiemap_extent *extent;
size_t ext_end_off;
unsigned int start = 0;

for (unsigned int i = 0; i < fiemap->fm_mapped_extents; i++) {
/* Use hint if it doesn't point past the target offset */
if (index && *index < fiemap->fm_mapped_extents &&
fiemap->fm_extents[*index].fe_logical <= loff)
start = *index;

for (unsigned int i = start; i < fiemap->fm_mapped_extents; i++) {
extent = &fiemap->fm_extents[i];
ext_end_off = extent->fe_logical + extent->fe_length - 1;
if (ext_end_off < loff)
Expand Down
5 changes: 3 additions & 2 deletions fiemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
/*
* Given a filled fiemap structure, extract the struct fiemap_extent
* which covers the loff offset.
* If index is not NULL, then it will be filled with the extent's index.
* If no extent is found, returns NULL and index is garbage.
* If index is not NULL, it is used as a hint to start the search and
* updated with the found extent's index.
* If no extent is found, returns NULL and index is unchanged.
* The returned value must not be used after fiemap is freed, and must not
* be freed directly either.
*/
Expand Down
17 changes: 10 additions & 7 deletions file_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct scan_ctxt {
struct fiemap *fiemap;
struct running_checksum *file_csum;
struct running_checksum *extent_csum;
unsigned int extent_hint; /* cached index for get_extent lookups */
};

/*
Expand Down Expand Up @@ -776,12 +777,13 @@ static int add_block_hash(struct hashes *hashes,
/*
* Check if the area should be scanned.
*/
static bool is_area_ignored(struct fiemap *fiemap, size_t start, size_t len)
static bool is_area_ignored(struct fiemap *fiemap, size_t start, size_t len,
unsigned int *extent_hint)
{
size_t end = start + len;
struct fiemap_extent *current_extent;
while (start < end) {
current_extent = get_extent(fiemap, start, NULL);
current_extent = get_extent(fiemap, start, extent_hint);

/* File changed since we fiemap */
if (!current_extent)
Expand All @@ -800,9 +802,10 @@ static bool is_area_ignored(struct fiemap *fiemap, size_t start, size_t len)
/*
* Check if the block starting at off should be ignored.
*/
static inline bool is_block_ignored(struct fiemap *fiemap, size_t off)
static inline bool is_block_ignored(struct fiemap *fiemap, size_t off,
unsigned int *extent_hint)
{
return is_area_ignored(fiemap, off, blocksize);
return is_area_ignored(fiemap, off, blocksize, extent_hint);
}

static int process_block(char *buf, unsigned int bsize,
Expand Down Expand Up @@ -830,7 +833,7 @@ static ssize_t process_blocks(struct scan_ctxt *ctxt, struct buffer *buffer,
return buffer->dl_len;

for (unsigned int i = 0; i < nb_blocks; i++) {
if (!is_block_ignored(ctxt->fiemap, curr_file_off) &&
if (!is_block_ignored(ctxt->fiemap, curr_file_off, &ctxt->extent_hint) &&
!(options.skip_zeroes &&
is_block_zeroed(buffer->buf + buffer->dl_offset))) {
ret = process_block(buffer->buf + i * blocksize,
Expand Down Expand Up @@ -885,7 +888,7 @@ static int process_extents(struct scan_ctxt *ctxt, struct buffer *buffer,
size_t to_add;

while (file_off < ctxt->off + bytes) {
extent = get_extent(ctxt->fiemap, file_off, NULL);
extent = get_extent(ctxt->fiemap, file_off, &ctxt->extent_hint);
if (!extent) {
eprintf("process_extents: unable to get extent\n");

Expand Down Expand Up @@ -955,7 +958,7 @@ static int fill_buffer(struct scan_ctxt *ctxt, struct buffer *buffer)
* The entire buffer could be ignored. Let's fast forward
* and mark the buffer as faked
*/
if (is_area_ignored(ctxt->fiemap, ctxt->off, buffer->size)
if (is_area_ignored(ctxt->fiemap, ctxt->off, buffer->size, &ctxt->extent_hint)
&& ctxt->off + buffer->size <= ctxt->filesize) {
memset(buffer->buf, 0, buffer->size);
buffer->dl_len = buffer->size;
Expand Down