ext4: fix sleep inside spinlock issue with quota and dealloc (#14739)

Unlock i_block_reservation_lock before vfs_dq_reserve_block().
This patch fixes http://bugzilla.kernel.org/show_bug.cgi?id=14739

CC: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Dmitry Monakhov 2009-12-10 16:36:27 +00:00 committed by Jan Kara
parent d21cd8f163
commit 39bc680a81

View file

@ -1816,19 +1816,17 @@ repeat:
md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
total = md_needed + nrblocks; total = md_needed + nrblocks;
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
/* /*
* Make quota reservation here to prevent quota overflow * Make quota reservation here to prevent quota overflow
* later. Real quota accounting is done at pages writeout * later. Real quota accounting is done at pages writeout
* time. * time.
*/ */
if (vfs_dq_reserve_block(inode, total)) { if (vfs_dq_reserve_block(inode, total))
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
return -EDQUOT; return -EDQUOT;
}
if (ext4_claim_free_blocks(sbi, total)) { if (ext4_claim_free_blocks(sbi, total)) {
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
vfs_dq_release_reservation_block(inode, total); vfs_dq_release_reservation_block(inode, total);
if (ext4_should_retry_alloc(inode->i_sb, &retries)) { if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
yield(); yield();
@ -1836,10 +1834,11 @@ repeat:
} }
return -ENOSPC; return -ENOSPC;
} }
spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
EXT4_I(inode)->i_reserved_data_blocks += nrblocks; EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
EXT4_I(inode)->i_reserved_meta_blocks = mdblocks; EXT4_I(inode)->i_reserved_meta_blocks += md_needed;
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
return 0; /* success */ return 0; /* success */
} }