Skip to content

Commit 55f020d

Browse files
achendertytso
authored andcommitted
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 <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]> Reviewed-by: Mingming Cao <[email protected]>
1 parent ae81230 commit 55f020d

File tree

6 files changed

+60
-31
lines changed

6 files changed

+60
-31
lines changed

fs/ext4/balloc.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
369369
* Check if filesystem has nblocks free & available for allocation.
370370
* On success return 1, return 0 on failure.
371371
*/
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)
373374
{
374375
s64 free_blocks, dirty_blocks, root_blocks;
375376
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)
393394
/* Hm, nope. Are (enough) root reserved blocks available? */
394395
if (sbi->s_resuid == current_fsuid() ||
395396
((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+
397400
if (free_blocks >= (nblocks + dirty_blocks))
398401
return 1;
399402
}
@@ -402,9 +405,9 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
402405
}
403406

404407
int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
405-
s64 nblocks)
408+
s64 nblocks, unsigned int flags)
406409
{
407-
if (ext4_has_free_blocks(sbi, nblocks)) {
410+
if (ext4_has_free_blocks(sbi, nblocks, flags)) {
408411
percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks);
409412
return 0;
410413
} else
@@ -425,7 +428,7 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
425428
*/
426429
int ext4_should_retry_alloc(struct super_block *sb, int *retries)
427430
{
428-
if (!ext4_has_free_blocks(EXT4_SB(sb), 1) ||
431+
if (!ext4_has_free_blocks(EXT4_SB(sb), 1, 0) ||
429432
(*retries)++ > 3 ||
430433
!EXT4_SB(sb)->s_journal)
431434
return 0;
@@ -448,7 +451,8 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
448451
* error stores in errp pointer
449452
*/
450453
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)
452456
{
453457
struct ext4_allocation_request ar;
454458
ext4_fsblk_t ret;
@@ -458,6 +462,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
458462
ar.inode = inode;
459463
ar.goal = goal;
460464
ar.len = count ? *count : 1;
465+
ar.flags = flags;
461466

462467
ret = ext4_mb_new_blocks(handle, &ar, errp);
463468
if (count)

fs/ext4/ext4.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ typedef unsigned int ext4_group_t;
108108
#define EXT4_MB_DELALLOC_RESERVED 0x0400
109109
/* We are doing stream allocation */
110110
#define EXT4_MB_STREAM_ALLOC 0x0800
111-
111+
/* Use reserved root blocks if needed */
112+
#define EXT4_MB_USE_ROOT_BLOCKS 0x1000
112113

113114
struct ext4_allocation_request {
114115
/* target inode for block we're allocating */
@@ -514,6 +515,8 @@ struct ext4_new_group_data {
514515
/* Convert extent to initialized after IO complete */
515516
#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
516517
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
518+
/* Punch out blocks of an extent */
519+
#define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020
517520

518521
/*
519522
* Flags used by ext4_free_blocks
@@ -1718,8 +1721,12 @@ extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group);
17181721
extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
17191722
ext4_group_t group);
17201723
extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
1721-
ext4_fsblk_t goal, unsigned long *count, int *errp);
1722-
extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
1724+
ext4_fsblk_t goal,
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);
17231730
extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
17241731
extern void ext4_check_blocks_bitmap(struct super_block *);
17251732
extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,

fs/ext4/extents.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,13 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
192192
static ext4_fsblk_t
193193
ext4_ext_new_meta_block(handle_t *handle, struct inode *inode,
194194
struct ext4_ext_path *path,
195-
struct ext4_extent *ex, int *err)
195+
struct ext4_extent *ex, int *err, unsigned int flags)
196196
{
197197
ext4_fsblk_t goal, newblock;
198198

199199
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);
201202
return newblock;
202203
}
203204

@@ -792,8 +793,9 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
792793
* - initializes subtree
793794
*/
794795
static int ext4_ext_split(handle_t *handle, struct inode *inode,
795-
struct ext4_ext_path *path,
796-
struct ext4_extent *newext, int at)
796+
unsigned int flags,
797+
struct ext4_ext_path *path,
798+
struct ext4_extent *newext, int at)
797799
{
798800
struct buffer_head *bh = NULL;
799801
int depth = ext_depth(inode);
@@ -847,7 +849,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
847849
ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
848850
for (a = 0; a < depth - at; a++) {
849851
newblock = ext4_ext_new_meta_block(handle, inode, path,
850-
newext, &err);
852+
newext, &err, flags);
851853
if (newblock == 0)
852854
goto cleanup;
853855
ablocks[a] = newblock;
@@ -1056,16 +1058,18 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
10561058
* just created block
10571059
*/
10581060
static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
1059-
struct ext4_ext_path *path,
1060-
struct ext4_extent *newext)
1061+
unsigned int flags,
1062+
struct ext4_ext_path *path,
1063+
struct ext4_extent *newext)
10611064
{
10621065
struct ext4_ext_path *curp = path;
10631066
struct ext4_extent_header *neh;
10641067
struct buffer_head *bh;
10651068
ext4_fsblk_t newblock;
10661069
int err = 0;
10671070

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);
10691073
if (newblock == 0)
10701074
return err;
10711075

@@ -1140,8 +1144,9 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
11401144
* if no free index is found, then it requests in-depth growing.
11411145
*/
11421146
static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
1143-
struct ext4_ext_path *path,
1144-
struct ext4_extent *newext)
1147+
unsigned int flags,
1148+
struct ext4_ext_path *path,
1149+
struct ext4_extent *newext)
11451150
{
11461151
struct ext4_ext_path *curp;
11471152
int depth, i, err = 0;
@@ -1161,7 +1166,7 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
11611166
if (EXT_HAS_FREE_INDEX(curp)) {
11621167
/* if we found index with free entry, then use that
11631168
* 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);
11651170
if (err)
11661171
goto out;
11671172

@@ -1174,7 +1179,8 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
11741179
err = PTR_ERR(path);
11751180
} else {
11761181
/* 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);
11781184
if (err)
11791185
goto out;
11801186

@@ -1693,6 +1699,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
16931699
int depth, len, err;
16941700
ext4_lblk_t next;
16951701
unsigned uninitialized = 0;
1702+
int flags = 0;
16961703

16971704
if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
16981705
EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
@@ -1767,7 +1774,9 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
17671774
* There is no free space in the found leaf.
17681775
* We're gonna add a new leaf in the tree.
17691776
*/
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);
17711780
if (err)
17721781
goto cleanup;
17731782
depth = ext_depth(inode);

fs/ext4/inode.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,8 +639,8 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
639639
while (target > 0) {
640640
count = target;
641641
/* 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);
644644
if (*err)
645645
goto failed_out;
646646

@@ -1930,7 +1930,7 @@ static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock)
19301930
* We do still charge estimated metadata to the sb though;
19311931
* we cannot afford to run out of free blocks.
19321932
*/
1933-
if (ext4_claim_free_blocks(sbi, md_needed + 1)) {
1933+
if (ext4_claim_free_blocks(sbi, md_needed + 1, 0)) {
19341934
dquot_release_reservation_block(inode, 1);
19351935
if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
19361936
yield();

fs/ext4/mballoc.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4236,7 +4236,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
42364236
* there is enough free blocks to do block allocation
42374237
* and verify allocation doesn't exceed the quota limits.
42384238
*/
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+
42404242
/* let others to free the space */
42414243
yield();
42424244
ar->len = ar->len >> 1;
@@ -4246,9 +4248,15 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
42464248
return 0;
42474249
}
42484250
reserv_blks = ar->len;
4249-
while (ar->len && dquot_alloc_block(ar->inode, ar->len)) {
4250-
ar->flags |= EXT4_MB_HINT_NOPREALLOC;
4251-
ar->len--;
4251+
if (ar->flags & EXT4_MB_USE_ROOT_BLOCKS) {
4252+
dquot_alloc_block_nofail(ar->inode, 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+
}
42524260
}
42534261
inquota = ar->len;
42544262
if (ar->len == 0) {

fs/ext4/xattr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
820820
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
821821
goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
822822

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);
825825
if (error)
826826
goto cleanup;
827827

0 commit comments

Comments
 (0)