mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 04:29:11 -04:00
ext4: factor out ext4_map_create_blocks() to allocate new blocks
Factor out a common helper ext4_map_create_blocks() from ext4_map_blocks() to do a real blocks allocation, no logic changes. [ Note: this first patch of a ten patch series named "v3: simplify the counting and management of delalloc reserved blocks". The link to the v1 and v2 patch series are below. -- TYT ] Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20240802115120.362902-1-yi.zhang@huaweicloud.com # v2 of patch series Link: https://patch.msgid.link/20240601034149.2169771-1-yi.zhang@huaweicloud.com # v1 of the patch series Link: https://patch.msgid.link/20240813123452.2824659-2-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
157
fs/ext4/inode.c
157
fs/ext4/inode.c
@@ -482,6 +482,86 @@ static int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags)
|
||||
{
|
||||
struct extent_status es;
|
||||
unsigned int status;
|
||||
int err, retval = 0;
|
||||
|
||||
/*
|
||||
* Here we clear m_flags because after allocating an new extent,
|
||||
* it will be set again.
|
||||
*/
|
||||
map->m_flags &= ~EXT4_MAP_FLAGS;
|
||||
|
||||
/*
|
||||
* We need to check for EXT4 here because migrate could have
|
||||
* changed the inode type in between.
|
||||
*/
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, flags);
|
||||
} else {
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, flags);
|
||||
|
||||
/*
|
||||
* We allocated new blocks which will result in i_data's
|
||||
* format changing. Force the migrate to fail by clearing
|
||||
* migrate flags.
|
||||
*/
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_NEW)
|
||||
ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
|
||||
}
|
||||
if (retval <= 0)
|
||||
return retval;
|
||||
|
||||
if (unlikely(retval != map->m_len)) {
|
||||
ext4_warning(inode->i_sb,
|
||||
"ES len assertion failed for inode %lu: "
|
||||
"retval %d != map->m_len %d",
|
||||
inode->i_ino, retval, map->m_len);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to zeroout blocks before inserting them into extent
|
||||
* status tree. Otherwise someone could look them up there and
|
||||
* use them before they are really zeroed. We also have to
|
||||
* unmap metadata before zeroing as otherwise writeback can
|
||||
* overwrite zeros with stale data from block device.
|
||||
*/
|
||||
if (flags & EXT4_GET_BLOCKS_ZERO &&
|
||||
map->m_flags & EXT4_MAP_MAPPED && map->m_flags & EXT4_MAP_NEW) {
|
||||
err = ext4_issue_zeroout(inode, map->m_lblk, map->m_pblk,
|
||||
map->m_len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the extent has been zeroed out, we don't need to update
|
||||
* extent status tree.
|
||||
*/
|
||||
if (flags & EXT4_GET_BLOCKS_PRE_IO &&
|
||||
ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
|
||||
if (ext4_es_is_written(&es))
|
||||
return retval;
|
||||
}
|
||||
|
||||
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
|
||||
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
|
||||
if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
|
||||
!(status & EXTENT_STATUS_WRITTEN) &&
|
||||
ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk,
|
||||
map->m_lblk + map->m_len - 1))
|
||||
status |= EXTENT_STATUS_DELAYED;
|
||||
|
||||
ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
|
||||
map->m_pblk, status);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ext4_map_blocks() function tries to look up the requested blocks,
|
||||
* and returns if the blocks are already mapped.
|
||||
@@ -630,12 +710,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Here we clear m_flags because after allocating an new extent,
|
||||
* it will be set again.
|
||||
*/
|
||||
map->m_flags &= ~EXT4_MAP_FLAGS;
|
||||
|
||||
/*
|
||||
* New blocks allocate and/or writing to unwritten extent
|
||||
* will possibly result in updating i_data, so we take
|
||||
@@ -643,76 +717,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
* with create == 1 flag.
|
||||
*/
|
||||
down_write(&EXT4_I(inode)->i_data_sem);
|
||||
|
||||
/*
|
||||
* We need to check for EXT4 here because migrate
|
||||
* could have changed the inode type in between
|
||||
*/
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, flags);
|
||||
} else {
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, flags);
|
||||
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {
|
||||
/*
|
||||
* We allocated new blocks which will result in
|
||||
* i_data's format changing. Force the migrate
|
||||
* to fail by clearing migrate flags
|
||||
*/
|
||||
ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval > 0) {
|
||||
unsigned int status;
|
||||
|
||||
if (unlikely(retval != map->m_len)) {
|
||||
ext4_warning(inode->i_sb,
|
||||
"ES len assertion failed for inode "
|
||||
"%lu: retval %d != map->m_len %d",
|
||||
inode->i_ino, retval, map->m_len);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to zeroout blocks before inserting them into extent
|
||||
* status tree. Otherwise someone could look them up there and
|
||||
* use them before they are really zeroed. We also have to
|
||||
* unmap metadata before zeroing as otherwise writeback can
|
||||
* overwrite zeros with stale data from block device.
|
||||
*/
|
||||
if (flags & EXT4_GET_BLOCKS_ZERO &&
|
||||
map->m_flags & EXT4_MAP_MAPPED &&
|
||||
map->m_flags & EXT4_MAP_NEW) {
|
||||
ret = ext4_issue_zeroout(inode, map->m_lblk,
|
||||
map->m_pblk, map->m_len);
|
||||
if (ret) {
|
||||
retval = ret;
|
||||
goto out_sem;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the extent has been zeroed out, we don't need to update
|
||||
* extent status tree.
|
||||
*/
|
||||
if ((flags & EXT4_GET_BLOCKS_PRE_IO) &&
|
||||
ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
|
||||
if (ext4_es_is_written(&es))
|
||||
goto out_sem;
|
||||
}
|
||||
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
|
||||
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
|
||||
if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
|
||||
!(status & EXTENT_STATUS_WRITTEN) &&
|
||||
ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk,
|
||||
map->m_lblk + map->m_len - 1))
|
||||
status |= EXTENT_STATUS_DELAYED;
|
||||
ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
|
||||
map->m_pblk, status);
|
||||
}
|
||||
|
||||
out_sem:
|
||||
retval = ext4_map_create_blocks(handle, inode, map, flags);
|
||||
up_write((&EXT4_I(inode)->i_data_sem));
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
|
||||
ret = check_block_validity(inode, map);
|
||||
|
||||
Reference in New Issue
Block a user