ext4: Do not allow retry alloc loop under open transaction
Subsystems (2)
PATCH 1/2 ext4: Do not allow retry alloc loop under open transaction
Some times we call ->write_begin() with opened journal but write_begin() may internally call ext4_should_retry_alloc() in case of ENOSPC, which result in deadlock.
This patch introduce new AOP_FLAG which should be tested on retry alloc path.
--- fs/ext4/ext4.h | 5 +++++ fs/ext4/inode.c | 6 ++++-- fs/ext4/move_extent.c | 2 +- include/linux/fs.h | 1 + 4 files changed, 11 insertions(+), 3 deletions(-)
fs/ext4/ext4.h +5 -0
@@ -792,6 +792,11 @@ struct ext4_inode_info {#define EXT4_DFL_CHECKINTERVAL 0/* Don't use interval check */ /* +* Address space flags. +*/ +#define EXT4_AOP_FLAG_NORETRY AOP_FLAG_LAST/* Do not allow to fail in to +retry alloc loop */ +/* * Behaviour when detecting errors */ #define EXT4_ERRORS_CONTINUE 1/* Continue execution */
fs/ext4/inode.c +4 -2
@@ -1593,7 +1593,8 @@ retry: } } -if (ret == -ENOSPC &&ext4_should_retry_alloc (inode->i_sb, &retries)) +if (!(flags &EXT4_AOP_FLAG_NORETRY ) && ret == -ENOSPC && +ext4_should_retry_alloc (inode->i_sb, &retries)) goto retry; out:return ret;
@@ -3089,7 +3090,8 @@ retry:ext4_truncate_failed_write (inode); } -if (ret == -ENOSPC &&ext4_should_retry_alloc (inode->i_sb, &retries)) +if (!(flags &EXT4_AOP_FLAG_NORETRY ) && + ret == -ENOSPC &&ext4_should_retry_alloc (inode->i_sb, &retries)) goto retry; out:return ret;
fs/ext4/move_extent.c +1 -1
@@ -796,7 +796,7 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,ext4_lblk_t orig_blk_offset;long long offs = orig_page_offset <<PAGE_CACHE_SHIFT ;unsigned long blocksize = orig_inode->i_sb->s_blocksize; -unsigned int w_flags =0 ; +unsigned int w_flags =EXT4_AOP_FLAG_NORETRY ;unsigned int tmp_data_size, data_size, replaced_size;void *fsdata;int i, jblocks;
include/linux/fs.h +1 -0
@@ -504,6 +504,7 @@ enum positive_aop_returns {#define AOP_FLAG_NOFS 0x0004/* used by filesystem to direct * helper code (eg buffer layer) * to clear GFP_FS from alloc */ +#define AOP_FLAG_LAST 0x0008/* First unused private flag */ /* * oh the beauties of C type declarations.
Signature · 1 line
1.6.3.3
Quoted 7 lines · Dmitry Monakhov
Some times we call ->write_begin() with opened journal but
write_begin()may internally callext4_should_retry_alloc()in case of ENOSPC, which result in deadlock.
This patch introduce newAOP_FLAGwhich should be tested on retry alloc path.
Can you explain this further. We do a journal_stop before ext4_should_retry_alloc. So not sure about the deadlock.
-aneesh
Quoted 11 lines · Aneesh Kumar K. V
Quoted 7 lines · Dmitry Monakhov
Some times we call ->write_begin() with opened journal but
write_begin()may internally callext4_should_retry_alloc()in case of ENOSPC, which result in deadlock.
This patch introduce newAOP_FLAGwhich should be tested on retry alloc path.Can you explain this further. We do a
journal_stopbeforeext4_should_retry_alloc. So not sure about the deadlock.
move_extent_per_page
ext4_journal_start -> current->journal_info != NULL ->write_begin
ext4_journal_start
ext4_journal_stop
ext4_should_retry_alloc : here current->journal_info != NULLSorry i've missed the fact that ext4_should_retry_alloc() check for current->journal_info and skip running transaction in that case. Seems what this check was added long time ago, but i miss it. So this patch is useless.
Quoted 2 lines
-aneesh