aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Yan <yanaijie@huawei.com>2017-12-08 04:42:09 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2018-01-10 23:24:02 -0500
commit0558f33c06bb910e2879e355192227a8e8f0219d (patch)
treebbcddcb5078ec6f66d40e9a9855535a762f01b1c
parent517e5153d242cb2dd0a1150d2a7bd6788d501ca9 (diff)
scsi: libsas: direct call probe and destruct
In commit 87c8331fcf72 ("[SCSI] libsas: prevent domain rediscovery competing with ata error handling") introduced disco mutex to prevent rediscovery competing with ata error handling and put the whole revalidation in the mutex. But the rphy add/remove needs to wait for the error handling which also grabs the disco mutex. This may leads to dead lock.So the probe and destruct event were introduce to do the rphy add/remove asynchronously and out of the lock. The asynchronously processed workers makes the whole discovery process not atomic, the other events may interrupt the process. For example, if a loss of signal event inserted before the probe event, the sas_deform_port() is called and the port will be deleted. And sas_port_delete() may run before the destruct event, but the port-x:x is the top parent of end device or expander. This leads to a kernel WARNING such as: [ 82.042979] sysfs group 'power' not found for kobject 'phy-1:0:22' [ 82.042983] ------------[ cut here ]------------ [ 82.042986] WARNING: CPU: 54 PID: 1714 at fs/sysfs/group.c:237 sysfs_remove_group+0x94/0xa0 [ 82.043059] Call trace: [ 82.043082] [<ffff0000082e7624>] sysfs_remove_group+0x94/0xa0 [ 82.043085] [<ffff00000864e320>] dpm_sysfs_remove+0x60/0x70 [ 82.043086] [<ffff00000863ee10>] device_del+0x138/0x308 [ 82.043089] [<ffff00000869a2d0>] sas_phy_delete+0x38/0x60 [ 82.043091] [<ffff00000869a86c>] do_sas_phy_delete+0x6c/0x80 [ 82.043093] [<ffff00000863dc20>] device_for_each_child+0x58/0xa0 [ 82.043095] [<ffff000008696f80>] sas_remove_children+0x40/0x50 [ 82.043100] [<ffff00000869d1bc>] sas_destruct_devices+0x64/0xa0 [ 82.043102] [<ffff0000080e93bc>] process_one_work+0x1fc/0x4b0 [ 82.043104] [<ffff0000080e96c0>] worker_thread+0x50/0x490 [ 82.043105] [<ffff0000080f0364>] kthread+0xfc/0x128 [ 82.043107] [<ffff0000080836c0>] ret_from_fork+0x10/0x50 Make probe and destruct a direct call in the disco and revalidate function, but put them outside the lock. The whole discovery or revalidate won't be interrupted by other events. And the DISCE_PROBE and DISCE_DESTRUCT event are deleted as a result of the direct call. Introduce a new list to destruct the sas_port and put the port delete after the destruct. This makes sure the right order of destroying the sysfs kobject and fix the warning above. In sas_ex_revalidate_domain() have a loop to find all broadcasted device, and sometimes we have a chance to find the same expander twice. Because the sas_port will be deleted at the end of the whole revalidate process, sas_port with the same name cannot be added before this. Otherwise the sysfs will complain of creating duplicate filename. Since the LLDD will send broadcast for every device change, we can only process one expander's revalidation. [mkp: kbuild test robot warning] Signed-off-by: Jason Yan <yanaijie@huawei.com> CC: John Garry <john.garry@huawei.com> CC: Johannes Thumshirn <jthumshirn@suse.de> CC: Ewan Milne <emilne@redhat.com> CC: Christoph Hellwig <hch@lst.de> CC: Tomas Henzl <thenzl@redhat.com> CC: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/libsas/sas_ata.c1
-rw-r--r--drivers/scsi/libsas/sas_discover.c32
-rw-r--r--drivers/scsi/libsas/sas_expander.c8
-rw-r--r--drivers/scsi/libsas/sas_internal.h1
-rw-r--r--drivers/scsi/libsas/sas_port.c3
-rw-r--r--include/scsi/libsas.h3
-rw-r--r--include/scsi/scsi_transport_sas.h1
7 files changed, 27 insertions, 22 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 70be4425ae0b..2b3637b40dde 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -730,7 +730,6 @@ int sas_discover_sata(struct domain_device *dev)
730 if (res) 730 if (res)
731 return res; 731 return res;
732 732
733 sas_discover_event(dev->port, DISCE_PROBE);
734 return 0; 733 return 0;
735} 734}
736 735
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 14f714d05767..e4fd078e4175 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -212,13 +212,9 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
212 } 212 }
213} 213}
214 214
215static void sas_probe_devices(struct work_struct *work) 215static void sas_probe_devices(struct asd_sas_port *port)
216{ 216{
217 struct domain_device *dev, *n; 217 struct domain_device *dev, *n;
218 struct sas_discovery_event *ev = to_sas_discovery_event(work);
219 struct asd_sas_port *port = ev->port;
220
221 clear_bit(DISCE_PROBE, &port->disc.pending);
222 218
223 /* devices must be domain members before link recovery and probe */ 219 /* devices must be domain members before link recovery and probe */
224 list_for_each_entry(dev, &port->disco_list, disco_list_node) { 220 list_for_each_entry(dev, &port->disco_list, disco_list_node) {
@@ -294,7 +290,6 @@ int sas_discover_end_dev(struct domain_device *dev)
294 res = sas_notify_lldd_dev_found(dev); 290 res = sas_notify_lldd_dev_found(dev);
295 if (res) 291 if (res)
296 return res; 292 return res;
297 sas_discover_event(dev->port, DISCE_PROBE);
298 293
299 return 0; 294 return 0;
300} 295}
@@ -353,13 +348,9 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
353 sas_put_device(dev); 348 sas_put_device(dev);
354} 349}
355 350
356static void sas_destruct_devices(struct work_struct *work) 351void sas_destruct_devices(struct asd_sas_port *port)
357{ 352{
358 struct domain_device *dev, *n; 353 struct domain_device *dev, *n;
359 struct sas_discovery_event *ev = to_sas_discovery_event(work);
360 struct asd_sas_port *port = ev->port;
361
362 clear_bit(DISCE_DESTRUCT, &port->disc.pending);
363 354
364 list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { 355 list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
365 list_del_init(&dev->disco_list_node); 356 list_del_init(&dev->disco_list_node);
@@ -370,6 +361,16 @@ static void sas_destruct_devices(struct work_struct *work)
370 } 361 }
371} 362}
372 363
364static void sas_destruct_ports(struct asd_sas_port *port)
365{
366 struct sas_port *sas_port, *p;
367
368 list_for_each_entry_safe(sas_port, p, &port->sas_port_del_list, del_list) {
369 list_del_init(&sas_port->del_list);
370 sas_port_delete(sas_port);
371 }
372}
373
373void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) 374void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
374{ 375{
375 if (!test_bit(SAS_DEV_DESTROY, &dev->state) && 376 if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
@@ -384,7 +385,6 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
384 if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { 385 if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
385 sas_rphy_unlink(dev->rphy); 386 sas_rphy_unlink(dev->rphy);
386 list_move_tail(&dev->disco_list_node, &port->destroy_list); 387 list_move_tail(&dev->disco_list_node, &port->destroy_list);
387 sas_discover_event(dev->port, DISCE_DESTRUCT);
388 } 388 }
389} 389}
390 390
@@ -490,6 +490,8 @@ static void sas_discover_domain(struct work_struct *work)
490 port->port_dev = NULL; 490 port->port_dev = NULL;
491 } 491 }
492 492
493 sas_probe_devices(port);
494
493 SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, 495 SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
494 task_pid_nr(current), error); 496 task_pid_nr(current), error);
495} 497}
@@ -523,6 +525,10 @@ static void sas_revalidate_domain(struct work_struct *work)
523 port->id, task_pid_nr(current), res); 525 port->id, task_pid_nr(current), res);
524 out: 526 out:
525 mutex_unlock(&ha->disco_mutex); 527 mutex_unlock(&ha->disco_mutex);
528
529 sas_destruct_devices(port);
530 sas_destruct_ports(port);
531 sas_probe_devices(port);
526} 532}
527 533
528/* ---------- Events ---------- */ 534/* ---------- Events ---------- */
@@ -578,10 +584,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
578 static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { 584 static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
579 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, 585 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
580 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, 586 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
581 [DISCE_PROBE] = sas_probe_devices,
582 [DISCE_SUSPEND] = sas_suspend_devices, 587 [DISCE_SUSPEND] = sas_suspend_devices,
583 [DISCE_RESUME] = sas_resume_devices, 588 [DISCE_RESUME] = sas_resume_devices,
584 [DISCE_DESTRUCT] = sas_destruct_devices,
585 }; 589 };
586 590
587 disc->pending = 0; 591 disc->pending = 0;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index a8a57b0593e3..7444d40e261c 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1916,7 +1916,8 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1916 sas_port_delete_phy(phy->port, phy->phy); 1916 sas_port_delete_phy(phy->port, phy->phy);
1917 sas_device_set_phy(found, phy->port); 1917 sas_device_set_phy(found, phy->port);
1918 if (phy->port->num_phys == 0) 1918 if (phy->port->num_phys == 0)
1919 sas_port_delete(phy->port); 1919 list_add_tail(&phy->port->del_list,
1920 &parent->port->sas_port_del_list);
1920 phy->port = NULL; 1921 phy->port = NULL;
1921 } 1922 }
1922} 1923}
@@ -2124,7 +2125,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
2124 struct domain_device *dev = NULL; 2125 struct domain_device *dev = NULL;
2125 2126
2126 res = sas_find_bcast_dev(port_dev, &dev); 2127 res = sas_find_bcast_dev(port_dev, &dev);
2127 while (res == 0 && dev) { 2128 if (res == 0 && dev) {
2128 struct expander_device *ex = &dev->ex_dev; 2129 struct expander_device *ex = &dev->ex_dev;
2129 int i = 0, phy_id; 2130 int i = 0, phy_id;
2130 2131
@@ -2136,9 +2137,6 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
2136 res = sas_rediscover(dev, phy_id); 2137 res = sas_rediscover(dev, phy_id);
2137 i = phy_id + 1; 2138 i = phy_id + 1;
2138 } while (i < ex->num_phys); 2139 } while (i < ex->num_phys);
2139
2140 dev = NULL;
2141 res = sas_find_bcast_dev(port_dev, &dev);
2142 } 2140 }
2143 return res; 2141 return res;
2144} 2142}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index d8826a747690..50e12d662ffe 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -101,6 +101,7 @@ int sas_try_ata_reset(struct asd_sas_phy *phy);
101void sas_hae_reset(struct work_struct *work); 101void sas_hae_reset(struct work_struct *work);
102 102
103void sas_free_device(struct kref *kref); 103void sas_free_device(struct kref *kref);
104void sas_destruct_devices(struct asd_sas_port *port);
104 105
105extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS]; 106extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
106extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS]; 107extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 64722f42b256..f07e55d3aa73 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -66,6 +66,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
66 rc = sas_notify_lldd_dev_found(dev); 66 rc = sas_notify_lldd_dev_found(dev);
67 if (rc) { 67 if (rc) {
68 sas_unregister_dev(port, dev); 68 sas_unregister_dev(port, dev);
69 sas_destruct_devices(port);
69 continue; 70 continue;
70 } 71 }
71 72
@@ -220,6 +221,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
220 221
221 if (port->num_phys == 1) { 222 if (port->num_phys == 1) {
222 sas_unregister_domain_devices(port, gone); 223 sas_unregister_domain_devices(port, gone);
224 sas_destruct_devices(port);
223 sas_port_delete(port->port); 225 sas_port_delete(port->port);
224 port->port = NULL; 226 port->port = NULL;
225 } else { 227 } else {
@@ -317,6 +319,7 @@ static void sas_init_port(struct asd_sas_port *port,
317 INIT_LIST_HEAD(&port->dev_list); 319 INIT_LIST_HEAD(&port->dev_list);
318 INIT_LIST_HEAD(&port->disco_list); 320 INIT_LIST_HEAD(&port->disco_list);
319 INIT_LIST_HEAD(&port->destroy_list); 321 INIT_LIST_HEAD(&port->destroy_list);
322 INIT_LIST_HEAD(&port->sas_port_del_list);
320 spin_lock_init(&port->phy_list_lock); 323 spin_lock_init(&port->phy_list_lock);
321 INIT_LIST_HEAD(&port->phy_list); 324 INIT_LIST_HEAD(&port->phy_list);
322 port->ha = sas_ha; 325 port->ha = sas_ha;
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 6255bb5ed1e4..1cab6f7af425 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -82,10 +82,8 @@ enum phy_event {
82enum discover_event { 82enum discover_event {
83 DISCE_DISCOVER_DOMAIN = 0U, 83 DISCE_DISCOVER_DOMAIN = 0U,
84 DISCE_REVALIDATE_DOMAIN, 84 DISCE_REVALIDATE_DOMAIN,
85 DISCE_PROBE,
86 DISCE_SUSPEND, 85 DISCE_SUSPEND,
87 DISCE_RESUME, 86 DISCE_RESUME,
88 DISCE_DESTRUCT,
89 DISC_NUM_EVENTS, 87 DISC_NUM_EVENTS,
90}; 88};
91 89
@@ -262,6 +260,7 @@ struct asd_sas_port {
262 struct list_head dev_list; 260 struct list_head dev_list;
263 struct list_head disco_list; 261 struct list_head disco_list;
264 struct list_head destroy_list; 262 struct list_head destroy_list;
263 struct list_head sas_port_del_list;
265 enum sas_linkrate linkrate; 264 enum sas_linkrate linkrate;
266 265
267 struct sas_work work; 266 struct sas_work work;
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 62895b405933..05ec927a3c72 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -156,6 +156,7 @@ struct sas_port {
156 156
157 struct mutex phy_list_mutex; 157 struct mutex phy_list_mutex;
158 struct list_head phy_list; 158 struct list_head phy_list;
159 struct list_head del_list; /* libsas only */
159}; 160};
160 161
161#define dev_to_sas_port(d) \ 162#define dev_to_sas_port(d) \