From: Brian Foster <bfoster@xxxxxxxxxx> If we call ext4_calc_metadata_amount() and then fail to claim the space, a subsequent successful request to a block covered by the same ext2 indirect block will set md_needed to 0, fail to update the associated counters and result in a delayed md block allocation without a reservation. Decrement i_da_metadata_calc_len on failure to ensure the next reservation sets md_needed correctly. Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx> --- fs/ext4/inode.c | 18 ++++++++++++++++-- 1 files changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b58845c..7d2a3c0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1138,13 +1138,14 @@ repeat: * We do still charge estimated metadata to the sb though; * we cannot afford to run out of free blocks. */ - if (ext4_claim_free_clusters(sbi, md_needed + 1, 0)) { + ret = ext4_claim_free_clusters(sbi, md_needed + 1, 0); + if (ret) { dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1)); if (ext4_should_retry_alloc(inode->i_sb, &retries)) { yield(); goto repeat; } - return -ENOSPC; + goto error; } spin_lock(&ei->i_block_reservation_lock); ei->i_reserved_data_blocks++; @@ -1152,6 +1153,19 @@ repeat: spin_unlock(&ei->i_block_reservation_lock); return 0; /* success */ + +error: + /* + * We've failed to reserve the space. Undo the effect + * of ext4_calc_metadata_amount() to ensure the next + * attempt correctly accounts for metadata. + */ + spin_lock(&ei->i_block_reservation_lock); + if (ei->i_da_metadata_calc_len) + ei->i_da_metadata_calc_len--; + spin_unlock(&ei->i_block_reservation_lock); + + return ret; } static void ext4_da_release_space(struct inode *inode, int to_free) -- 1.7.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html