diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-03-20 13:53:24 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:08:56 -0400 |
commit | 9487669fc225092cf315e1291ece28e23e6754f3 (patch) | |
tree | b07d2c3250f44e3262d9580295ef4ecd501ba371 /drivers/scsi | |
parent | ec236e526777ea8825e6e0c3673a40389692eabf (diff) |
[SCSI] libsas: unify domain_device sas_rphy lifetimes
Since the domain_device can out live the scsi_target we need the rphy to
follow suit otherwise we run into issues like:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000050
IP: [<ffffffffa011561b>] sas_ata_printk+0x43/0x6f [libsas]
PGD 0
Oops: 0000 [#1] SMP
CPU 1
Modules linked in: ses enclosure isci libsas scsi_transport_sas fuse sunrpc cpufreq_ondemand acpi_cpufreq freq_table mperf microcode pcspkr igb joydev iTCO_wdt ioatdma iTCO_vendor_support i2c_i801 i2c_core dca wmi hed ipv6 pata_acpi ata_generic [last unloaded: scsi_wait_scan]
Pid: 129, comm: kworker/u:3 Not tainted 3.3.0-rc5-isci+ #1 Intel Corporation SandyBridge Platform/To be filled by O.E.M.
RIP: 0010:[<ffffffffa011561b>] [<ffffffffa011561b>] sas_ata_printk+0x43/0x6f [libsas]
RSP: 0018:ffff88042232dd70 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff8804283165b8 RCX: ffff88042232dda0
RDX: ffff88042232dd78 RSI: ffff8804283165b8 RDI: ffffffffa01188d7
RBP: ffff88042232ddd0 R08: ffff880388454000 R09: ffff8803edfde1f8
R10: ffff8803edfde1f8 R11: ffff8803edfde1f8 R12: ffff880428316750
R13: ffff880388454000 R14: ffff8803f88b31d0 R15: ffff8803f8b21d50
FS: 0000000000000000(0000) GS:ffff88042ee20000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000050 CR3: 0000000001a05000 CR4: 00000000000406e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process kworker/u:3 (pid: 129, threadinfo ffff88042232c000, task ffff88042230c920)
Stack:
0000000000000000 ffff880400000018 ffff88042232dde0 ffff88042232dda0
ffffffffa01188c4 ffff88042ee93af0 ffff88042232ddb0 ffffffff8100e047
ffff88042232de10 ffff880420e5a2c8 ffff8803f8b21d50 ffff8803edfde1f8
Call Trace:
[<ffffffff8100e047>] ? load_TLS+0xb/0xf
[<ffffffffa01156ad>] async_sas_ata_eh+0x66/0x95 [libsas]
[<ffffffff810655e1>] async_run_entry_fn+0x9e/0x131
Reported-by: Tom Jackson <thomas.p.jackson@intel.com>
Tested-by: Tom Jackson <thomas.p.jackson@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 11 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 6 |
2 files changed, 10 insertions, 7 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 658f16cc2f03..13b5891f9961 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -151,6 +151,7 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
151 | sas_device_set_phy(dev, port->port); | 151 | sas_device_set_phy(dev, port->port); |
152 | 152 | ||
153 | dev->rphy = rphy; | 153 | dev->rphy = rphy; |
154 | get_device(&dev->rphy->dev); | ||
154 | 155 | ||
155 | if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) | 156 | if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) |
156 | list_add_tail(&dev->disco_list_node, &port->disco_list); | 157 | list_add_tail(&dev->disco_list_node, &port->disco_list); |
@@ -255,6 +256,9 @@ void sas_free_device(struct kref *kref) | |||
255 | { | 256 | { |
256 | struct domain_device *dev = container_of(kref, typeof(*dev), kref); | 257 | struct domain_device *dev = container_of(kref, typeof(*dev), kref); |
257 | 258 | ||
259 | put_device(&dev->rphy->dev); | ||
260 | dev->rphy = NULL; | ||
261 | |||
258 | if (dev->parent) | 262 | if (dev->parent) |
259 | sas_put_device(dev->parent); | 263 | sas_put_device(dev->parent); |
260 | 264 | ||
@@ -301,7 +305,6 @@ static void sas_destruct_devices(struct work_struct *work) | |||
301 | 305 | ||
302 | sas_remove_children(&dev->rphy->dev); | 306 | sas_remove_children(&dev->rphy->dev); |
303 | sas_rphy_delete(dev->rphy); | 307 | sas_rphy_delete(dev->rphy); |
304 | dev->rphy = NULL; | ||
305 | sas_unregister_common_dev(port, dev); | 308 | sas_unregister_common_dev(port, dev); |
306 | } | 309 | } |
307 | } | 310 | } |
@@ -313,11 +316,11 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | |||
313 | /* this rphy never saw sas_rphy_add */ | 316 | /* this rphy never saw sas_rphy_add */ |
314 | list_del_init(&dev->disco_list_node); | 317 | list_del_init(&dev->disco_list_node); |
315 | sas_rphy_free(dev->rphy); | 318 | sas_rphy_free(dev->rphy); |
316 | dev->rphy = NULL; | ||
317 | sas_unregister_common_dev(port, dev); | 319 | sas_unregister_common_dev(port, dev); |
320 | return; | ||
318 | } | 321 | } |
319 | 322 | ||
320 | if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { | 323 | if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { |
321 | sas_rphy_unlink(dev->rphy); | 324 | sas_rphy_unlink(dev->rphy); |
322 | list_move_tail(&dev->disco_list_node, &port->destroy_list); | 325 | list_move_tail(&dev->disco_list_node, &port->destroy_list); |
323 | sas_discover_event(dev->port, DISCE_DESTRUCT); | 326 | sas_discover_event(dev->port, DISCE_DESTRUCT); |
@@ -417,8 +420,6 @@ static void sas_discover_domain(struct work_struct *work) | |||
417 | 420 | ||
418 | if (error) { | 421 | if (error) { |
419 | sas_rphy_free(dev->rphy); | 422 | sas_rphy_free(dev->rphy); |
420 | dev->rphy = NULL; | ||
421 | |||
422 | list_del_init(&dev->disco_list_node); | 423 | list_del_init(&dev->disco_list_node); |
423 | spin_lock_irq(&port->dev_list_lock); | 424 | spin_lock_irq(&port->dev_list_lock); |
424 | list_del_init(&dev->dev_list_node); | 425 | list_del_init(&dev->dev_list_node); |
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 833bea067a77..37c3c3f5f35d 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -783,6 +783,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
783 | sas_init_dev(child); | 783 | sas_init_dev(child); |
784 | 784 | ||
785 | child->rphy = rphy; | 785 | child->rphy = rphy; |
786 | get_device(&rphy->dev); | ||
786 | 787 | ||
787 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); | 788 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); |
788 | 789 | ||
@@ -806,6 +807,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
806 | sas_init_dev(child); | 807 | sas_init_dev(child); |
807 | 808 | ||
808 | child->rphy = rphy; | 809 | child->rphy = rphy; |
810 | get_device(&rphy->dev); | ||
809 | sas_fill_in_rphy(child, rphy); | 811 | sas_fill_in_rphy(child, rphy); |
810 | 812 | ||
811 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); | 813 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); |
@@ -830,8 +832,6 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
830 | 832 | ||
831 | out_list_del: | 833 | out_list_del: |
832 | sas_rphy_free(child->rphy); | 834 | sas_rphy_free(child->rphy); |
833 | child->rphy = NULL; | ||
834 | |||
835 | list_del(&child->disco_list_node); | 835 | list_del(&child->disco_list_node); |
836 | spin_lock_irq(&parent->port->dev_list_lock); | 836 | spin_lock_irq(&parent->port->dev_list_lock); |
837 | list_del(&child->dev_list_node); | 837 | list_del(&child->dev_list_node); |
@@ -911,6 +911,7 @@ static struct domain_device *sas_ex_discover_expander( | |||
911 | } | 911 | } |
912 | port = parent->port; | 912 | port = parent->port; |
913 | child->rphy = rphy; | 913 | child->rphy = rphy; |
914 | get_device(&rphy->dev); | ||
914 | edev = rphy_to_expander_device(rphy); | 915 | edev = rphy_to_expander_device(rphy); |
915 | child->dev_type = phy->attached_dev_type; | 916 | child->dev_type = phy->attached_dev_type; |
916 | kref_get(&parent->kref); | 917 | kref_get(&parent->kref); |
@@ -934,6 +935,7 @@ static struct domain_device *sas_ex_discover_expander( | |||
934 | 935 | ||
935 | res = sas_discover_expander(child); | 936 | res = sas_discover_expander(child); |
936 | if (res) { | 937 | if (res) { |
938 | sas_rphy_delete(rphy); | ||
937 | spin_lock_irq(&parent->port->dev_list_lock); | 939 | spin_lock_irq(&parent->port->dev_list_lock); |
938 | list_del(&child->dev_list_node); | 940 | list_del(&child->dev_list_node); |
939 | spin_unlock_irq(&parent->port->dev_list_lock); | 941 | spin_unlock_irq(&parent->port->dev_list_lock); |