From f450c75dad04061f2d51401088f156e1226804ac Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Jan 2017 10:19:02 +0000 Subject: [PATCH] [interface] Unplug interface before calling intf_close() in intf_shutdown() The call to intf_close() may result in the original interface being reopened. For example: when reading the capacity of a 2TB+ disk via iSCSI, the SCSI layer will respond to the intf_close() from the READ CAPACITY (10) command by immediately issuing a READ CAPACITY (16) command. The iSCSI layer happens to reuse the same interface for the new command (since it allows only a single concurrent command). Currently, intf_shutdown() unplugs the interface after the call to intf_close() returns. In the above scenario, this results in unplugging the just-reopened interface. Fix by transferring the interface destination (and its reference) to a temporary interface, and so effectively performing the unplug before making the call to intf_close(). Signed-off-by: Michael Brown --- src/core/interface.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/core/interface.c b/src/core/interface.c index a700d2e4..f7802be0 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -271,6 +271,7 @@ void intf_close ( struct interface *intf, int rc ) { * unplugs the interface. */ void intf_shutdown ( struct interface *intf, int rc ) { + struct interface tmp; DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n", INTF_DBG ( intf ), strerror ( rc ) ); @@ -278,11 +279,15 @@ void intf_shutdown ( struct interface *intf, int rc ) { /* Block further operations */ intf_nullify ( intf ); - /* Notify destination of close */ - intf_close ( intf, rc ); + /* Transfer destination to temporary interface */ + tmp.dest = intf->dest; + intf->dest = &null_intf; - /* Unplug interface */ - intf_unplug ( intf ); + /* Notify destination of close via temporary interface */ + intf_close ( &tmp, rc ); + + /* Unplug temporary interface */ + intf_unplug ( &tmp ); } /**