Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Allison Henderson and committed by
Theodore Ts'o
55f020db ae812306

+60 -31
+11 -6
fs/ext4/balloc.c
··· 369 369 * Check if filesystem has nblocks free & available for allocation. 370 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 375 s64 free_blocks, dirty_blocks, root_blocks; 375 376 struct percpu_counter *fbc = &sbi->s_freeblocks_counter; ··· 394 393 /* Hm, nope. Are (enough) root reserved blocks available? */ 395 394 if (sbi->s_resuid == current_fsuid() || 396 395 ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || 397 - capable(CAP_SYS_RESOURCE)) { 396 + capable(CAP_SYS_RESOURCE) || 397 + (flags & EXT4_MB_USE_ROOT_BLOCKS)) { 398 + 398 399 if (free_blocks >= (nblocks + dirty_blocks)) 399 400 return 1; 400 401 } ··· 405 402 } 406 403 407 404 int ext4_claim_free_blocks(struct ext4_sb_info *sbi, 408 - s64 nblocks) 405 + s64 nblocks, unsigned int flags) 409 406 { 410 - if (ext4_has_free_blocks(sbi, nblocks)) { 407 + if (ext4_has_free_blocks(sbi, nblocks, flags)) { 411 408 percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); 412 409 return 0; 413 410 } else ··· 428 425 */ 429 426 int ext4_should_retry_alloc(struct super_block *sb, int *retries) 430 427 { 431 - if (!ext4_has_free_blocks(EXT4_SB(sb), 1) || 428 + if (!ext4_has_free_blocks(EXT4_SB(sb), 1, 0) || 432 429 (*retries)++ > 3 || 433 430 !EXT4_SB(sb)->s_journal) 434 431 return 0; ··· 451 448 * error stores in errp pointer 452 449 */ 453 450 ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, 454 - ext4_fsblk_t goal, unsigned long *count, int *errp) 451 + ext4_fsblk_t goal, unsigned int flags, 452 + unsigned long *count, int *errp) 455 453 { 456 454 struct ext4_allocation_request ar; 457 455 ext4_fsblk_t ret; ··· 462 458 ar.inode = inode; 463 459 ar.goal = goal; 464 460 ar.len = count ? *count : 1; 461 + ar.flags = flags; 465 462 466 463 ret = ext4_mb_new_blocks(handle, &ar, errp); 467 464 if (count)
+10 -3
fs/ext4/ext4.h
··· 108 108 #define EXT4_MB_DELALLOC_RESERVED 0x0400 109 109 /* We are doing stream allocation */ 110 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 114 struct ext4_allocation_request { 114 115 /* target inode for block we're allocating */ ··· 515 514 /* Convert extent to initialized after IO complete */ 516 515 #define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ 517 516 EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) 517 + /* Punch out blocks of an extent */ 518 + #define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020 518 519 519 520 /* 520 521 * Flags used by ext4_free_blocks ··· 1721 1718 extern unsigned long ext4_bg_num_gdb(struct super_block *sb, 1722 1719 ext4_group_t group); 1723 1720 extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, 1724 - ext4_fsblk_t goal, unsigned long *count, int *errp); 1725 - extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); 1721 + ext4_fsblk_t goal, 1722 + unsigned int flags, 1723 + unsigned long *count, 1724 + int *errp); 1725 + extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, 1726 + s64 nblocks, unsigned int flags); 1726 1727 extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); 1727 1728 extern void ext4_check_blocks_bitmap(struct super_block *); 1728 1729 extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+22 -13
fs/ext4/extents.c
··· 192 192 static ext4_fsblk_t 193 193 ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, 194 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 197 ext4_fsblk_t goal, newblock; 198 198 199 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 202 return newblock; 202 203 } 203 204 ··· 793 792 * - initializes subtree 794 793 */ 795 794 static int ext4_ext_split(handle_t *handle, struct inode *inode, 796 - struct ext4_ext_path *path, 797 - struct ext4_extent *newext, int at) 795 + unsigned int flags, 796 + struct ext4_ext_path *path, 797 + struct ext4_extent *newext, int at) 798 798 { 799 799 struct buffer_head *bh = NULL; 800 800 int depth = ext_depth(inode); ··· 849 847 ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); 850 848 for (a = 0; a < depth - at; a++) { 851 849 newblock = ext4_ext_new_meta_block(handle, inode, path, 852 - newext, &err); 850 + newext, &err, flags); 853 851 if (newblock == 0) 854 852 goto cleanup; 855 853 ablocks[a] = newblock; ··· 1058 1056 * just created block 1059 1057 */ 1060 1058 static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, 1061 - struct ext4_ext_path *path, 1062 - struct ext4_extent *newext) 1059 + unsigned int flags, 1060 + struct ext4_ext_path *path, 1061 + struct ext4_extent *newext) 1063 1062 { 1064 1063 struct ext4_ext_path *curp = path; 1065 1064 struct ext4_extent_header *neh; ··· 1068 1065 ext4_fsblk_t newblock; 1069 1066 int err = 0; 1070 1067 1071 - newblock = ext4_ext_new_meta_block(handle, inode, path, newext, &err); 1068 + newblock = ext4_ext_new_meta_block(handle, inode, path, 1069 + newext, &err, flags); 1072 1070 if (newblock == 0) 1073 1071 return err; 1074 1072 ··· 1144 1140 * if no free index is found, then it requests in-depth growing. 1145 1141 */ 1146 1142 static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, 1147 - struct ext4_ext_path *path, 1148 - struct ext4_extent *newext) 1143 + unsigned int flags, 1144 + struct ext4_ext_path *path, 1145 + struct ext4_extent *newext) 1149 1146 { 1150 1147 struct ext4_ext_path *curp; 1151 1148 int depth, i, err = 0; ··· 1166 1161 if (EXT_HAS_FREE_INDEX(curp)) { 1167 1162 /* if we found index with free entry, then use that 1168 1163 * entry: create all needed subtree and add new leaf */ 1169 - err = ext4_ext_split(handle, inode, path, newext, i); 1164 + err = ext4_ext_split(handle, inode, flags, path, newext, i); 1170 1165 if (err) 1171 1166 goto out; 1172 1167 ··· 1179 1174 err = PTR_ERR(path); 1180 1175 } else { 1181 1176 /* tree is full, time to grow in depth */ 1182 - err = ext4_ext_grow_indepth(handle, inode, path, newext); 1177 + err = ext4_ext_grow_indepth(handle, inode, flags, 1178 + path, newext); 1183 1179 if (err) 1184 1180 goto out; 1185 1181 ··· 1699 1693 int depth, len, err; 1700 1694 ext4_lblk_t next; 1701 1695 unsigned uninitialized = 0; 1696 + int flags = 0; 1702 1697 1703 1698 if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { 1704 1699 EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); ··· 1774 1767 * There is no free space in the found leaf. 1775 1768 * We're gonna add a new leaf in the tree. 1776 1769 */ 1777 - err = ext4_ext_create_new_leaf(handle, inode, path, newext); 1770 + if (flag & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) 1771 + flags = EXT4_MB_USE_ROOT_BLOCKS; 1772 + err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext); 1778 1773 if (err) 1779 1774 goto cleanup; 1780 1775 depth = ext_depth(inode);
+3 -3
fs/ext4/inode.c
··· 639 639 while (target > 0) { 640 640 count = target; 641 641 /* allocating blocks for indirect blocks and direct blocks */ 642 - current_block = ext4_new_meta_blocks(handle, inode, 643 - goal, &count, err); 642 + current_block = ext4_new_meta_blocks(handle, inode, goal, 643 + 0, &count, err); 644 644 if (*err) 645 645 goto failed_out; 646 646 ··· 1930 1930 * We do still charge estimated metadata to the sb though; 1931 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 1934 dquot_release_reservation_block(inode, 1); 1935 1935 if (ext4_should_retry_alloc(inode->i_sb, &retries)) { 1936 1936 yield();
+12 -4
fs/ext4/mballoc.c
··· 4236 4236 * there is enough free blocks to do block allocation 4237 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 4242 /* let others to free the space */ 4241 4243 yield(); 4242 4244 ar->len = ar->len >> 1; ··· 4248 4246 return 0; 4249 4247 } 4250 4248 reserv_blks = ar->len; 4251 - while (ar->len && dquot_alloc_block(ar->inode, ar->len)) { 4252 - ar->flags |= EXT4_MB_HINT_NOPREALLOC; 4253 - ar->len--; 4249 + if (ar->flags & EXT4_MB_USE_ROOT_BLOCKS) { 4250 + dquot_alloc_block_nofail(ar->inode, ar->len); 4251 + } else { 4252 + while (ar->len && 4253 + dquot_alloc_block(ar->inode, ar->len)) { 4254 + 4255 + ar->flags |= EXT4_MB_HINT_NOPREALLOC; 4256 + ar->len--; 4257 + } 4254 4258 } 4255 4259 inquota = ar->len; 4256 4260 if (ar->len == 0) {
+2 -2
fs/ext4/xattr.c
··· 820 820 if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) 821 821 goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; 822 822 823 - block = ext4_new_meta_blocks(handle, inode, 824 - goal, NULL, &error); 823 + block = ext4_new_meta_blocks(handle, inode, goal, 0, 824 + NULL, &error); 825 825 if (error) 826 826 goto cleanup; 827 827