diff options
author | Allison Henderson <achender@linux.vnet.ibm.com> | 2011-05-25 07:41:26 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2011-05-25 07:41:26 -0400 |
commit | 55f020db66ce187fb8c8e4002a94b0eb714da450 (patch) | |
tree | e98214511542f57fa93074be12e27c4819520333 /fs/ext4 | |
parent | ae81230686282af745ebb7a74c0332349cb9131a (diff) |
ext4: add flag to ext4_has_free_blocks
This patch adds an allocation request flag to the ext4_has_free_blocks
function which enables the use of reserved blocks. This will allow a
punch hole to proceed even if the disk is full. Punching a hole may
require additional blocks to first split the extents.
Because ext4_has_free_blocks is a low level function, the flag needs
to be passed down through several functions listed below:
ext4_ext_insert_extent
ext4_ext_create_new_leaf
ext4_ext_grow_indepth
ext4_ext_split
ext4_ext_new_meta_block
ext4_mb_new_blocks
ext4_claim_free_blocks
ext4_has_free_blocks
[ext4 punch hole patch series 1/5 v7]
Signed-off-by: Allison Henderson <achender@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Mingming Cao <cmm@us.ibm.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 17 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 13 | ||||
-rw-r--r-- | fs/ext4/extents.c | 35 | ||||
-rw-r--r-- | fs/ext4/inode.c | 6 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 16 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 4 |
6 files changed, 60 insertions, 31 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b2d10da505ef..264f6949511e 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -369,7 +369,8 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
369 | * Check if filesystem has nblocks free & available for allocation. | 369 | * Check if filesystem has nblocks free & available for allocation. |
370 | * On success return 1, return 0 on failure. | 370 | * On success return 1, return 0 on failure. |
371 | */ | 371 | */ |
372 | static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) | 372 | static int ext4_has_free_blocks(struct ext4_sb_info *sbi, |
373 | s64 nblocks, unsigned int flags) | ||
373 | { | 374 | { |
374 | s64 free_blocks, dirty_blocks, root_blocks; | 375 | s64 free_blocks, dirty_blocks, root_blocks; |
375 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | 376 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; |
@@ -393,7 +394,9 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) | |||
393 | /* Hm, nope. Are (enough) root reserved blocks available? */ | 394 | /* Hm, nope. Are (enough) root reserved blocks available? */ |
394 | if (sbi->s_resuid == current_fsuid() || | 395 | if (sbi->s_resuid == current_fsuid() || |
395 | ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || | 396 | ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || |
396 | capable(CAP_SYS_RESOURCE)) { | 397 | capable(CAP_SYS_RESOURCE) || |
398 | (flags & EXT4_MB_USE_ROOT_BLOCKS)) { | ||
399 | |||
397 | if (free_blocks >= (nblocks + dirty_blocks)) | 400 | if (free_blocks >= (nblocks + dirty_blocks)) |
398 | return 1; | 401 | return 1; |
399 | } | 402 | } |
@@ -402,9 +405,9 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) | |||
402 | } | 405 | } |
403 | 406 | ||
404 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | 407 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, |
405 | s64 nblocks) | 408 | s64 nblocks, unsigned int flags) |
406 | { | 409 | { |
407 | if (ext4_has_free_blocks(sbi, nblocks)) { | 410 | if (ext4_has_free_blocks(sbi, nblocks, flags)) { |
408 | percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); | 411 | percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); |
409 | return 0; | 412 | return 0; |
410 | } else | 413 | } else |
@@ -425,7 +428,7 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | |||
425 | */ | 428 | */ |
426 | int ext4_should_retry_alloc(struct super_block *sb, int *retries) | 429 | int ext4_should_retry_alloc(struct super_block *sb, int *retries) |
427 | { | 430 | { |
428 | if (!ext4_has_free_blocks(EXT4_SB(sb), 1) || | 431 | if (!ext4_has_free_blocks(EXT4_SB(sb), 1, 0) || |
429 | (*retries)++ > 3 || | 432 | (*retries)++ > 3 || |
430 | !EXT4_SB(sb)->s_journal) | 433 | !EXT4_SB(sb)->s_journal) |
431 | return 0; | 434 | return 0; |
@@ -448,7 +451,8 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries) | |||
448 | * error stores in errp pointer | 451 | * error stores in errp pointer |
449 | */ | 452 | */ |
450 | ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, | 453 | ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, |
451 | ext4_fsblk_t goal, unsigned long *count, int *errp) | 454 | ext4_fsblk_t goal, unsigned int flags, |
455 | unsigned long *count, int *errp) | ||
452 | { | 456 | { |
453 | struct ext4_allocation_request ar; | 457 | struct ext4_allocation_request ar; |
454 | ext4_fsblk_t ret; | 458 | ext4_fsblk_t ret; |
@@ -458,6 +462,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, | |||
458 | ar.inode = inode; | 462 | ar.inode = inode; |
459 | ar.goal = goal; | 463 | ar.goal = goal; |
460 | ar.len = count ? *count : 1; | 464 | ar.len = count ? *count : 1; |
465 | ar.flags = flags; | ||
461 | 466 | ||
462 | ret = ext4_mb_new_blocks(handle, &ar, errp); | 467 | ret = ext4_mb_new_blocks(handle, &ar, errp); |
463 | if (count) | 468 | if (count) |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2bc4c21f1d26..2f310d1839ed 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -108,7 +108,8 @@ typedef unsigned int ext4_group_t; | |||
108 | #define EXT4_MB_DELALLOC_RESERVED 0x0400 | 108 | #define EXT4_MB_DELALLOC_RESERVED 0x0400 |
109 | /* We are doing stream allocation */ | 109 | /* We are doing stream allocation */ |
110 | #define EXT4_MB_STREAM_ALLOC 0x0800 | 110 | #define EXT4_MB_STREAM_ALLOC 0x0800 |
111 | 111 | /* Use reserved root blocks if needed */ | |
112 | #define EXT4_MB_USE_ROOT_BLOCKS 0x1000 | ||
112 | 113 | ||
113 | struct ext4_allocation_request { | 114 | struct ext4_allocation_request { |
114 | /* target inode for block we're allocating */ | 115 | /* target inode for block we're allocating */ |
@@ -514,6 +515,8 @@ struct ext4_new_group_data { | |||
514 | /* Convert extent to initialized after IO complete */ | 515 | /* Convert extent to initialized after IO complete */ |
515 | #define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ | 516 | #define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ |
516 | EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) | 517 | EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) |
518 | /* Punch out blocks of an extent */ | ||
519 | #define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020 | ||
517 | 520 | ||
518 | /* | 521 | /* |
519 | * Flags used by ext4_free_blocks | 522 | * Flags used by ext4_free_blocks |
@@ -1718,8 +1721,12 @@ extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); | |||
1718 | extern unsigned long ext4_bg_num_gdb(struct super_block *sb, | 1721 | extern unsigned long ext4_bg_num_gdb(struct super_block *sb, |
1719 | ext4_group_t group); | 1722 | ext4_group_t group); |
1720 | extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, | 1723 | extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, |
1721 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 1724 | ext4_fsblk_t goal, |
1722 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); | 1725 | unsigned int flags, |
1726 | unsigned long *count, | ||
1727 | int *errp); | ||
1728 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | ||
1729 | s64 nblocks, unsigned int flags); | ||
1723 | extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); | 1730 | extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); |
1724 | extern void ext4_check_blocks_bitmap(struct super_block *); | 1731 | extern void ext4_check_blocks_bitmap(struct super_block *); |
1725 | extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, | 1732 | extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index ca62d748cc65..aa3a2601bada 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -192,12 +192,13 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, | |||
192 | static ext4_fsblk_t | 192 | static ext4_fsblk_t |
193 | ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, | 193 | ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, |
194 | struct ext4_ext_path *path, | 194 | struct ext4_ext_path *path, |
195 | struct ext4_extent *ex, int *err) | 195 | struct ext4_extent *ex, int *err, unsigned int flags) |
196 | { | 196 | { |
197 | ext4_fsblk_t goal, newblock; | 197 | ext4_fsblk_t goal, newblock; |
198 | 198 | ||
199 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); | 199 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); |
200 | newblock = ext4_new_meta_blocks(handle, inode, goal, NULL, err); | 200 | newblock = ext4_new_meta_blocks(handle, inode, goal, flags, |
201 | NULL, err); | ||
201 | return newblock; | 202 | return newblock; |
202 | } | 203 | } |
203 | 204 | ||
@@ -792,8 +793,9 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, | |||
792 | * - initializes subtree | 793 | * - initializes subtree |
793 | */ | 794 | */ |
794 | static int ext4_ext_split(handle_t *handle, struct inode *inode, | 795 | static int ext4_ext_split(handle_t *handle, struct inode *inode, |
795 | struct ext4_ext_path *path, | 796 | unsigned int flags, |
796 | struct ext4_extent *newext, int at) | 797 | struct ext4_ext_path *path, |
798 | struct ext4_extent *newext, int at) | ||
797 | { | 799 | { |
798 | struct buffer_head *bh = NULL; | 800 | struct buffer_head *bh = NULL; |
799 | int depth = ext_depth(inode); | 801 | int depth = ext_depth(inode); |
@@ -847,7 +849,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
847 | ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); | 849 | ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); |
848 | for (a = 0; a < depth - at; a++) { | 850 | for (a = 0; a < depth - at; a++) { |
849 | newblock = ext4_ext_new_meta_block(handle, inode, path, | 851 | newblock = ext4_ext_new_meta_block(handle, inode, path, |
850 | newext, &err); | 852 | newext, &err, flags); |
851 | if (newblock == 0) | 853 | if (newblock == 0) |
852 | goto cleanup; | 854 | goto cleanup; |
853 | ablocks[a] = newblock; | 855 | ablocks[a] = newblock; |
@@ -1056,8 +1058,9 @@ cleanup: | |||
1056 | * just created block | 1058 | * just created block |
1057 | */ | 1059 | */ |
1058 | static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | 1060 | static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, |
1059 | struct ext4_ext_path *path, | 1061 | unsigned int flags, |
1060 | struct ext4_extent *newext) | 1062 | struct ext4_ext_path *path, |
1063 | struct ext4_extent *newext) | ||
1061 | { | 1064 | { |
1062 | struct ext4_ext_path *curp = path; | 1065 | struct ext4_ext_path *curp = path; |
1063 | struct ext4_extent_header *neh; | 1066 | struct ext4_extent_header *neh; |
@@ -1065,7 +1068,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | |||
1065 | ext4_fsblk_t newblock; | 1068 | ext4_fsblk_t newblock; |
1066 | int err = 0; | 1069 | int err = 0; |
1067 | 1070 | ||
1068 | newblock = ext4_ext_new_meta_block(handle, inode, path, newext, &err); | 1071 | newblock = ext4_ext_new_meta_block(handle, inode, path, |
1072 | newext, &err, flags); | ||
1069 | if (newblock == 0) | 1073 | if (newblock == 0) |
1070 | return err; | 1074 | return err; |
1071 | 1075 | ||
@@ -1140,8 +1144,9 @@ out: | |||
1140 | * if no free index is found, then it requests in-depth growing. | 1144 | * if no free index is found, then it requests in-depth growing. |
1141 | */ | 1145 | */ |
1142 | static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, | 1146 | static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, |
1143 | struct ext4_ext_path *path, | 1147 | unsigned int flags, |
1144 | struct ext4_extent *newext) | 1148 | struct ext4_ext_path *path, |
1149 | struct ext4_extent *newext) | ||
1145 | { | 1150 | { |
1146 | struct ext4_ext_path *curp; | 1151 | struct ext4_ext_path *curp; |
1147 | int depth, i, err = 0; | 1152 | int depth, i, err = 0; |
@@ -1161,7 +1166,7 @@ repeat: | |||
1161 | if (EXT_HAS_FREE_INDEX(curp)) { | 1166 | if (EXT_HAS_FREE_INDEX(curp)) { |
1162 | /* if we found index with free entry, then use that | 1167 | /* if we found index with free entry, then use that |
1163 | * entry: create all needed subtree and add new leaf */ | 1168 | * entry: create all needed subtree and add new leaf */ |
1164 | err = ext4_ext_split(handle, inode, path, newext, i); | 1169 | err = ext4_ext_split(handle, inode, flags, path, newext, i); |
1165 | if (err) | 1170 | if (err) |
1166 | goto out; | 1171 | goto out; |
1167 | 1172 | ||
@@ -1174,7 +1179,8 @@ repeat: | |||
1174 | err = PTR_ERR(path); | 1179 | err = PTR_ERR(path); |
1175 | } else { | 1180 | } else { |
1176 | /* tree is full, time to grow in depth */ | 1181 | /* tree is full, time to grow in depth */ |
1177 | err = ext4_ext_grow_indepth(handle, inode, path, newext); | 1182 | err = ext4_ext_grow_indepth(handle, inode, flags, |
1183 | path, newext); | ||
1178 | if (err) | 1184 | if (err) |
1179 | goto out; | 1185 | goto out; |
1180 | 1186 | ||
@@ -1693,6 +1699,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, | |||
1693 | int depth, len, err; | 1699 | int depth, len, err; |
1694 | ext4_lblk_t next; | 1700 | ext4_lblk_t next; |
1695 | unsigned uninitialized = 0; | 1701 | unsigned uninitialized = 0; |
1702 | int flags = 0; | ||
1696 | 1703 | ||
1697 | if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { | 1704 | if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { |
1698 | EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); | 1705 | EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); |
@@ -1767,7 +1774,9 @@ repeat: | |||
1767 | * There is no free space in the found leaf. | 1774 | * There is no free space in the found leaf. |
1768 | * We're gonna add a new leaf in the tree. | 1775 | * We're gonna add a new leaf in the tree. |
1769 | */ | 1776 | */ |
1770 | err = ext4_ext_create_new_leaf(handle, inode, path, newext); | 1777 | if (flag & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) |
1778 | flags = EXT4_MB_USE_ROOT_BLOCKS; | ||
1779 | err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext); | ||
1771 | if (err) | 1780 | if (err) |
1772 | goto cleanup; | 1781 | goto cleanup; |
1773 | depth = ext_depth(inode); | 1782 | depth = ext_depth(inode); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d98b033dd4a4..aef864b725d3 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -639,8 +639,8 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
639 | while (target > 0) { | 639 | while (target > 0) { |
640 | count = target; | 640 | count = target; |
641 | /* allocating blocks for indirect blocks and direct blocks */ | 641 | /* allocating blocks for indirect blocks and direct blocks */ |
642 | current_block = ext4_new_meta_blocks(handle, inode, | 642 | current_block = ext4_new_meta_blocks(handle, inode, goal, |
643 | goal, &count, err); | 643 | 0, &count, err); |
644 | if (*err) | 644 | if (*err) |
645 | goto failed_out; | 645 | goto failed_out; |
646 | 646 | ||
@@ -1930,7 +1930,7 @@ repeat: | |||
1930 | * We do still charge estimated metadata to the sb though; | 1930 | * We do still charge estimated metadata to the sb though; |
1931 | * we cannot afford to run out of free blocks. | 1931 | * we cannot afford to run out of free blocks. |
1932 | */ | 1932 | */ |
1933 | if (ext4_claim_free_blocks(sbi, md_needed + 1)) { | 1933 | if (ext4_claim_free_blocks(sbi, md_needed + 1, 0)) { |
1934 | dquot_release_reservation_block(inode, 1); | 1934 | dquot_release_reservation_block(inode, 1); |
1935 | if (ext4_should_retry_alloc(inode->i_sb, &retries)) { | 1935 | if (ext4_should_retry_alloc(inode->i_sb, &retries)) { |
1936 | yield(); | 1936 | yield(); |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 396b01f5c4fb..859f2ae8864e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4236,7 +4236,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4236 | * there is enough free blocks to do block allocation | 4236 | * there is enough free blocks to do block allocation |
4237 | * and verify allocation doesn't exceed the quota limits. | 4237 | * and verify allocation doesn't exceed the quota limits. |
4238 | */ | 4238 | */ |
4239 | while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) { | 4239 | while (ar->len && |
4240 | ext4_claim_free_blocks(sbi, ar->len, ar->flags)) { | ||
4241 | |||
4240 | /* let others to free the space */ | 4242 | /* let others to free the space */ |
4241 | yield(); | 4243 | yield(); |
4242 | ar->len = ar->len >> 1; | 4244 | ar->len = ar->len >> 1; |
@@ -4246,9 +4248,15 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4246 | return 0; | 4248 | return 0; |
4247 | } | 4249 | } |
4248 | reserv_blks = ar->len; | 4250 | reserv_blks = ar->len; |
4249 | while (ar->len && dquot_alloc_block(ar->inode, ar->len)) { | 4251 | if (ar->flags & EXT4_MB_USE_ROOT_BLOCKS) { |
4250 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; | 4252 | dquot_alloc_block_nofail(ar->inode, ar->len); |
4251 | ar->len--; | 4253 | } else { |
4254 | while (ar->len && | ||
4255 | dquot_alloc_block(ar->inode, ar->len)) { | ||
4256 | |||
4257 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; | ||
4258 | ar->len--; | ||
4259 | } | ||
4252 | } | 4260 | } |
4253 | inquota = ar->len; | 4261 | inquota = ar->len; |
4254 | if (ar->len == 0) { | 4262 | if (ar->len == 0) { |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index b545ca1c459c..c757adc97250 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -820,8 +820,8 @@ inserted: | |||
820 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) | 820 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) |
821 | goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; | 821 | goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; |
822 | 822 | ||
823 | block = ext4_new_meta_blocks(handle, inode, | 823 | block = ext4_new_meta_blocks(handle, inode, goal, 0, |
824 | goal, NULL, &error); | 824 | NULL, &error); |
825 | if (error) | 825 | if (error) |
826 | goto cleanup; | 826 | goto cleanup; |
827 | 827 | ||