[PATCH v3 05/13] btrfs: fiemap: return extent physical size

From: Sweet Tea Dorminy
Date: Wed Apr 03 2024 - 03:34:58 EST


Now that fiemap allows returning extent physical size, make btrfs return
the appropriate extent's actual disk size.

Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx>
---
fs/btrfs/extent_io.c | 70 ++++++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index e9df670ef7d2..b631f387cc3c 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2506,7 +2506,8 @@ int try_release_extent_mapping(struct page *page, gfp_t mask)
struct btrfs_fiemap_entry {
u64 offset;
u64 phys;
- u64 len;
+ u64 log_len;
+ u64 phys_len;
u32 flags;
};

@@ -2564,7 +2565,8 @@ struct fiemap_cache {
/* Fields for the cached extent (unsubmitted, not ready, extent). */
u64 offset;
u64 phys;
- u64 len;
+ u64 log_len;
+ u64 phys_len;
u32 flags;
bool cached;
};
@@ -2577,8 +2579,8 @@ static int flush_fiemap_cache(struct fiemap_extent_info *fieinfo,
int ret;

ret = fiemap_fill_next_extent(fieinfo, entry->offset,
- entry->phys, entry->len, 0,
- entry->flags);
+ entry->phys, entry->log_len,
+ entry->phys_len, entry->flags);
/*
* Ignore 1 (reached max entries) because we keep track of that
* ourselves in emit_fiemap_extent().
@@ -2603,7 +2605,8 @@ static int flush_fiemap_cache(struct fiemap_extent_info *fieinfo,
*/
static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
struct fiemap_cache *cache,
- u64 offset, u64 phys, u64 len, u32 flags)
+ u64 offset, u64 phys, u64 log_len,
+ u64 phys_len, u32 flags)
{
struct btrfs_fiemap_entry *entry;
u64 cache_end;
@@ -2611,6 +2614,9 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
/* Set at the end of extent_fiemap(). */
ASSERT((flags & FIEMAP_EXTENT_LAST) == 0);

+ /* We always set the correct physical length. */
+ flags |= FIEMAP_EXTENT_HAS_PHYS_LEN;
+
if (!cache->cached)
goto assign;

@@ -2646,7 +2652,7 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
* or equals to what we have in cache->offset. We deal with this as
* described below.
*/
- cache_end = cache->offset + cache->len;
+ cache_end = cache->offset + cache->log_len;
if (cache_end > offset) {
if (offset == cache->offset) {
/*
@@ -2670,10 +2676,10 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
* where a previously found file extent item was split
* due to an ordered extent completing.
*/
- cache->len = offset - cache->offset;
+ cache->log_len = offset - cache->offset;
goto emit;
} else {
- const u64 range_end = offset + len;
+ const u64 range_end = offset + log_len;

/*
* The offset of the file extent item we have just found
@@ -2706,11 +2712,13 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
if (range_end <= cache_end)
return 0;

- if (!(flags & (FIEMAP_EXTENT_DATA_COMPRESSED | FIEMAP_EXTENT_DELALLOC)))
+ if (!(flags & (FIEMAP_EXTENT_DATA_COMPRESSED | FIEMAP_EXTENT_DELALLOC))) {
phys += cache_end - offset;
+ phys_len -= cache_end - offset;
+ }

offset = cache_end;
- len = range_end - cache_end;
+ log_len = range_end - cache_end;
goto emit;
}
}
@@ -2720,15 +2728,17 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
* 1) Their logical addresses are continuous
*
* 2) Their physical addresses are continuous
- * So truly compressed (physical size smaller than logical size)
- * extents won't get merged with each other
*
* 3) Share same flags
+ *
+ * 4) Not compressed
*/
- if (cache->offset + cache->len == offset &&
- cache->phys + cache->len == phys &&
- cache->flags == flags) {
- cache->len += len;
+ if (cache->offset + cache->log_len == offset &&
+ cache->phys + cache->log_len == phys &&
+ cache->flags == flags &&
+ !(flags & FIEMAP_EXTENT_DATA_COMPRESSED)) {
+ cache->log_len += log_len;
+ cache->phys_len += phys_len;
return 0;
}

@@ -2745,7 +2755,7 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
* to miss it.
*/
entry = &cache->entries[cache->entries_size - 1];
- cache->next_search_offset = entry->offset + entry->len;
+ cache->next_search_offset = entry->offset + entry->log_len;
cache->cached = false;

return BTRFS_FIEMAP_FLUSH_CACHE;
@@ -2754,7 +2764,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
entry = &cache->entries[cache->entries_pos];
entry->offset = cache->offset;
entry->phys = cache->phys;
- entry->len = cache->len;
+ entry->log_len = cache->log_len;
+ entry->phys_len = cache->phys_len;
entry->flags = cache->flags;
cache->entries_pos++;
cache->extents_mapped++;
@@ -2767,7 +2778,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
cache->cached = true;
cache->offset = offset;
cache->phys = phys;
- cache->len = len;
+ cache->log_len = log_len;
+ cache->phys_len = phys_len;
cache->flags = flags;

return 0;
@@ -2793,7 +2805,8 @@ static int emit_last_fiemap_cache(struct fiemap_extent_info *fieinfo,
return 0;

ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
- cache->len, 0, cache->flags);
+ cache->log_len, cache->phys_len,
+ cache->flags);
cache->cached = false;
if (ret > 0)
ret = 0;
@@ -2987,13 +3000,15 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
}
ret = emit_fiemap_extent(fieinfo, cache, prealloc_start,
disk_bytenr + extent_offset,
- prealloc_len, prealloc_flags);
+ prealloc_len, prealloc_len,
+ prealloc_flags);
if (ret)
return ret;
extent_offset += prealloc_len;
}

ret = emit_fiemap_extent(fieinfo, cache, delalloc_start, 0,
+ delalloc_end + 1 - delalloc_start,
delalloc_end + 1 - delalloc_start,
FIEMAP_EXTENT_DELALLOC |
FIEMAP_EXTENT_UNKNOWN);
@@ -3034,7 +3049,8 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
}
ret = emit_fiemap_extent(fieinfo, cache, prealloc_start,
disk_bytenr + extent_offset,
- prealloc_len, prealloc_flags);
+ prealloc_len, prealloc_len,
+ prealloc_flags);
if (ret)
return ret;
}
@@ -3180,6 +3196,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
u64 extent_offset = 0;
u64 extent_gen;
u64 disk_bytenr = 0;
+ u64 disk_size = 0;
u64 flags = 0;
int extent_type;
u8 compression;
@@ -3242,7 +3259,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
flags |= FIEMAP_EXTENT_DATA_INLINE;
flags |= FIEMAP_EXTENT_NOT_ALIGNED;
ret = emit_fiemap_extent(fieinfo, &cache, key.offset, 0,
- extent_len, flags);
+ extent_len, extent_len, flags);
} else if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
ret = fiemap_process_hole(inode, fieinfo, &cache,
&delalloc_cached_state,
@@ -3257,6 +3274,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
backref_ctx, 0, 0, 0,
key.offset, extent_end - 1);
} else {
+ disk_size = btrfs_file_extent_disk_num_bytes(leaf, ei);
/* We have a regular extent. */
if (fieinfo->fi_extents_max) {
ret = btrfs_is_data_extent_shared(inode,
@@ -3271,7 +3289,9 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,

ret = emit_fiemap_extent(fieinfo, &cache, key.offset,
disk_bytenr + extent_offset,
- extent_len, flags);
+ extent_len,
+ disk_size - extent_offset,
+ flags);
}

if (ret < 0) {
@@ -3309,7 +3329,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
prev_extent_end = range_end;
}

- if (cache.cached && cache.offset + cache.len >= last_extent_end) {
+ if (cache.cached && cache.offset + cache.log_len >= last_extent_end) {
const u64 i_size = i_size_read(&inode->vfs_inode);

if (prev_extent_end < i_size) {
--
2.43.0