Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Dan Williams and committed by
James Bottomley
9487669f ec236e52

+10 -7
+6 -5
drivers/scsi/libsas/sas_discover.c
··· 151 151 sas_device_set_phy(dev, port->port); 152 152 153 153 dev->rphy = rphy; 154 + get_device(&dev->rphy->dev); 154 155 155 156 if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) 156 157 list_add_tail(&dev->disco_list_node, &port->disco_list); ··· 256 255 { 257 256 struct domain_device *dev = container_of(kref, typeof(*dev), kref); 258 257 258 + put_device(&dev->rphy->dev); 259 + dev->rphy = NULL; 260 + 259 261 if (dev->parent) 260 262 sas_put_device(dev->parent); 261 263 ··· 305 301 306 302 sas_remove_children(&dev->rphy->dev); 307 303 sas_rphy_delete(dev->rphy); 308 - dev->rphy = NULL; 309 304 sas_unregister_common_dev(port, dev); 310 305 } 311 306 } ··· 316 313 /* this rphy never saw sas_rphy_add */ 317 314 list_del_init(&dev->disco_list_node); 318 315 sas_rphy_free(dev->rphy); 319 - dev->rphy = NULL; 320 316 sas_unregister_common_dev(port, dev); 317 + return; 321 318 } 322 319 323 - if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { 320 + if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { 324 321 sas_rphy_unlink(dev->rphy); 325 322 list_move_tail(&dev->disco_list_node, &port->destroy_list); 326 323 sas_discover_event(dev->port, DISCE_DESTRUCT); ··· 420 417 421 418 if (error) { 422 419 sas_rphy_free(dev->rphy); 423 - dev->rphy = NULL; 424 - 425 420 list_del_init(&dev->disco_list_node); 426 421 spin_lock_irq(&port->dev_list_lock); 427 422 list_del_init(&dev->dev_list_node);
+4 -2
drivers/scsi/libsas/sas_expander.c
··· 783 783 sas_init_dev(child); 784 784 785 785 child->rphy = rphy; 786 + get_device(&rphy->dev); 786 787 787 788 list_add_tail(&child->disco_list_node, &parent->port->disco_list); 788 789 ··· 807 806 sas_init_dev(child); 808 807 809 808 child->rphy = rphy; 809 + get_device(&rphy->dev); 810 810 sas_fill_in_rphy(child, rphy); 811 811 812 812 list_add_tail(&child->disco_list_node, &parent->port->disco_list); ··· 832 830 833 831 out_list_del: 834 832 sas_rphy_free(child->rphy); 835 - child->rphy = NULL; 836 - 837 833 list_del(&child->disco_list_node); 838 834 spin_lock_irq(&parent->port->dev_list_lock); 839 835 list_del(&child->dev_list_node); ··· 911 911 } 912 912 port = parent->port; 913 913 child->rphy = rphy; 914 + get_device(&rphy->dev); 914 915 edev = rphy_to_expander_device(rphy); 915 916 child->dev_type = phy->attached_dev_type; 916 917 kref_get(&parent->kref); ··· 935 934 936 935 res = sas_discover_expander(child); 937 936 if (res) { 937 + sas_rphy_delete(rphy); 938 938 spin_lock_irq(&parent->port->dev_list_lock); 939 939 list_del(&child->dev_list_node); 940 940 spin_unlock_irq(&parent->port->dev_list_lock);