aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2013-04-09 22:11:22 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-09 22:11:22 -0400
commit27dd43854227bb0e6ab70129bd21b60d396db2e7 (patch)
tree14e490b9d0ac63583849c4cad4b3ad0123902c3a /fs/ext4/extents.c
parentf45a5ef91bef7e02149a216ed6dc3fcdd8b38268 (diff)
ext4: introduce reserved space
Currently in ENOSPC condition when writing into unwritten space, or punching a hole, we might need to split the extent and grow extent tree. However since we can not allocate any new metadata blocks we'll have to zero out unwritten part of extent or punched out part of extent, or in the worst case return ENOSPC even though use actually does not allocate any space. Also in delalloc path we do reserve metadata and data blocks for the time we're going to write out, however metadata block reservation is very tricky especially since we expect that logical connectivity implies physical connectivity, however that might not be the case and hence we might end up allocating more metadata blocks than previously reserved. So in future, metadata reservation checks should be removed since we can not assure that we do not under reserve. And this is where reserved space comes into the picture. When mounting the file system we slice off a little bit of the file system space (2% or 4096 clusters, whichever is smaller) which can be then used for the cases mentioned above to prevent costly zeroout, or unexpected ENOSPC. The number of reserved clusters can be set via sysfs, however it can never be bigger than number of free clusters in the file system. Note that this patch fixes the failure of xfstest 274 as expected. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ea607f907232..8b158ae2443b 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1942,8 +1942,8 @@ prepend:
1942 * There is no free space in the found leaf. 1942 * There is no free space in the found leaf.
1943 * We're gonna add a new leaf in the tree. 1943 * We're gonna add a new leaf in the tree.
1944 */ 1944 */
1945 if (flag & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) 1945 if (flag & EXT4_GET_BLOCKS_METADATA_NOFAIL)
1946 flags = EXT4_MB_USE_ROOT_BLOCKS; 1946 flags = EXT4_MB_USE_RESERVED;
1947 err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext); 1947 err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext);
1948 if (err) 1948 if (err)
1949 goto cleanup; 1949 goto cleanup;
@@ -2729,12 +2729,14 @@ again:
2729 2729
2730 /* 2730 /*
2731 * Split the extent in two so that 'end' is the last 2731 * Split the extent in two so that 'end' is the last
2732 * block in the first new extent 2732 * block in the first new extent. Also we should not
2733 * fail removing space due to ENOSPC so try to use
2734 * reserved block if that happens.
2733 */ 2735 */
2734 err = ext4_split_extent_at(handle, inode, path, 2736 err = ext4_split_extent_at(handle, inode, path,
2735 end + 1, split_flag, 2737 end + 1, split_flag,
2736 EXT4_GET_BLOCKS_PRE_IO | 2738 EXT4_GET_BLOCKS_PRE_IO |
2737 EXT4_GET_BLOCKS_PUNCH_OUT_EXT); 2739 EXT4_GET_BLOCKS_METADATA_NOFAIL);
2738 2740
2739 if (err < 0) 2741 if (err < 0)
2740 goto out; 2742 goto out;
@@ -3209,7 +3211,8 @@ out:
3209static int ext4_ext_convert_to_initialized(handle_t *handle, 3211static int ext4_ext_convert_to_initialized(handle_t *handle,
3210 struct inode *inode, 3212 struct inode *inode,
3211 struct ext4_map_blocks *map, 3213 struct ext4_map_blocks *map,
3212 struct ext4_ext_path *path) 3214 struct ext4_ext_path *path,
3215 int flags)
3213{ 3216{
3214 struct ext4_sb_info *sbi; 3217 struct ext4_sb_info *sbi;
3215 struct ext4_extent_header *eh; 3218 struct ext4_extent_header *eh;
@@ -3435,7 +3438,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
3435 } 3438 }
3436 3439
3437 allocated = ext4_split_extent(handle, inode, path, 3440 allocated = ext4_split_extent(handle, inode, path,
3438 &split_map, split_flag, 0); 3441 &split_map, split_flag, flags);
3439 if (allocated < 0) 3442 if (allocated < 0)
3440 err = allocated; 3443 err = allocated;
3441 3444
@@ -3755,6 +3758,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
3755 flags, allocated); 3758 flags, allocated);
3756 ext4_ext_show_leaf(inode, path); 3759 ext4_ext_show_leaf(inode, path);
3757 3760
3761 /*
3762 * When writing into uninitialized space, we should not fail to
3763 * allocate metadata blocks for the new extent block if needed.
3764 */
3765 flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;
3766
3758 trace_ext4_ext_handle_uninitialized_extents(inode, map, flags, 3767 trace_ext4_ext_handle_uninitialized_extents(inode, map, flags,
3759 allocated, newblock); 3768 allocated, newblock);
3760 3769
@@ -3818,7 +3827,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
3818 } 3827 }
3819 3828
3820 /* buffered write, writepage time, convert*/ 3829 /* buffered write, writepage time, convert*/
3821 ret = ext4_ext_convert_to_initialized(handle, inode, map, path); 3830 ret = ext4_ext_convert_to_initialized(handle, inode, map, path, flags);
3822 if (ret >= 0) 3831 if (ret >= 0)
3823 ext4_update_inode_fsync_trans(handle, inode, 1); 3832 ext4_update_inode_fsync_trans(handle, inode, 1);
3824out: 3833out: