ocfs2: fix dead lock caused by ocfs2_defrag_extent
PATCH v2 1/1 ocfs2: fix dead lock caused by ocfs2_defrag_extent
ocfs2_defrag_extent may fall into dead lock.
ocfs2_ioctl_move_extents
ocfs2_ioctl_move_extents
ocfs2_move_extents
ocfs2_defrag_extent
ocfs2_lock_allocators_move_extents
ocfs2_reserve_clusters
inode_lock GLOBAL_BITMAP_SYSTEM_INODE
__ocfs2_flush_truncate_log
inode_lock GLOBAL_BITMAP_SYSTEM_INODE
As back trace shows above, ocfs2_reserve_clusters will call inode_lock against the global bitmap if local allocator has not sufficient cluters. Once global bitmap could meet the demand, ocfs2_reserve_cluster will return success with global bitmap locked.
After ocfs2_reserve_cluster, if truncate log is full, __ocfs2_flush_truncate_log will definitely fall into dead lock because it needs to inode_lock global bitmap, which has already been locked.
To fix this bug, we could remove from ocfs2_lock_allocators_move_extents the code which intends to lock global allocator, and put the removed code after __ocfs2_flush_truncate_log
The ocfs2_lock_allocators_move_extents has been refered by 2 places, one is here, the other does not need the data allocator context, which means this patch does not affect the caller so far.
Change log:
1. rename ocfs2_lock_allocators_move_extents to
ocfs2_lock_meta_allocator_move_extents
2. add some comments
--- fs/ocfs2/move_extents.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
fs/ocfs2/move_extents.c +25 -15
@@ -162,7 +162,7 @@ static int __ocfs2_move_extent(handle_t *handle,* in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ -static int ocfs2_lock_allocators_move_extents(struct inode *inode, +static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split,
@@ -192,13 +192,6 @@ static int ocfs2_lock_allocators_move_extents(struct inode *inode, goto out; } -if (data_ac) { - ret =ocfs2_reserve_clusters (osb, clusters_to_move, data_ac); -if (ret) { -mlog_errno (ret); - goto out; - } - } *credits +=ocfs2_calc_extend_credits (osb->sb, et->et_root_el);
@@ -257,10 +250,11 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context, } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, *len,1 , - &context->meta_ac, - &context->data_ac, - extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + *len,1 , + &context->meta_ac, + &context->data_ac, + extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;
@@ -283,6 +277,21 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context, } } +/* +* Make sure ocfs2_reserve_cluster is called after +* __ocfs2_flush_truncate_log, otherwise, dead lock may happen. +* +* If ocfs2_reserve_cluster is called +* before __ocfs2_flush_truncate_log, dead lock on global bitmap +* may happen. +* +*/ + ret =ocfs2_reserve_clusters (osb, *len, &context->data_ac); +if (ret) { +mlog_errno (ret); + goto out_unlock_mutex; + } + handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { ret =PTR_ERR (handle);
@@ -600,9 +609,10 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context, } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, len,1 , - &context->meta_ac, -NULL , extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + len,1 , + &context->meta_ac, +NULL , extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;
Signature · 1 line
2.13.7
Folks, could we please review this patch for upstream inclusion?
Thanks.
From: Larry Chen <[email protected]>
Subject: ocfs2: fix deadlock caused by ocfs2_defrag_extent
ocfs2_defrag_extent may fall into deadlock.
ocfs2_ioctl_move_extents
ocfs2_ioctl_move_extents
ocfs2_move_extents
ocfs2_defrag_extent
ocfs2_lock_allocators_move_extents
ocfs2_reserve_clusters
inode_lock GLOBAL_BITMAP_SYSTEM_INODE
__ocfs2_flush_truncate_log
inode_lock GLOBAL_BITMAP_SYSTEM_INODE
As backtrace shows above, ocfs2_reserve_clusters() will call inode_lock against the global bitmap if local allocator has not sufficient cluters. Once global bitmap could meet the demand, ocfs2_reserve_cluster will return success with global bitmap locked.
After ocfs2_reserve_cluster(), if truncate log is full, __ocfs2_flush_truncate_log() will definitely fall into deadlock because it needs to inode_lock global bitmap, which has already been locked.
To fix this bug, we could remove from ocfs2_lock_allocators_move_extents() the code which intends to lock global allocator, and put the removed code after __ocfs2_flush_truncate_log().
ocfs2_lock_allocators_move_extents() is refered by 2 places, one is here, the other does not need the data allocator context, which means this patch does not affect the caller so far.
---
fs/ocfs2/move_extents.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +25 -15
@@ -162,7 +162,7 @@ out:* in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ -static int ocfs2_lock_allocators_move_extents(struct inode *inode, +static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split,
@@ -192,13 +192,6 @@ static int ocfs2_lock_allocators_move_ex goto out; } -if (data_ac) { - ret =ocfs2_reserve_clusters (osb, clusters_to_move, data_ac); -if (ret) { -mlog_errno (ret); - goto out; - } - } *credits +=ocfs2_calc_extend_credits (osb->sb, et->et_root_el);
@@ -257,10 +250,11 @@ static int ocfs2_defrag_extent(struct oc } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, *len,1 , - &context->meta_ac, - &context->data_ac, - extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + *len,1 , + &context->meta_ac, + &context->data_ac, + extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;
@@ -283,6 +277,21 @@ static int ocfs2_defrag_extent(struct oc } } +/* +* Make sure ocfs2_reserve_cluster is called after +* __ocfs2_flush_truncate_log, otherwise, dead lock may happen. +* +* If ocfs2_reserve_cluster is called +* before __ocfs2_flush_truncate_log, dead lock on global bitmap +* may happen. +* +*/ + ret =ocfs2_reserve_clusters (osb, *len, &context->data_ac); +if (ret) { +mlog_errno (ret); + goto out_unlock_mutex; + } + handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { ret =PTR_ERR (handle);
@@ -600,9 +609,10 @@ static int ocfs2_move_extent(struct ocfs } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, len,1 , - &context->meta_ac, -NULL , extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + len,1 , + &context->meta_ac, +NULL , extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;
_
Hi Larry,
I still have a few tiny comments for your patch, please refer to them.
Quoted 58 lines · Andrew Morton
Folks, could we please review this patch for upstream inclusion?
Thanks.
From: Larry Chen <[email protected]>
Subject: ocfs2: fix deadlock caused byocfs2_defrag_extent
ocfs2_defrag_extentmay fall into deadlock.
ocfs2_ioctl_move_extents
ocfs2_ioctl_move_extents
ocfs2_move_extents
ocfs2_defrag_extent
ocfs2_lock_allocators_move_extents
ocfs2_reserve_clusters
inode_lockGLOBAL_BITMAP_SYSTEM_INODE
__ocfs2_flush_truncate_log
inode_lockGLOBAL_BITMAP_SYSTEM_INODEAs backtrace shows above,
ocfs2_reserve_clusters()will callinode_lockagainst the global bitmap if local allocator has not sufficient cluters. Once global bitmap could meet the demand,ocfs2_reserve_clusterwill return success with global bitmap locked.After
ocfs2_reserve_cluster(), if truncate log is full,__ocfs2_flush_truncate_log()will definitely fall into deadlock because it needs toinode_lockglobal bitmap, which has already been locked.To fix this bug, we could remove from
ocfs2_lock_allocators_move_extents()the code which intends to lock global allocator, and put the removed code after__ocfs2_flush_truncate_log().
ocfs2_lock_allocators_move_extents()is refered by 2 places, one is here, the other does not need the data allocator context, which means this patch does not affect the caller so far.[lchen at suse.com: rename ocfs2_lock_allocators_move_extents() to ocfs2_lock_meta_allocator_move_extents(), add some comments]Signed-off-by Larry Chen <[email protected]>Cc Mark Fasheh <[email protected]>Cc Joel Becker <[email protected]>Cc Junxiao Bi <[email protected]>Cc Joseph Qi <[email protected]>Cc Changwei Ge <[email protected]>Signed-off-by Andrew Morton <[email protected]>---
fs/ocfs2/move_extents.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
fs/ocfs2/move_extents.c out: · line 168
Quoted 8 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +1
-1@@ -162,7 +162,7 @@ out:* in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ -static int ocfs2_lock_allocators_move_extents(struct inode *inode, +static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split,
After removing 'reserving clusters logic' out of this function, I suggest to also change the function header comments. And I think there is no need for arguments _data_ac_ now.
Otherwise this patch looks sane to me.
Thanks,
Changwei
Quoted 74 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +24
-14@@ -192,13 +192,6 @@ static int ocfs2_lock_allocators_move_ex goto out; } -if (data_ac) { - ret =ocfs2_reserve_clusters (osb, clusters_to_move, data_ac); -if (ret) { -mlog_errno (ret); - goto out; - } - } *credits +=ocfs2_calc_extend_credits (osb->sb, et->et_root_el);@@ -257,10 +250,11 @@ static int ocfs2_defrag_extent(struct oc } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, *len,1 , - &context->meta_ac, - &context->data_ac, - extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + *len,1 , + &context->meta_ac, + &context->data_ac, + extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;@@ -283,6 +277,21 @@ static int ocfs2_defrag_extent(struct oc } } +/* +* Make sure ocfs2_reserve_cluster is called after +* __ocfs2_flush_truncate_log, otherwise, dead lock may happen. +* +* If ocfs2_reserve_cluster is called +* before __ocfs2_flush_truncate_log, dead lock on global bitmap +* may happen. +* +*/ + ret =ocfs2_reserve_clusters (osb, *len, &context->data_ac); +if (ret) { +mlog_errno (ret); + goto out_unlock_mutex; + } + handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { ret =PTR_ERR (handle);@@ -600,9 +609,10 @@ static int ocfs2_move_extent(struct ocfs } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, len,1 , - &context->meta_ac, -NULL , extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + len,1 , + &context->meta_ac, +NULL , extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;_
_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel
Hi Changwei,
Thanks for your review, I'll improve my patch and resend it later.
Thanks
Larry
Quoted 154 lines · Changwei Ge
Hi Larry,
I still have a few tiny comments for your patch, please refer to them.
Quoted 58 lines · Andrew Morton
Folks, could we please review this patch for upstream inclusion?
Thanks.
From: Larry Chen <[email protected]>
Subject: ocfs2: fix deadlock caused byocfs2_defrag_extent
ocfs2_defrag_extentmay fall into deadlock.
ocfs2_ioctl_move_extents
ocfs2_ioctl_move_extents
ocfs2_move_extents
ocfs2_defrag_extent
ocfs2_lock_allocators_move_extents
ocfs2_reserve_clusters
inode_lockGLOBAL_BITMAP_SYSTEM_INODE
__ocfs2_flush_truncate_log
inode_lockGLOBAL_BITMAP_SYSTEM_INODEAs backtrace shows above,
ocfs2_reserve_clusters()will callinode_lockagainst the global bitmap if local allocator has not sufficient cluters. Once global bitmap could meet the demand,ocfs2_reserve_clusterwill return success with global bitmap locked.After
ocfs2_reserve_cluster(), if truncate log is full,__ocfs2_flush_truncate_log()will definitely fall into deadlock because it needs toinode_lockglobal bitmap, which has already been locked.To fix this bug, we could remove from
ocfs2_lock_allocators_move_extents()the code which intends to lock global allocator, and put the removed code after__ocfs2_flush_truncate_log().
ocfs2_lock_allocators_move_extents()is refered by 2 places, one is here, the other does not need the data allocator context, which means this patch does not affect the caller so far.[lchen at suse.com: rename
ocfs2_lock_allocators_move_extents()toocfs2_lock_meta_allocator_move_extents(), add some comments]Link: https://urldefense.proofpoint.com/v2/url?u=http-3A__lkml.kernel.org_r_20180902091455.23862-2D1-2Dlchen-40suse.com&d=DwICAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=C7gAd4uDxlAvTdc0vmU6X8CMk6L2iDY8-HD0qT6Fo7Y&m=K8aRgOiMescamJW-IuHq-cW4mWedGQv2JTT-2KPy1RI&s=3fQHFtwgixirPeQ5Px4fRBnd_UcSx3rvSsLKLidwESo&e=Signed-off-by Larry Chen <[email protected]>Cc Mark Fasheh <[email protected]>Cc Joel Becker <[email protected]>Cc Junxiao Bi <[email protected]>Cc Joseph Qi <[email protected]>Cc Changwei Ge <[email protected]>Signed-off-by Andrew Morton <[email protected]>---
fs/ocfs2/move_extents.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)fs/ocfs2/move_extents.c out: · line 168
Quoted 8 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +1
-1@@ -162,7 +162,7 @@ out:* in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ -static int ocfs2_lock_allocators_move_extents(struct inode *inode, +static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split,After removing 'reserving clusters logic' out of this function, I suggest to also change the function header comments. And I think there is no need for arguments _data_ac_ now.
Otherwise this patch looks sane to me.Thanks,
ChangweiQuoted 74 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +24
-14@@ -192,13 +192,6 @@ static int ocfs2_lock_allocators_move_ex goto out; } -if (data_ac) { - ret =ocfs2_reserve_clusters (osb, clusters_to_move, data_ac); -if (ret) { -mlog_errno (ret); - goto out; - } - } *credits +=ocfs2_calc_extend_credits (osb->sb, et->et_root_el);@@ -257,10 +250,11 @@ static int ocfs2_defrag_extent(struct oc } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, *len,1 , - &context->meta_ac, - &context->data_ac, - extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + *len,1 , + &context->meta_ac, + &context->data_ac, + extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;@@ -283,6 +277,21 @@ static int ocfs2_defrag_extent(struct oc } } +/* +* Make sure ocfs2_reserve_cluster is called after +* __ocfs2_flush_truncate_log, otherwise, dead lock may happen. +* +* If ocfs2_reserve_cluster is called +* before __ocfs2_flush_truncate_log, dead lock on global bitmap +* may happen. +* +*/ + ret =ocfs2_reserve_clusters (osb, *len, &context->data_ac); +if (ret) { +mlog_errno (ret); + goto out_unlock_mutex; + } + handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { ret =PTR_ERR (handle);@@ -600,9 +609,10 @@ static int ocfs2_move_extent(struct ocfs } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, len,1 , - &context->meta_ac, -NULL , extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + len,1 , + &context->meta_ac, +NULL , extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;_
_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel
Quoted 60 lines · Changwei Ge
Hi Larry,
I still have a few tiny comments for your patch, please refer to them.
Quoted 55 lines · Andrew Morton
Folks, could we please review this patch for upstream inclusion?
Thanks.
From: Larry Chen <[email protected]>
Subject: ocfs2: fix deadlock caused byocfs2_defrag_extent
ocfs2_defrag_extentmay fall into deadlock.
ocfs2_ioctl_move_extents
ocfs2_ioctl_move_extents
ocfs2_move_extents
ocfs2_defrag_extent
ocfs2_lock_allocators_move_extents
ocfs2_reserve_clusters
inode_lockGLOBAL_BITMAP_SYSTEM_INODE
__ocfs2_flush_truncate_log
inode_lockGLOBAL_BITMAP_SYSTEM_INODEAs backtrace shows above,
ocfs2_reserve_clusters()will callinode_lockagainst the global bitmap if local allocator has not sufficient cluters. Once global bitmap could meet the demand,ocfs2_reserve_clusterwill return success with global bitmap locked.After
ocfs2_reserve_cluster(), if truncate log is full,__ocfs2_flush_truncate_log()will definitely fall into deadlock because it needs toinode_lockglobal bitmap, which has already been locked.To fix this bug, we could remove from
ocfs2_lock_allocators_move_extents()the code which intends to lock global allocator, and put the removed code after__ocfs2_flush_truncate_log().
ocfs2_lock_allocators_move_extents()is refered by 2 places, one is here, the other does not need the data allocator context, which means this patch does not affect the caller so far.[lchen at suse.com: rename ocfs2_lock_allocators_move_extents() to ocfs2_lock_meta_allocator_move_extents(), add some comments]Signed-off-by Larry Chen <[email protected]>Cc Mark Fasheh <[email protected]>Cc Joel Becker <[email protected]>Cc Junxiao Bi <[email protected]>Cc Joseph Qi <[email protected]>Cc Changwei Ge <[email protected]>Signed-off-by Andrew Morton <[email protected]>---
fs/ocfs2/move_extents.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
Quoted 16 lines
fs/ocfs2/move_extents.c out: · line 168
Quoted 11 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +1
-1@@ -162,7 +162,7 @@ out:* in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ -static int ocfs2_lock_allocators_move_extents(struct inode *inode, +static int ocfs2_lock_meta_allocator_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split,After removing 'reserving clusters logic' out of this function, I suggest to also change the function header comments. And I think there is no need for arguments _data_ac_ now.
Otherwise this patch looks sane to me.
Agree, I think I have commented this out before.
Thanks,
Joseph
Quoted 83 lines
Thanks,
ChangweiQuoted 69 lines
fs/ocfs2/move_extents.c renamed from fs/ocfs2/move_extents.c~fix-dead-lock-caused-by-ocfs2_defrag_extent +24
-14@@ -192,13 +192,6 @@ static int ocfs2_lock_allocators_move_ex goto out; } -if (data_ac) { - ret =ocfs2_reserve_clusters (osb, clusters_to_move, data_ac); -if (ret) { -mlog_errno (ret); - goto out; - } - } *credits +=ocfs2_calc_extend_credits (osb->sb, et->et_root_el);@@ -257,10 +250,11 @@ static int ocfs2_defrag_extent(struct oc } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, *len,1 , - &context->meta_ac, - &context->data_ac, - extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + *len,1 , + &context->meta_ac, + &context->data_ac, + extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;@@ -283,6 +277,21 @@ static int ocfs2_defrag_extent(struct oc } } +/* +* Make sure ocfs2_reserve_cluster is called after +* __ocfs2_flush_truncate_log, otherwise, dead lock may happen. +* +* If ocfs2_reserve_cluster is called +* before __ocfs2_flush_truncate_log, dead lock on global bitmap +* may happen. +* +*/ + ret =ocfs2_reserve_clusters (osb, *len, &context->data_ac); +if (ret) { +mlog_errno (ret); + goto out_unlock_mutex; + } + handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { ret =PTR_ERR (handle);@@ -600,9 +609,10 @@ static int ocfs2_move_extent(struct ocfs } } - ret =ocfs2_lock_allocators_move_extents (inode, &context->et, len,1 , - &context->meta_ac, -NULL , extra_blocks, &credits); + ret =ocfs2_lock_meta_allocator_move_extents (inode, &context->et, + len,1 , + &context->meta_ac, +NULL , extra_blocks, &credits);if (ret) {mlog_errno (ret); goto out;_
Quoted 5 lines
_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel