Fix race when removing SCSI devices
commit
546ae796bfac6399e30da4b5af2cf7a6d0f8a4ec upstream.
Removing SCSI devices through
echo 1 > /sys/bus/scsi/devices/ ... /delete
while the FC transport class removes the SCSI target can lead to an
oops:
Unable to handle kernel pointer dereference at virtual kernel address
00000000b6815000
Oops: 0011 [#1] PREEMPT SMP DEBUG_PAGEALLOC
Modules linked in: sunrpc qeth_l3 binfmt_misc dm_multipath scsi_dh dm_mod ipv6 qeth ccwgroup [last unloaded: scsi_wait_scan]
CPU: 1 Not tainted 2.6.35.5-45.x.
20100924-s390xdefault #1
Process fc_wq_0 (pid: 861, task:
00000000b7331240, ksp:
00000000b735bac0)
Krnl PSW :
0704200180000000 00000000003ff6e4 (__scsi_remove_device+0x24/0xd0)
R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:0 CC:2 PM:0 EA:3
Krnl GPRS:
0000000000000001 0000000000000000 00000000b6815000 00000000bc24a8c0
00000000003ff7c8 000000000056dbb8 0000000000000002 0000000000835d80
ffffffff00000000 0000000000001000 00000000b6815000 00000000bc24a7f0
00000000b68151a0 00000000b6815000 00000000b735bc20 00000000b735bbf8
Krnl Code:
00000000003ff6d6:
a7840001 brc 8,3ff6d8
00000000003ff6da:
a7fbffd8 aghi %r15,-40
00000000003ff6de:
e3e0f0980024 stg %r14,152(%r15)
>
00000000003ff6e4:
e31021200004 lg %r1,288(%r2)
00000000003ff6ea:
a71f0000 cghi %r1,0
00000000003ff6ee:
a7a40011 brc 10,3ff710
00000000003ff6f2:
a7390003 lghi %r3,3
00000000003ff6f6:
c0e5ffffc8b1 brasl %r14,3f8858
Call Trace:
([<
0000000000001000>] 0x1000)
[<
00000000003ff7d2>] scsi_remove_device+0x42/0x54
[<
00000000003ff8ba>] __scsi_remove_target+0xca/0xfc
[<
00000000003ff99a>] __remove_child+0x3a/0x48
[<
00000000003e3246>] device_for_each_child+0x72/0xbc
[<
00000000003ff93a>] scsi_remove_target+0x4e/0x74
[<
0000000000406586>] fc_rport_final_delete+0xb2/0x23c
[<
000000000015d080>] worker_thread+0x200/0x344
[<
000000000016330c>] kthread+0xa0/0xa8
[<
0000000000106c1a>] kernel_thread_starter+0x6/0xc
[<
0000000000106c14>] kernel_thread_starter+0x0/0xc
INFO: lockdep is turned off.
Last Breaking-Event-Address:
[<
00000000003ff7cc>] scsi_remove_device+0x3c/0x54
The function __scsi_remove_target iterates through the SCSI devices on
the host, but it drops the host_lock before calling
scsi_remove_device. When the SCSI device is deleted from another
thread, the pointer to the SCSI device in scsi_remove_device can
become invalid. Fix this by getting a reference to the SCSI device
before dropping the host_lock to keep the SCSI device alive for the
call to scsi_remove_device.
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>