Skip to content

Commit e861304

Browse files
achendertytso
authored andcommitted
ext4: add "punch hole" flag to ext4_map_blocks()
This patch adds a new flag to ext4_map_blocks() that specifies the given range of blocks should be punched out. Extents are first converted to uninitialized extents before they are punched out. Because punching a hole may require that the extent be split, it is possible that the splitting may need more blocks than are available. To deal with this, use of reserved blocks are enabled to allow the split to proceed. The routine then returns the number of blocks successfully punched out. [ext4 punch hole patch series 4/5 v7] Signed-off-by: Allison Henderson <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]> Reviewed-by: Mingming Cao <[email protected]>
1 parent d583fb8 commit e861304

File tree

1 file changed

+87
-11
lines changed

1 file changed

+87
-11
lines changed

fs/ext4/extents.c

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3298,15 +3298,19 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
32983298
ext4_fsblk_t newblock = 0;
32993299
int err = 0, depth, ret;
33003300
unsigned int allocated = 0;
3301+
unsigned int punched_out = 0;
3302+
unsigned int result = 0;
33013303
struct ext4_allocation_request ar;
33023304
ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
3305+
struct ext4_map_blocks punch_map;
33033306

33043307
ext_debug("blocks %u/%u requested for inode %lu\n",
33053308
map->m_lblk, map->m_len, inode->i_ino);
33063309
trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
33073310

33083311
/* check in cache */
3309-
if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
3312+
if (ext4_ext_in_cache(inode, map->m_lblk, &newex) &&
3313+
((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0)) {
33103314
if (!newex.ee_start_lo && !newex.ee_start_hi) {
33113315
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
33123316
/*
@@ -3371,16 +3375,84 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
33713375
ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
33723376
ee_block, ee_len, newblock);
33733377

3374-
/* Do not put uninitialized extent in the cache */
3375-
if (!ext4_ext_is_uninitialized(ex)) {
3376-
ext4_ext_put_in_cache(inode, ee_block,
3377-
ee_len, ee_start);
3378-
goto out;
3378+
if ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0) {
3379+
/*
3380+
* Do not put uninitialized extent
3381+
* in the cache
3382+
*/
3383+
if (!ext4_ext_is_uninitialized(ex)) {
3384+
ext4_ext_put_in_cache(inode, ee_block,
3385+
ee_len, ee_start);
3386+
goto out;
3387+
}
3388+
ret = ext4_ext_handle_uninitialized_extents(
3389+
handle, inode, map, path, flags,
3390+
allocated, newblock);
3391+
return ret;
33793392
}
3380-
ret = ext4_ext_handle_uninitialized_extents(handle,
3381-
inode, map, path, flags, allocated,
3382-
newblock);
3383-
return ret;
3393+
3394+
/*
3395+
* Punch out the map length, but only to the
3396+
* end of the extent
3397+
*/
3398+
punched_out = allocated < map->m_len ?
3399+
allocated : map->m_len;
3400+
3401+
/*
3402+
* Sense extents need to be converted to
3403+
* uninitialized, they must fit in an
3404+
* uninitialized extent
3405+
*/
3406+
if (punched_out > EXT_UNINIT_MAX_LEN)
3407+
punched_out = EXT_UNINIT_MAX_LEN;
3408+
3409+
punch_map.m_lblk = map->m_lblk;
3410+
punch_map.m_pblk = newblock;
3411+
punch_map.m_len = punched_out;
3412+
punch_map.m_flags = 0;
3413+
3414+
/* Check to see if the extent needs to be split */
3415+
if (punch_map.m_len != ee_len ||
3416+
punch_map.m_lblk != ee_block) {
3417+
3418+
ret = ext4_split_extent(handle, inode,
3419+
path, &punch_map, 0,
3420+
EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
3421+
EXT4_GET_BLOCKS_PRE_IO);
3422+
3423+
if (ret < 0) {
3424+
err = ret;
3425+
goto out2;
3426+
}
3427+
/*
3428+
* find extent for the block at
3429+
* the start of the hole
3430+
*/
3431+
ext4_ext_drop_refs(path);
3432+
kfree(path);
3433+
3434+
path = ext4_ext_find_extent(inode,
3435+
map->m_lblk, NULL);
3436+
if (IS_ERR(path)) {
3437+
err = PTR_ERR(path);
3438+
path = NULL;
3439+
goto out2;
3440+
}
3441+
3442+
depth = ext_depth(inode);
3443+
ex = path[depth].p_ext;
3444+
ee_len = ext4_ext_get_actual_len(ex);
3445+
ee_block = le32_to_cpu(ex->ee_block);
3446+
ee_start = ext4_ext_pblock(ex);
3447+
3448+
}
3449+
3450+
ext4_ext_mark_uninitialized(ex);
3451+
3452+
err = ext4_ext_remove_space(inode, map->m_lblk,
3453+
map->m_lblk + punched_out);
3454+
3455+
goto out2;
33843456
}
33853457
}
33863458

@@ -3525,7 +3597,11 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
35253597
}
35263598
trace_ext4_ext_map_blocks_exit(inode, map->m_lblk,
35273599
newblock, map->m_len, err ? err : allocated);
3528-
return err ? err : allocated;
3600+
3601+
result = (flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) ?
3602+
punched_out : allocated;
3603+
3604+
return err ? err : result;
35293605
}
35303606

35313607
void ext4_ext_truncate(struct inode *inode)

0 commit comments

Comments
 (0)