Skip to content

Commit 03179fe

Browse files
committed
ext4: undo ext4_calc_metadata_amount if we fail to claim space
The function ext4_calc_metadata_amount() has side effects, although it's not obvious from its function name. So if we fail to claim space, regardless of whether we retry to claim the space again, or return an error, we need to undo these side effects. Otherwise we can end up incorrectly calculating the number of metadata blocks needed for the operation, which was responsible for an xfstests failure for test raspberrypi#271 when using an ext2 file system with delalloc enabled. Reported-by: Brian Foster <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]> Cc: [email protected]
1 parent 97795d2 commit 03179fe

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

fs/ext4/inode.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,17 @@ static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock)
11821182
struct ext4_inode_info *ei = EXT4_I(inode);
11831183
unsigned int md_needed;
11841184
int ret;
1185+
ext4_lblk_t save_last_lblock;
1186+
int save_len;
1187+
1188+
/*
1189+
* We will charge metadata quota at writeout time; this saves
1190+
* us from metadata over-estimation, though we may go over by
1191+
* a small amount in the end. Here we just reserve for data.
1192+
*/
1193+
ret = dquot_reserve_block(inode, EXT4_C2B(sbi, 1));
1194+
if (ret)
1195+
return ret;
11851196

11861197
/*
11871198
* recalculate the amount of metadata blocks to reserve
@@ -1190,32 +1201,31 @@ static int ext4_da_reserve_space(struct inode *inode, ext4_lblk_t lblock)
11901201
*/
11911202
repeat:
11921203
spin_lock(&ei->i_block_reservation_lock);
1204+
/*
1205+
* ext4_calc_metadata_amount() has side effects, which we have
1206+
* to be prepared undo if we fail to claim space.
1207+
*/
1208+
save_len = ei->i_da_metadata_calc_len;
1209+
save_last_lblock = ei->i_da_metadata_calc_last_lblock;
11931210
md_needed = EXT4_NUM_B2C(sbi,
11941211
ext4_calc_metadata_amount(inode, lblock));
11951212
trace_ext4_da_reserve_space(inode, md_needed);
1196-
spin_unlock(&ei->i_block_reservation_lock);
11971213

1198-
/*
1199-
* We will charge metadata quota at writeout time; this saves
1200-
* us from metadata over-estimation, though we may go over by
1201-
* a small amount in the end. Here we just reserve for data.
1202-
*/
1203-
ret = dquot_reserve_block(inode, EXT4_C2B(sbi, 1));
1204-
if (ret)
1205-
return ret;
12061214
/*
12071215
* We do still charge estimated metadata to the sb though;
12081216
* we cannot afford to run out of free blocks.
12091217
*/
12101218
if (ext4_claim_free_clusters(sbi, md_needed + 1, 0)) {
1211-
dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1));
1219+
ei->i_da_metadata_calc_len = save_len;
1220+
ei->i_da_metadata_calc_last_lblock = save_last_lblock;
1221+
spin_unlock(&ei->i_block_reservation_lock);
12121222
if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
12131223
yield();
12141224
goto repeat;
12151225
}
1226+
dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1));
12161227
return -ENOSPC;
12171228
}
1218-
spin_lock(&ei->i_block_reservation_lock);
12191229
ei->i_reserved_data_blocks++;
12201230
ei->i_reserved_meta_blocks += md_needed;
12211231
spin_unlock(&ei->i_block_reservation_lock);

0 commit comments

Comments
 (0)