diff options
author | Jan Kara <jack@suse.cz> | 2016-03-09 22:54:00 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-03-09 22:54:00 -0500 |
commit | facab4d9711e7aa3532cb82643803e8f1b9518e8 (patch) | |
tree | 5c0f800db5aeb1fca6842c81cd3821ae847fcc0d | |
parent | 140a52508a68387e22486659ff9eaa89a24f6e40 (diff) |
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 <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | fs/ext4/extents.c | 11 | ||||
-rw-r--r-- | fs/ext4/indirect.c | 19 | ||||
-rw-r--r-- | fs/ext4/inode.c | 15 |
3 files changed, 36 insertions, 9 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 7858fc1d2501..2730039d4742 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4374,13 +4374,20 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
4374 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { | 4374 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { |
4375 | ext4_lblk_t hole_start, hole_len; | 4375 | ext4_lblk_t hole_start, hole_len; |
4376 | 4376 | ||
4377 | hole_start = map->m_lblk; | ||
4378 | hole_len = ext4_ext_determine_hole(inode, path, &hole_start); | ||
4377 | /* | 4379 | /* |
4378 | * put just found gap into cache to speed up | 4380 | * put just found gap into cache to speed up |
4379 | * subsequent requests | 4381 | * subsequent requests |
4380 | */ | 4382 | */ |
4381 | hole_start = map->m_lblk; | ||
4382 | hole_len = ext4_ext_determine_hole(inode, path, &hole_start); | ||
4383 | ext4_ext_put_gap_in_cache(inode, hole_start, hole_len); | 4383 | 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 | |||
4384 | goto out2; | 4391 | goto out2; |
4385 | } | 4392 | } |
4386 | 4393 | ||
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 1655ff195e0e..3027fa681de5 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
@@ -555,8 +555,23 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, | |||
555 | goto got_it; | 555 | goto got_it; |
556 | } | 556 | } |
557 | 557 | ||
558 | /* Next simple case - plain lookup or failed read of indirect block */ | 558 | /* Next simple case - plain lookup failed */ |
559 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO) | 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) | ||
560 | goto cleanup; | 575 | goto cleanup; |
561 | 576 | ||
562 | /* | 577 | /* |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 971892d7c213..1a156ec043a0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -455,13 +455,13 @@ static void ext4_map_blocks_es_recheck(handle_t *handle, | |||
455 | * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping | 455 | * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping |
456 | * based files | 456 | * based files |
457 | * | 457 | * |
458 | * On success, it returns the number of blocks being mapped or allocated. | 458 | * On success, it returns the number of blocks being mapped or allocated. if |
459 | * if create==0 and the blocks are pre-allocated and unwritten block, | 459 | * create==0 and the blocks are pre-allocated and unwritten, the resulting @map |
460 | * the result buffer head is unmapped. If the create ==1, it will make sure | 460 | * is marked as unwritten. If the create == 1, it will mark @map as mapped. |
461 | * the buffer head is mapped. | ||
462 | * | 461 | * |
463 | * It returns 0 if plain look up failed (blocks have not been allocated), in | 462 | * 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. | ||
465 | * | 465 | * |
466 | * It returns the error in case of allocation failure. | 466 | * It returns the error in case of allocation failure. |
467 | */ | 467 | */ |
@@ -504,6 +504,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
504 | retval = map->m_len; | 504 | retval = map->m_len; |
505 | map->m_len = retval; | 505 | map->m_len = retval; |
506 | } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) { | 506 | } 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; | ||
507 | retval = 0; | 512 | retval = 0; |
508 | } else { | 513 | } else { |
509 | BUG_ON(1); | 514 | BUG_ON(1); |