scsi: zfcp: Fix sysfs roll-back on error in zfcp_adapter_enqueue()
authorJulian Wiedmann <jwi@linux.ibm.com>
Wed, 14 Apr 2021 17:08:01 +0000 (19:08 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 16 Apr 2021 02:19:39 +0000 (22:19 -0400)
When zfcp_adapter_enqueue() fails to create the zfcp_sysfs_adapter_attrs
group, it calls zfcp_adapter_unregister() to tear down the adapter state
again. This then unconditionally attempts to remove the
zfcp_sysfs_adapter_attrs group, resulting in a "group not found" WARN from
sysfs code.

Avoid this by copying most of zfcp_adapter_unregister() into the error
path, allowing for more fine-granular roll-back. Then skip the sysfs
tear-down steps if we haven't progressed this far in the initialization.

Link: https://lore.kernel.org/r/790922cc3af075795fff9a4b787e6bda19bdb3be.1618417667.git.bblock@linux.ibm.com
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/s390/scsi/zfcp_aux.c

index 768873dd55b86abee0c1976db2f4f2af4a08192d..abad77694e72ed0f7249a3d4da55e378c7add639 100644 (file)
@@ -418,7 +418,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
                goto failed;
 
        if (zfcp_diag_sysfs_setup(adapter))
-               goto failed;
+               goto err_diag_sysfs;
 
        /* report size limit per scatter-gather segment */
        adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
@@ -427,8 +427,24 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 
        return adapter;
 
+err_diag_sysfs:
+       sysfs_remove_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs);
 failed:
-       zfcp_adapter_unregister(adapter);
+       /* TODO: make this more fine-granular */
+       cancel_delayed_work_sync(&adapter->scan_work);
+       cancel_work_sync(&adapter->stat_work);
+       cancel_work_sync(&adapter->ns_up_work);
+       cancel_work_sync(&adapter->version_change_lost_work);
+       zfcp_destroy_adapter_work_queue(adapter);
+
+       zfcp_fc_wka_ports_force_offline(adapter->gs);
+       zfcp_scsi_adapter_unregister(adapter);
+
+       zfcp_erp_thread_kill(adapter);
+       zfcp_dbf_adapter_unregister(adapter);
+       zfcp_qdio_destroy(adapter->qdio);
+
+       zfcp_ccw_adapter_put(adapter); /* final put to release */
        return ERR_PTR(-ENOMEM);
 }