cleanup after a discovery error
Subsystems (2)
PATCH 1/1 cleanup after a discovery error
Domain device is freed but the port dev list is not adjusted on some discovery errors. Module unload will Oops if this happens.
drivers/scsi/libsas/sas_discover.c +17 -1
@@ -684,7 +684,23 @@ static void sas_discover_domain(void *da }if (error) { -kfree (port->port_dev);/* not kobject_register-ed yet */ +struct domain_device *dev = port->port_dev; + +if (dev->rphy) { +sas_remove_children (&dev->rphy->dev); +sas_rphy_delete (dev->rphy); + dev->rphy =NULL ; + } +if (dev->dev_type ==EDGE_DEV || dev->dev_type ==FANOUT_DEV ) { +if (dev->ex_dev.ex_phy) { +kfree (dev->ex_dev.ex_phy); + dev->ex_dev.ex_phy =NULL ; + } + } +spin_lock (&port->dev_list_lock); +list_del_init (&dev->dev_list_node); +spin_unlock (&port->dev_list_lock); +kfree (dev);/* not kobject_register-ed yet */ port->port_dev =NULL ; }
Quoted 20 lines · On Wed, 2006-10-18 at 20:19 -0700, [email protected] wrote:
Domain device is freed but the port dev list is not adjusted on some discovery errors. Module unload will Oops if this happens.
Signed-off-by Malahal Naineni <[email protected]>diff -r
4e1720b3c71bdrivers/scsi/libsas/sas_discover.cdrivers/scsi/libsas/sas_discover.c +7
-1@@ -684,7 +684,23 @@ static void sas_discover_domain(void *da }if (error) { -kfree (port->port_dev);/* not kobject_register-ed yet */ +struct domain_device *dev = port->port_dev; + +if (dev->rphy) { +sas_remove_children (&dev->rphy->dev); +sas_rphy_delete (dev->rphy); + dev->rphy =NULL ; + }
drivers/scsi/libsas/sas_discover.c static void sas_discover_domain(void *da · line 703
Quoted 10 lines
drivers/scsi/libsas/sas_discover.c +10
-0+if (dev->dev_type ==EDGE_DEV || dev->dev_type ==FANOUT_DEV ) { +if (dev->ex_dev.ex_phy) { +kfree (dev->ex_dev.ex_phy); + dev->ex_dev.ex_phy =NULL ; + } + } +spin_lock (&port->dev_list_lock); +list_del_init (&dev->dev_list_node); +spin_unlock (&port->dev_list_lock); +kfree (dev);/* not kobject_register-ed yet */
This is a bit of a layering violation
if the various discover functions are going to return an error, I think it's their job to clean up whatever they did before returning.
James
Quoted 7 lines · James Bottomley [[email protected]] wrote:
This is a bit of a layering violation
if the various discover functions are going to return an error, I think it's their job to clean up whatever they did before returning.
James
Hope this works better.
drivers/scsi/libsas/sas_discover.c +5 -0
@@ -684,6 +684,11 @@ static void sas_discover_domain(void *da }if (error) { +sas_rphy_delete (port->port_dev->rphy); + port->port_dev->rphy =NULL ; +spin_lock (&port->dev_list_lock); +list_del_init (&port->port_dev->dev_list_node); +spin_unlock (&port->dev_list_lock);kfree (port->port_dev);/* not kobject_register-ed yet */ port->port_dev =NULL ; }
Quoted 5 lines
Quoted 4 lines · James Bottomley [[email protected]] wrote:
This is a bit of a layering violation
if the various discover functions are going to return an error, I think it's their job to clean up whatever they did before returning.
Here's a reworked version of Malahal's patch that pushes the sas_rphy cleanups into the sas_discover_{sas,sata,expander}.* functions. It also checks the return value of sas_notify_lldd_dev_found(). This patch (since it includes discovery error cleanup for SATA) is against 2.6.19-rc4 + scsi-misc + scsi-rc-fixes + aic94xx-sas, though I can respin it without the SATA bits if desired.
--
drivers/scsi/libsas/sas_discover.c +30 -5
@@ -564,12 +564,25 @@ int sas_discover_sata(struct domain_devidefault :break ; } +if (res) + goto out_err;sas_notify_lldd_dev_gone (dev); -if (!res) { -sas_notify_lldd_dev_found (dev); - res =sas_rphy_add (dev->rphy); - } + res =sas_notify_lldd_dev_found (dev); +if (res) + goto out_err2; + + res =sas_rphy_add (dev->rphy); +if (res) + goto out_err; + +return res; + +out_err: +sas_notify_lldd_dev_gone (dev); +out_err2: +sas_rphy_free (dev->rphy); + dev->rphy =NULL ;return res; }
@@ -594,12 +607,20 @@ int sas_discover_end_dev(struct domain_d/* do this to get the end device port attributes which will have * been scanned in sas_rphy_add */ sas_notify_lldd_dev_gone (dev); -sas_notify_lldd_dev_found (dev); + res =sas_notify_lldd_dev_found (dev); +if (res) + goto out_err2;return 0 ; out_err:sas_notify_lldd_dev_gone (dev); +sas_rphy_free (dev->rphy); + dev->rphy =NULL ; +return res; +out_err2: +sas_rphy_delete (dev->rphy); + dev->rphy =NULL ;return res; }
@@ -689,6 +710,10 @@ static void sas_discover_domain(void *da }if (error) { +spin_lock (&port->dev_list_lock); +list_del_init (&port->port_dev->dev_list_node); +spin_unlock (&port->dev_list_lock); +kfree (port->port_dev);/* not kobject_register-ed yet */ port->port_dev =NULL ; }
drivers/scsi/libsas/sas_expander.c +16 -3
@@ -1474,14 +1474,27 @@ int sas_discover_root_expander(struct doint res;struct sas_expander_device *ex =rphy_to_expander_device (dev->rphy); -sas_rphy_add (dev->rphy); + res =sas_rphy_add (dev->rphy); +if (res) + goto out_err; ex->level = dev->port->disc.max_level;/* 0 */ res =sas_discover_expander (dev); -if (!res) -sas_ex_bfs_disc (dev->port); +if (res) + goto out_err2; + +sas_ex_bfs_disc (dev->port);return res; + +out_err2: +sas_rphy_delete (dev->rphy); + dev->rphy =NULL ; +return res; +out_err: +sas_rphy_free (dev->rphy); + dev->rphy =NULL ; +return res; }/* ---------- Domain revalidation ---------- */