Commit 9487669f authored by Dan Williams's avatar Dan Williams Committed by James Bottomley

[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: default avatarTom Jackson <thomas.p.jackson@intel.com>
Tested-by: default avatarTom Jackson <thomas.p.jackson@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent ec236e52
...@@ -151,6 +151,7 @@ static int sas_get_port_device(struct asd_sas_port *port) ...@@ -151,6 +151,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
sas_device_set_phy(dev, port->port); sas_device_set_phy(dev, port->port);
dev->rphy = rphy; dev->rphy = rphy;
get_device(&dev->rphy->dev);
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV)
list_add_tail(&dev->disco_list_node, &port->disco_list); list_add_tail(&dev->disco_list_node, &port->disco_list);
...@@ -255,6 +256,9 @@ void sas_free_device(struct kref *kref) ...@@ -255,6 +256,9 @@ void sas_free_device(struct kref *kref)
{ {
struct domain_device *dev = container_of(kref, typeof(*dev), kref); struct domain_device *dev = container_of(kref, typeof(*dev), kref);
put_device(&dev->rphy->dev);
dev->rphy = NULL;
if (dev->parent) if (dev->parent)
sas_put_device(dev->parent); sas_put_device(dev->parent);
...@@ -301,7 +305,6 @@ static void sas_destruct_devices(struct work_struct *work) ...@@ -301,7 +305,6 @@ static void sas_destruct_devices(struct work_struct *work)
sas_remove_children(&dev->rphy->dev); sas_remove_children(&dev->rphy->dev);
sas_rphy_delete(dev->rphy); sas_rphy_delete(dev->rphy);
dev->rphy = NULL;
sas_unregister_common_dev(port, dev); sas_unregister_common_dev(port, dev);
} }
} }
...@@ -313,11 +316,11 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) ...@@ -313,11 +316,11 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
/* this rphy never saw sas_rphy_add */ /* this rphy never saw sas_rphy_add */
list_del_init(&dev->disco_list_node); list_del_init(&dev->disco_list_node);
sas_rphy_free(dev->rphy); sas_rphy_free(dev->rphy);
dev->rphy = NULL;
sas_unregister_common_dev(port, dev); sas_unregister_common_dev(port, dev);
return;
} }
if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
sas_rphy_unlink(dev->rphy); sas_rphy_unlink(dev->rphy);
list_move_tail(&dev->disco_list_node, &port->destroy_list); list_move_tail(&dev->disco_list_node, &port->destroy_list);
sas_discover_event(dev->port, DISCE_DESTRUCT); sas_discover_event(dev->port, DISCE_DESTRUCT);
...@@ -417,8 +420,6 @@ static void sas_discover_domain(struct work_struct *work) ...@@ -417,8 +420,6 @@ static void sas_discover_domain(struct work_struct *work)
if (error) { if (error) {
sas_rphy_free(dev->rphy); sas_rphy_free(dev->rphy);
dev->rphy = NULL;
list_del_init(&dev->disco_list_node); list_del_init(&dev->disco_list_node);
spin_lock_irq(&port->dev_list_lock); spin_lock_irq(&port->dev_list_lock);
list_del_init(&dev->dev_list_node); list_del_init(&dev->dev_list_node);
......
...@@ -783,6 +783,7 @@ static struct domain_device *sas_ex_discover_end_dev( ...@@ -783,6 +783,7 @@ static struct domain_device *sas_ex_discover_end_dev(
sas_init_dev(child); sas_init_dev(child);
child->rphy = rphy; child->rphy = rphy;
get_device(&rphy->dev);
list_add_tail(&child->disco_list_node, &parent->port->disco_list); list_add_tail(&child->disco_list_node, &parent->port->disco_list);
...@@ -806,6 +807,7 @@ static struct domain_device *sas_ex_discover_end_dev( ...@@ -806,6 +807,7 @@ static struct domain_device *sas_ex_discover_end_dev(
sas_init_dev(child); sas_init_dev(child);
child->rphy = rphy; child->rphy = rphy;
get_device(&rphy->dev);
sas_fill_in_rphy(child, rphy); sas_fill_in_rphy(child, rphy);
list_add_tail(&child->disco_list_node, &parent->port->disco_list); 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,8 +832,6 @@ static struct domain_device *sas_ex_discover_end_dev(
out_list_del: out_list_del:
sas_rphy_free(child->rphy); sas_rphy_free(child->rphy);
child->rphy = NULL;
list_del(&child->disco_list_node); list_del(&child->disco_list_node);
spin_lock_irq(&parent->port->dev_list_lock); spin_lock_irq(&parent->port->dev_list_lock);
list_del(&child->dev_list_node); list_del(&child->dev_list_node);
...@@ -911,6 +911,7 @@ static struct domain_device *sas_ex_discover_expander( ...@@ -911,6 +911,7 @@ static struct domain_device *sas_ex_discover_expander(
} }
port = parent->port; port = parent->port;
child->rphy = rphy; child->rphy = rphy;
get_device(&rphy->dev);
edev = rphy_to_expander_device(rphy); edev = rphy_to_expander_device(rphy);
child->dev_type = phy->attached_dev_type; child->dev_type = phy->attached_dev_type;
kref_get(&parent->kref); kref_get(&parent->kref);
...@@ -934,6 +935,7 @@ static struct domain_device *sas_ex_discover_expander( ...@@ -934,6 +935,7 @@ static struct domain_device *sas_ex_discover_expander(
res = sas_discover_expander(child); res = sas_discover_expander(child);
if (res) { if (res) {
sas_rphy_delete(rphy);
spin_lock_irq(&parent->port->dev_list_lock); spin_lock_irq(&parent->port->dev_list_lock);
list_del(&child->dev_list_node); list_del(&child->dev_list_node);
spin_unlock_irq(&parent->port->dev_list_lock); spin_unlock_irq(&parent->port->dev_list_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment