ocfs2: use spinlock irqsave for downconvert lock.patch
PATCH 1/1 ocfs2: use spinlock irqsave for downconvert lock.patch
When ocfs2dc thread holds dc_task_lock spinlock and receives soft IRQ it deadlock itself trying to get same spinlock in ocfs2_wake_downconvert_thread. Below is the stack snippet.
The patch disables interrupts when acquiring dc_task_lock spinlock.
ocfs2_wake_downconvert_thread ocfs2_rw_unlock ocfs2_dio_end_io dio_complete ..... bio_endio req_bio_endio .... scsi_io_completion blk_done_softirq __do_softirq do_softirq irq_exit do_IRQ ocfs2_downconvert_thread [kthread]
--- fs/ocfs2/dlmglue.c | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-)
fs/ocfs2/dlmglue.c +19 -12
@@ -3932,6 +3932,8 @@ unqueue:static void ocfs2_schedule_blocked_lock (struct ocfs2_super *osb,struct ocfs2_lock_res *lockres) { +unsigned long flags; +assert_spin_locked (&lockres->l_lock);if (lockres->l_flags &OCFS2_LOCK_FREEING ) {
@@ -3945,21 +3947,22 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,lockres_or_flags (lockres,OCFS2_LOCK_QUEUED ); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&lockres->l_blocked_list)) {list_add_tail (&lockres->l_blocked_list, &osb->blocked_lock_list); osb->blocked_lock_count++; } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static void ocfs2_downconvert_thread_do_work (struct ocfs2_super *osb) {unsigned long processed; +unsigned long flags;struct ocfs2_lock_res *lockres; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);/* grab this early so we know to try again if a state change and * wake happens part-way through our work */ osb->dc_work_sequence = osb->dc_wake_sequence;
@@ -3972,38 +3975,40 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) struct ocfs2_lock_res, l_blocked_list);list_del_init (&lockres->l_blocked_list); osb->blocked_lock_count--; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);BUG_ON (!processed); processed--;ocfs2_process_blocked_lock (osb, lockres); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags); } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static int ocfs2_downconvert_thread_lists_empty (struct ocfs2_super *osb) {int empty =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&osb->blocked_lock_list)) empty =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return empty; }static int ocfs2_downconvert_thread_should_wake (struct ocfs2_super *osb) {int should_wake =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (osb->dc_work_sequence != osb->dc_wake_sequence) should_wake =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return should_wake; }
@@ -4033,10 +4038,12 @@ static int ocfs2_downconvert_thread(void *arg)void ocfs2_wake_downconvert_thread (struct ocfs2_super *osb) { -spin_lock (&osb->dc_task_lock); +unsigned long flags; + +spin_lock_irqsave (&osb->dc_task_lock, flags);/* make sure the voting thread gets a swipe at whatever changes * the caller may have made to the voting state */ osb->dc_wake_sequence++; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);wake_up (&osb->dc_event); }
Signature · 1 line
1.5.4.3
PATCH 1/1 ocfs2: use spinlock irqsave for downconvert lock.patch
sob
Quoted 130 lines · Srinivas Eeda
When ocfs2dc thread holds
dc_task_lockspinlock and receives soft IRQ it deadlock itself trying to get same spinlock inocfs2_wake_downconvert_thread. Below is the stack snippet.The patch disables interrupts when acquiring
dc_task_lockspinlock.ocfs2_wake_downconvert_thread ocfs2_rw_unlock ocfs2_dio_end_io dio_complete ..... bio_endio req_bio_endio .... scsi_io_completion blk_done_softirq __do_softirq do_softirq irq_exit do_IRQ ocfs2_downconvert_thread [kthread]Signed-off-by Srinivas Eeda<[email protected]>--- fs/ocfs2/dlmglue.c | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-)fs/ocfs2/dlmglue.c +19
-12@@ -3932,6 +3932,8 @@ unqueue:static void ocfs2_schedule_blocked_lock (struct ocfs2_super *osb,struct ocfs2_lock_res *lockres) { +unsigned long flags; +assert_spin_locked (&lockres->l_lock);if (lockres->l_flags&OCFS2_LOCK_FREEING ) {@@ -3945,21 +3947,22 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,lockres_or_flags (lockres,OCFS2_LOCK_QUEUED ); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&lockres->l_blocked_list)) {list_add_tail (&lockres->l_blocked_list, &osb->blocked_lock_list); osb->blocked_lock_count++; } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static void ocfs2_downconvert_thread_do_work (struct ocfs2_super *osb) {unsigned long processed; +unsigned long flags;struct ocfs2_lock_res *lockres; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);/* grab this early so we know to try again if a state change and * wake happens part-way through our work */ osb->dc_work_sequence = osb->dc_wake_sequence;@@ -3972,38 +3975,40 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) struct ocfs2_lock_res, l_blocked_list);list_del_init (&lockres->l_blocked_list); osb->blocked_lock_count--; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);BUG_ON (!processed); processed--;ocfs2_process_blocked_lock (osb, lockres); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags); } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static int ocfs2_downconvert_thread_lists_empty (struct ocfs2_super *osb) {int empty =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&osb->blocked_lock_list)) empty =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return empty; }static int ocfs2_downconvert_thread_should_wake (struct ocfs2_super *osb) {int should_wake =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (osb->dc_work_sequence != osb->dc_wake_sequence) should_wake =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return should_wake; }@@ -4033,10 +4038,12 @@ static int ocfs2_downconvert_thread(void *arg)void ocfs2_wake_downconvert_thread (struct ocfs2_super *osb) { -spin_lock (&osb->dc_task_lock); +unsigned long flags; + +spin_lock_irqsave (&osb->dc_task_lock, flags);/* make sure the voting thread gets a swipe at whatever changes * the caller may have made to the voting state */ osb->dc_wake_sequence++; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);wake_up (&osb->dc_event); }
Joel Becker
maintainerPATCH 1/1 ocfs2: use spinlock irqsave for downconvert lock.patch
In reply to Srinivas EedaQuoted 23 lines · Srinivas Eeda
When ocfs2dc thread holds
dc_task_lockspinlock and receives soft IRQ it deadlock itself trying to get same spinlock inocfs2_wake_downconvert_thread. Below is the stack snippet.The patch disables interrupts when acquiring
dc_task_lockspinlock.ocfs2_wake_downconvert_thread ocfs2_rw_unlock ocfs2_dio_end_io dio_complete ..... bio_endio req_bio_endio .... scsi_io_completion blk_done_softirq __do_softirq do_softirq irq_exit do_IRQ ocfs2_downconvert_thread [kthread]
Quoted 1 line
Signed-off-by Srinivas Eeda <[email protected]>
This patch is now (finally) part of the 'fixes' branch of ocfs2.git.
Joel
Quoted 114 lines
--- fs/ocfs2/dlmglue.c | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-)fs/ocfs2/dlmglue.c +19
-12@@ -3932,6 +3932,8 @@ unqueue:static void ocfs2_schedule_blocked_lock (struct ocfs2_super *osb,struct ocfs2_lock_res *lockres) { +unsigned long flags; +assert_spin_locked (&lockres->l_lock);if (lockres->l_flags &OCFS2_LOCK_FREEING ) {@@ -3945,21 +3947,22 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,lockres_or_flags (lockres,OCFS2_LOCK_QUEUED ); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&lockres->l_blocked_list)) {list_add_tail (&lockres->l_blocked_list, &osb->blocked_lock_list); osb->blocked_lock_count++; } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static void ocfs2_downconvert_thread_do_work (struct ocfs2_super *osb) {unsigned long processed; +unsigned long flags;struct ocfs2_lock_res *lockres; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);/* grab this early so we know to try again if a state change and * wake happens part-way through our work */ osb->dc_work_sequence = osb->dc_wake_sequence;@@ -3972,38 +3975,40 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) struct ocfs2_lock_res, l_blocked_list);list_del_init (&lockres->l_blocked_list); osb->blocked_lock_count--; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);BUG_ON (!processed); processed--;ocfs2_process_blocked_lock (osb, lockres); -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags); } -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags); }static int ocfs2_downconvert_thread_lists_empty (struct ocfs2_super *osb) {int empty =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (list_empty (&osb->blocked_lock_list)) empty =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return empty; }static int ocfs2_downconvert_thread_should_wake (struct ocfs2_super *osb) {int should_wake =0 ; +unsigned long flags; -spin_lock (&osb->dc_task_lock); +spin_lock_irqsave (&osb->dc_task_lock, flags);if (osb->dc_work_sequence != osb->dc_wake_sequence) should_wake =1 ; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);return should_wake; }@@ -4033,10 +4038,12 @@ static int ocfs2_downconvert_thread(void *arg)void ocfs2_wake_downconvert_thread (struct ocfs2_super *osb) { -spin_lock (&osb->dc_task_lock); +unsigned long flags; + +spin_lock_irqsave (&osb->dc_task_lock, flags);/* make sure the voting thread gets a swipe at whatever changes * the caller may have made to the voting state */ osb->dc_wake_sequence++; -spin_unlock (&osb->dc_task_lock); +spin_unlock_irqrestore (&osb->dc_task_lock, flags);wake_up (&osb->dc_event); }Signature · 7 lines
1.5.4.3 _______________________________________________ Ocfs2-devel mailing list Ocfs2-devel at oss.oracle.com http://oss.oracle.com/mailman/listinfo/ocfs2-devel
Signature · 6 lines
Life's Little Instruction Book #222 "Think twice before burdening a friend with a secret." http://www.jlbec.org/ jlbec at evilplan.org
PATCH 1/1 ocfs2: use spinlock irqsave for downconvert lock.patch
Quoted 24 lines · Joel Becker
Quoted 23 lines · Srinivas Eeda
When ocfs2dc thread holds
dc_task_lockspinlock and receives soft IRQ it deadlock itself trying to get same spinlock inocfs2_wake_downconvert_thread. Below is the stack snippet.The patch disables interrupts when acquiring
dc_task_lockspinlock.ocfs2_wake_downconvert_thread ocfs2_rw_unlock ocfs2_dio_end_io dio_complete ..... bio_endio req_bio_endio .... scsi_io_completion blk_done_softirq __do_softirq do_softirq irq_exit do_IRQ ocfs2_downconvert_thread [kthread]
Quoted 4 lines
Quoted 1 line
Signed-off-by Srinivas Eeda <[email protected]>This patch is now (finally) part of the 'fixes' branch of ocfs2.git.
Recently we hit this bug too, and planned to send exactly the same fix..