1 ext4: return hole from ext4_map_blocks()
3 From: Jan Kara <jack@suse.cz>
5 Currently, ext4_map_blocks() just returns 0 when it finds a hole and
6 allocation is not requested. However we have all the information
7 available to tell how large the hole actually is and there are callers
8 of ext4_map_blocks() which would save some block-by-block hole iteration
9 if they knew this information. So fill in struct ext4_map_blocks even
10 for holes with the information we have. We keep returning 0 for holes to
11 maintain backward compatibility of the function.
13 Signed-off-by: Jan Kara <jack@suse.cz>
14 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
16 fs/ext4/extents.c | 11 +++++++++--
17 fs/ext4/indirect.c | 19 +++++++++++++++++--
18 fs/ext4/inode.c | 15 ++++++++++-----
19 3 files changed, 36 insertions(+), 9 deletions(-)
21 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
22 index 2dc6261e247f..0e924ca153f9 100644
23 --- a/fs/ext4/extents.c
24 +++ b/fs/ext4/extents.c
25 @@ -4380,13 +4380,20 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
26 if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
27 ext4_lblk_t hole_start, hole_len;
29 + hole_start = map->m_lblk;
30 + hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
32 * put just found gap into cache to speed up
35 - hole_start = map->m_lblk;
36 - hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
37 ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
39 + /* Update hole_len to reflect hole size after map->m_lblk */
40 + if (hole_start != map->m_lblk)
41 + hole_len -= map->m_lblk - hole_start;
43 + map->m_len = min_t(unsigned int, map->m_len, hole_len);
48 diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
49 index 355ef9c36c87..7544d1047dc6 100644
50 --- a/fs/ext4/indirect.c
51 +++ b/fs/ext4/indirect.c
52 @@ -555,8 +555,23 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
56 - /* Next simple case - plain lookup or failed read of indirect block */
57 - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
58 + /* Next simple case - plain lookup failed */
59 + if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
60 + unsigned epb = inode->i_sb->s_blocksize / sizeof(u32);
63 + /* Count number blocks in a subtree under 'partial' */
65 + for (i = 0; partial + i != chain + depth - 1; i++)
67 + /* Fill in size of a hole we found */
69 + map->m_len = min_t(unsigned int, map->m_len, count);
73 + /* Failed read of indirect block */
78 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
79 index 9cc57c3b4661..ef590607b4a7 100644
82 @@ -458,13 +458,13 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
83 * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
86 - * On success, it returns the number of blocks being mapped or allocated.
87 - * if create==0 and the blocks are pre-allocated and unwritten block,
88 - * the result buffer head is unmapped. If the create ==1, it will make sure
89 - * the buffer head is mapped.
90 + * On success, it returns the number of blocks being mapped or allocated. if
91 + * create==0 and the blocks are pre-allocated and unwritten, the resulting @map
92 + * is marked as unwritten. If the create == 1, it will mark @map as mapped.
94 * It returns 0 if plain look up failed (blocks have not been allocated), in
95 - * that case, buffer head is unmapped
96 + * that case, @map is returned as unmapped but we still do fill map->m_len to
97 + * indicate the length of a hole starting at map->m_lblk.
99 * It returns the error in case of allocation failure.
101 @@ -507,6 +507,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
104 } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
106 + retval = es.es_len - (map->m_lblk - es.es_lblk);
107 + if (retval > map->m_len)
108 + retval = map->m_len;
109 + map->m_len = retval;
117 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
118 the body of a message to majordomo@vger.kernel.org
119 More majordomo info at http://vger.kernel.org/majordomo-info.html