aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorAllison Henderson <achender@linux.vnet.ibm.com>2011-05-25 07:41:26 -0400
committerTheodore Ts'o <tytso@mit.edu>2011-05-25 07:41:26 -0400
commit55f020db66ce187fb8c8e4002a94b0eb714da450 (patch)
treee98214511542f57fa93074be12e27c4819520333 /fs/ext4
parentae81230686282af745ebb7a74c0332349cb9131a (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.c17
-rw-r--r--fs/ext4/ext4.h13
-rw-r--r--fs/ext4/extents.c35
-rw-r--r--fs/ext4/inode.c6
-rw-r--r--fs/ext4/mballoc.c16
-rw-r--r--fs/ext4/xattr.c4
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 */
372static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) 372static 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
404int ext4_claim_free_blocks(struct ext4_sb_info *sbi, 407int 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 */
426int ext4_should_retry_alloc(struct super_block *sb, int *retries) 429int 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 */
450ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, 453ext4_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
113struct ext4_allocation_request { 114struct 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);
1718extern unsigned long ext4_bg_num_gdb(struct super_block *sb, 1721extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
1719 ext4_group_t group); 1722 ext4_group_t group);
1720extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, 1723extern 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,
1722extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); 1725 unsigned int flags,
1726 unsigned long *count,
1727 int *errp);
1728extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
1729 s64 nblocks, unsigned int flags);
1723extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); 1730extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
1724extern void ext4_check_blocks_bitmap(struct super_block *); 1731extern void ext4_check_blocks_bitmap(struct super_block *);
1725extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, 1732extern 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,
192static ext4_fsblk_t 192static ext4_fsblk_t
193ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, 193ext4_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 */
794static int ext4_ext_split(handle_t *handle, struct inode *inode, 795static 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 */
1058static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, 1060static 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 */
1142static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, 1146static 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