Re: [PATCH v8 2/2] scsi: libsas: Add linkrate and sas_addr change detection in rediscover
From: yangxingui
Date: Wed Jun 24 2026 - 02:16:39 EST
Hi Jason,
Thanks for the review.
On 2026/6/23 16:52, Jason Yan wrote:
在 2026/6/23 10:43, Xingui Yang 写道:
Introduce sas_dev_is_flutter() and sas_rediscover_ex_phy() to improve
flutter and device replace detection during rediscovery.
sas_dev_is_flutter() adds validation for linkrate and sas_addr changes.
When the SAS address changes, it restores phy->attached_sas_addr back to
the original address before returning false, ensuring
sas_unregister_devs_sas_addr() can properly match and unregister the old
device via sas_phy_match_dev_addr().
The sas_addr check is ordered before the linkrate check to ensure the
address restoration is not skipped when both change simultaneously.
Hold a kref on child_dev across the sas_ex_phy_discover() call to
prevent use-after-free, since sas_ex_phy_discover() sends an SMP
request which can sleep, during which the device could be freed by
a concurrent removal path.
sas_rediscover_ex_phy() uses the async discovery pattern
(sas_discover_event) instead of the synchronous sas_discover_new() to
ensure proper ordering between device unregistration and rediscovery,
avoiding sysfs_warn_dup() errors.
Signed-off-by: Xingui Yang <yangxingui@xxxxxxxxxx>
---
drivers/scsi/libsas/sas_expander.c | 89 +++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 14 deletions(-)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index cb9d3b748222..63d033e78985 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1966,6 +1966,78 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old)
return false;
}
+static void sas_rediscover_ex_phy(struct domain_device *dev, int phy_id,
+ bool last)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+
+ phy->phy_change_count = -1;
+ ex->ex_change_count = -1;
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
+ sas_discover_event(dev->port, DISCE_REVALIDATE_DOMAIN);
+}
+
+static bool sas_dev_is_flutter(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, enum sas_device_type type)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ struct domain_device *child_dev = NULL;
+ char *action = "";
+ int res;
+
+ if (SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr) ||
+ !dev_type_flutter(type, phy->attached_dev_type))
+ return false;
+
+ child_dev = sas_ex_to_dev(dev, phy_id);
+ if (!child_dev)
+ goto out;
+
+ kref_get(&child_dev->kref);
This is not necessary so I think you can remove it as domain device will never release here sine we are in the discover workqueue process.
It's ture that sas_find_dev_by_rphy() is not perfect. It shall get a reference after lock ->dev_list_lock. But this will affect many existing users. We can do that in another patchset.
Agreed. In v9 I have removed the kref_get/sas_put_device pattern
entirely. Instead, sas_ex_phy_discover() is now called before
sas_ex_to_dev(), so the child device pointer is obtained after the
sleeping SMP request completes. This eliminates the UAF concern
without needing a kref, since we are serialized by disco_mutex in
the discover workqueue.
The sas_find_dev_by_rphy() reference counting improvement is noted
as a separate patchset as you suggested.
Thanks,
Xingui