Hello All,
I've been trying to track down the cause of some soft lockups with
call traces involving the iscsi initiator. I believe I have found a
locking error in __iscsi_conn_send_pdu that is responsible.
A previous commit (4fa507992f0a ("scsi: libiscsi: Fix locking in
__iscsi_conn_send_pdu") changed the way that __iscsi_conn_send_pdu
acquires session->back_lock, from using spin_lock_bh to using
spin_lock. However, half a dozen lines up the function is still using
spin_lock_bh to acquire conn->taskqueuelock. I think the locking for
conn->taskqueuelock should be changed in the same way the locking for
conn->session->back_lock was changed. A patch to do so follows.
Furthermore, I think that the message for the previous commit
understates the impact of the improper use of spin_lock_bh. It states
that the use of spin_lock_bh here can trigger a WARN_ONCE. I believe
it creates the possibility of deadlocks involving session->frwd_lock
and/or queue_lock, and that I have observed such a deadlock.
Here is the call trace from one soft lockup I have seen:
Call Trace:
<IRQ>
do_raw_spin_lock+0xb2/0xc0
_raw_spin_lock+0x55/0x70
iscsi_check_transport_timeouts+0x24/0x1a0 [libiscsi]
call_timer_fn+0xb9/0x3a0
? iscsi_complete_pdu+0x60/0x60 [libiscsi]
run_timer_softirq+0x254/0x650
__do_softirq+0xc5/0x4eb
? __iscsi_conn_send_pdu+0x1e3/0x420 [libiscsi]
irq_exit+0xff/0x110
smp_apic_timer_interrupt+0x3d/0x50
apic_timer_interrupt+0x9d/0xb0
RIP: 0010:__local_bh_enable_ip+0x74/0xa0
RSP: 0018:ffffb0a60a26bc98 EFLAGS: 00000246 ORIG_RAX: ffffffffffffff10
RAX: ffff901985f30000 RBX: 00000000fffffe00 RCX: 0000000000000002
RDX: ffff901985f30000 RSI: 0000000000000001 RDI: ffffffffa9837ed4
RBP: ffffb0a60a26bca8 R08: 0000000000000000 R09: 0000000000000000
R10: ffff901985f30000 R11: 0000000000000002 R12: ffffffffc01b1ca3
R13: ffff90198d8916a0 R14: ffff90199207d480 R15: ffff90199207d400
</IRQ>
? __iscsi_conn_send_pdu+0x1e3/0x420 [libiscsi]
? dump_stack+0xaa/0xc6
? __local_bh_enable_ip+0x70/0xa0
_raw_spin_unlock_bh+0x35/0x40
__iscsi_conn_send_pdu+0x1e3/0x420 [libiscsi]
iscsi_send_nopout+0xbe/0x110 [libiscsi]
iscsi_eh_cmd_timed_out+0x2b7/0x2c0 [libiscsi]
scsi_times_out+0x86/0x2b0
blk_rq_timed_out+0x1f/0x60
blk_timeout_work+0x11b/0x170
process_one_work+0x250/0x690
worker_thread+0x4e/0x3c0
kthread+0x117/0x150
? process_one_work+0x690/0x690
? kthread_create_on_node+0x70/0x70
ret_from_fork+0x2a/0x40
blk_timeout_work calls blk_rq_timed_out inside a spin_lock_irqsave, so
it should not be possible to take the softirq at this point. I
believe, but would like to someone to confirm, that it is the use of
spin_lock_bh/spin_unlock_bh that makes it possible to take the irq
here. A deadlock results from spin_lock of session->frwd_lock in the
softirq while it is already held by same cpu, having been acquired in
iscsi_eh_cmd_timed_out.
I have seen another similar soft lockup trace:
<IRQ>
queued_spin_lock_slowpath
_raw_spin_lock
iscsi_complete_pdu
iscsi_tcp_process_data_in
... network driver and tcp stack ...
net_rx_action
__do_softirq
do_softirq_own_stack
<EOI>
do_softirq
__local_bh_enable_ip
_raw_spin_unlock_bh
__iscsi_conn_send_pdu
iscsi_eh_cmd_timed_out
scsi_times_out
blk_rq_timed_out
blk_timeout_work
...
Which I think is also a deadlock involving the spin_lock of
session->frwd_lock, in this instance following case ISCSI_OP_NOOP_IN:
in __iscsi_complete_pdu.
Feedback on the proposed change, patch, and whether it would be
expected to address the soft lockups I have seen are most welcome.
Best regards,
--Chris