Skip to content

Commit facab4d

Browse files
jankaratytso
authored andcommitted
ext4: return hole from ext4_map_blocks()
Currently, ext4_map_blocks() just returns 0 when it finds a hole and allocation is not requested. However we have all the information available to tell how large the hole actually is and there are callers of ext4_map_blocks() which would save some block-by-block hole iteration if they knew this information. So fill in struct ext4_map_blocks even for holes with the information we have. We keep returning 0 for holes to maintain backward compatibility of the function. Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 140a525 commit facab4d

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

fs/ext4/extents.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4374,13 +4374,20 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
43744374
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
43754375
ext4_lblk_t hole_start, hole_len;
43764376

4377+
hole_start = map->m_lblk;
4378+
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
43774379
/*
43784380
* put just found gap into cache to speed up
43794381
* subsequent requests
43804382
*/
4381-
hole_start = map->m_lblk;
4382-
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
43834383
ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
4384+
4385+
/* Update hole_len to reflect hole size after map->m_lblk */
4386+
if (hole_start != map->m_lblk)
4387+
hole_len -= map->m_lblk - hole_start;
4388+
map->m_pblk = 0;
4389+
map->m_len = min_t(unsigned int, map->m_len, hole_len);
4390+
43844391
goto out2;
43854392
}
43864393

fs/ext4/indirect.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,23 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
555555
goto got_it;
556556
}
557557

558-
/* Next simple case - plain lookup or failed read of indirect block */
559-
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
558+
/* Next simple case - plain lookup failed */
559+
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
560+
unsigned epb = inode->i_sb->s_blocksize / sizeof(u32);
561+
int i;
562+
563+
/* Count number blocks in a subtree under 'partial' */
564+
count = 1;
565+
for (i = 0; partial + i != chain + depth - 1; i++)
566+
count *= epb;
567+
/* Fill in size of a hole we found */
568+
map->m_pblk = 0;
569+
map->m_len = min_t(unsigned int, map->m_len, count);
570+
goto cleanup;
571+
}
572+
573+
/* Failed read of indirect block */
574+
if (err == -EIO)
560575
goto cleanup;
561576

562577
/*

fs/ext4/inode.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -455,13 +455,13 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
455455
* Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
456456
* based files
457457
*
458-
* On success, it returns the number of blocks being mapped or allocated.
459-
* if create==0 and the blocks are pre-allocated and unwritten block,
460-
* the result buffer head is unmapped. If the create ==1, it will make sure
461-
* the buffer head is mapped.
458+
* On success, it returns the number of blocks being mapped or allocated. if
459+
* create==0 and the blocks are pre-allocated and unwritten, the resulting @map
460+
* is marked as unwritten. If the create == 1, it will mark @map as mapped.
462461
*
463462
* It returns 0 if plain look up failed (blocks have not been allocated), in
464-
* that case, buffer head is unmapped
463+
* that case, @map is returned as unmapped but we still do fill map->m_len to
464+
* indicate the length of a hole starting at map->m_lblk.
465465
*
466466
* It returns the error in case of allocation failure.
467467
*/
@@ -504,6 +504,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
504504
retval = map->m_len;
505505
map->m_len = retval;
506506
} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
507+
map->m_pblk = 0;
508+
retval = es.es_len - (map->m_lblk - es.es_lblk);
509+
if (retval > map->m_len)
510+
retval = map->m_len;
511+
map->m_len = retval;
507512
retval = 0;
508513
} else {
509514
BUG_ON(1);

0 commit comments

Comments
 (0)