Skip to content

Commit 5f852be

Browse files
Christof SchmittJames Bottomley
Christof Schmitt
authored and
James Bottomley
committed
[SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI
The SCSI stack requires low level drivers to register and unregister devices. For zfcp this leads to the situation where zfcp calls the SCSI stack, the SCSI tries to scan the new device and the scan SCSI command fails. This would require the zfcp erp, but the erp thread is already blocked in the register call. The fix is to make sure that the calls from the ERP thread to the SCSI stack do not block the ERP thread. In detail: 1) Use a workqueue to avoid blocking of the scsi_scan_target calls. 2) When removing a unit make sure that no scsi_scan_target call is pending. 3) Replace scsi_flush_work with scsi_target_unblock. This avoids blocking and has the same result. Signed-off-by: Christof Schmitt <[email protected]> Signed-off-by: Swen Schillig <[email protected]> Signed-off-by: James Bottomley <[email protected]>
1 parent 801e0ce commit 5f852be

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

drivers/s390/scsi/zfcp_aux.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
913913
unit->sysfs_device.release = zfcp_sysfs_unit_release;
914914
dev_set_drvdata(&unit->sysfs_device, unit);
915915

916+
init_waitqueue_head(&unit->scsi_scan_wq);
917+
916918
/* mark unit unusable as long as sysfs registration is not complete */
917919
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
918920

drivers/s390/scsi/zfcp_def.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ do { \
637637
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
638638
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
639639
#define ZFCP_STATUS_UNIT_REGISTERED 0x00000010
640+
#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020
640641

641642
/* FSF request status (this does not have a common part) */
642643
#define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000
@@ -980,6 +981,10 @@ struct zfcp_unit {
980981
struct scsi_device *device; /* scsi device struct pointer */
981982
struct zfcp_erp_action erp_action; /* pending error recovery */
982983
atomic_t erp_counter;
984+
wait_queue_head_t scsi_scan_wq; /* can be used to wait until
985+
all scsi_scan_target
986+
requests have been
987+
completed. */
983988
};
984989

985990
/* FSF request */

drivers/s390/scsi/zfcp_erp.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
15911591
return result;
15921592
}
15931593

1594+
struct zfcp_erp_add_work {
1595+
struct zfcp_unit *unit;
1596+
struct work_struct work;
1597+
};
1598+
1599+
/**
1600+
* zfcp_erp_scsi_scan
1601+
* @data: pointer to a struct zfcp_erp_add_work
1602+
*
1603+
* Registers a logical unit with the SCSI stack.
1604+
*/
1605+
static void zfcp_erp_scsi_scan(struct work_struct *work)
1606+
{
1607+
struct zfcp_erp_add_work *p =
1608+
container_of(work, struct zfcp_erp_add_work, work);
1609+
struct zfcp_unit *unit = p->unit;
1610+
struct fc_rport *rport = unit->port->rport;
1611+
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
1612+
unit->scsi_lun, 0);
1613+
atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
1614+
wake_up(&unit->scsi_scan_wq);
1615+
zfcp_unit_put(unit);
1616+
kfree(p);
1617+
}
1618+
1619+
/**
1620+
* zfcp_erp_schedule_work
1621+
* @unit: pointer to unit which should be registered with SCSI stack
1622+
*
1623+
* Schedules work which registers a unit with the SCSI stack
1624+
*/
1625+
static void
1626+
zfcp_erp_schedule_work(struct zfcp_unit *unit)
1627+
{
1628+
struct zfcp_erp_add_work *p;
1629+
1630+
p = kmalloc(sizeof(*p), GFP_KERNEL);
1631+
if (!p) {
1632+
ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
1633+
"the FCP-LUN 0x%Lx connected to "
1634+
"the port with WWPN 0x%Lx connected to "
1635+
"the adapter %s with the SCSI stack.\n",
1636+
unit->fcp_lun,
1637+
unit->port->wwpn,
1638+
zfcp_get_busid_by_unit(unit));
1639+
return;
1640+
}
1641+
1642+
zfcp_unit_get(unit);
1643+
memset(p, 0, sizeof(*p));
1644+
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
1645+
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
1646+
p->unit = unit;
1647+
schedule_work(&p->work);
1648+
}
1649+
15941650
/*
15951651
* function:
15961652
*
@@ -3092,9 +3148,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
30923148
&& port->rport) {
30933149
atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
30943150
&unit->status);
3095-
scsi_scan_target(&port->rport->dev, 0,
3096-
port->rport->scsi_target_id,
3097-
unit->scsi_lun, 0);
3151+
if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
3152+
&unit->status) == 0)
3153+
zfcp_erp_schedule_work(unit);
30983154
}
30993155
zfcp_unit_put(unit);
31003156
break;
@@ -3121,7 +3177,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
31213177
zfcp_get_busid_by_port(port),
31223178
port->wwpn);
31233179
else {
3124-
scsi_flush_work(adapter->scsi_host);
3180+
scsi_target_unblock(&port->rport->dev);
31253181
port->rport->maxframe_size = port->maxframe_size;
31263182
port->rport->supported_classes =
31273183
port->supported_classes;

drivers/s390/scsi/zfcp_scsi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
2323

2424
#include "zfcp_ext.h"
25+
#include <asm/atomic.h>
2526

2627
static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
2728
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
@@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
179180
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
180181

181182
if (unit) {
183+
zfcp_erp_wait(unit->port->adapter);
184+
wait_event(unit->scsi_scan_wq,
185+
atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
186+
&unit->status) == 0);
182187
atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
183188
sdpnt->hostdata = NULL;
184189
unit->device = NULL;

0 commit comments

Comments
 (0)