From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dan Williams Subject: [PATCH 06/12] libsas: unify domain_device sas_rphy lifetimes Date: Fri, 13 Apr 2012 16:37:22 -0700 Message-ID: <20120413233722.8025.58168.stgit@dwillia2-linux.jf.intel.com> References: <20120413233343.8025.18101.stgit@dwillia2-linux.jf.intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Return-path: Received: from mga03.intel.com ([143.182.124.21]:12111 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932433Ab2DMXVt (ORCPT ); Fri, 13 Apr 2012 19:21:49 -0400 In-Reply-To: <20120413233343.8025.18101.stgit@dwillia2-linux.jf.intel.com> Sender: linux-ide-owner@vger.kernel.org List-Id: linux-ide@vger.kernel.org To: JBottomley@parallels.com Cc: Tom Jackson , linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org 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: [] 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:[] [] 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: [] ? load_TLS+0xb/0xf [] async_sas_ata_eh+0x66/0x95 [libsas] [] async_run_entry_fn+0x9e/0x131 Reported-by: Tom Jackson Tested-by: Tom Jackson Signed-off-by: Dan Williams --- drivers/scsi/libsas/sas_discover.c | 11 ++++++----- 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 4da5ea8..128160d 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) sas_device_set_phy(dev, port->port); dev->rphy = rphy; + get_device(&dev->rphy->dev); if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) list_add_tail(&dev->disco_list_node, &port->disco_list); @@ -255,6 +256,9 @@ void sas_free_device(struct kref *kref) { struct domain_device *dev = container_of(kref, typeof(*dev), kref); + put_device(&dev->rphy->dev); + dev->rphy = NULL; + if (dev->parent) sas_put_device(dev->parent); @@ -303,7 +307,6 @@ static void sas_destruct_devices(struct work_struct *work) sas_remove_children(&dev->rphy->dev); sas_rphy_delete(dev->rphy); - dev->rphy = NULL; sas_unregister_common_dev(port, dev); } } @@ -315,11 +318,11 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) /* this rphy never saw sas_rphy_add */ list_del_init(&dev->disco_list_node); sas_rphy_free(dev->rphy); - dev->rphy = NULL; 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); list_move_tail(&dev->disco_list_node, &port->destroy_list); sas_discover_event(dev->port, DISCE_DESTRUCT); @@ -419,8 +422,6 @@ static void sas_discover_domain(struct work_struct *work) if (error) { sas_rphy_free(dev->rphy); - dev->rphy = NULL; - list_del_init(&dev->disco_list_node); spin_lock_irq(&port->dev_list_lock); list_del_init(&dev->dev_list_node); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 833bea0..37c3c3f 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( sas_init_dev(child); child->rphy = rphy; + get_device(&rphy->dev); list_add_tail(&child->disco_list_node, &parent->port->disco_list); @@ -806,6 +807,7 @@ static struct domain_device *sas_ex_discover_end_dev( sas_init_dev(child); child->rphy = rphy; + get_device(&rphy->dev); sas_fill_in_rphy(child, rphy); list_add_tail(&child->disco_list_node, &parent->port->disco_list); @@ -830,8 +832,6 @@ static struct domain_device *sas_ex_discover_end_dev( out_list_del: sas_rphy_free(child->rphy); - child->rphy = NULL; - list_del(&child->disco_list_node); spin_lock_irq(&parent->port->dev_list_lock); list_del(&child->dev_list_node); @@ -911,6 +911,7 @@ static struct domain_device *sas_ex_discover_expander( } port = parent->port; child->rphy = rphy; + get_device(&rphy->dev); edev = rphy_to_expander_device(rphy); child->dev_type = phy->attached_dev_type; kref_get(&parent->kref); @@ -934,6 +935,7 @@ static struct domain_device *sas_ex_discover_expander( res = sas_discover_expander(child); if (res) { + sas_rphy_delete(rphy); spin_lock_irq(&parent->port->dev_list_lock); list_del(&child->dev_list_node); spin_unlock_irq(&parent->port->dev_list_lock);