Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[hyperv] Tear down NetVSC RX buffer GPADL after closing VMBus device
On Windows Server 2012 R2, the receive buffer teardown completion
message seems to occasionally be deferred until after the VMBus
channel has been closed.  This happens even if there are no packets
currently in the receive buffer.

Work around this problem by separating the revocation and teardown of
the receive buffer, and deferring the teardown until after the VMBus
channel has been closed.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Dec 20, 2014
1 parent 4de0e27 commit cd68d93
Showing 1 changed file with 20 additions and 24 deletions.
44 changes: 20 additions & 24 deletions src/drivers/net/netvsc.c
Expand Up @@ -262,8 +262,11 @@ static int netvsc_revoke_buffer ( struct netvsc_device *netvsc,

/* Send message and wait for completion */
if ( ( rc = netvsc_control ( netvsc, buffer->revoke_xrid,
&msg, sizeof ( msg ) ) ) != 0 )
&msg, sizeof ( msg ) ) ) != 0 ) {
DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
netvsc->name, strerror ( rc ) );
return rc;
}

return 0;
}
Expand Down Expand Up @@ -637,14 +640,8 @@ static int netvsc_create_buffer ( struct netvsc_device *netvsc,
goto err_register_pages;
}

/* Establish data buffer */
if ( ( rc = netvsc_establish_buffer ( netvsc, buffer ) ) != 0 )
goto err_establish_buffer;

return 0;

netvsc_revoke_buffer ( netvsc, buffer );
err_establish_buffer:
vmbus_unregister_pages ( vmdev, &buffer->pages );
err_register_pages:
vmbus_gpadl_teardown ( vmdev, gpadl );
Expand All @@ -665,16 +662,6 @@ static void netvsc_destroy_buffer ( struct netvsc_device *netvsc,
struct vmbus_device *vmdev = netvsc->vmdev;
int rc;

/* Revoke buffer */
if ( ( rc = netvsc_revoke_buffer ( netvsc, buffer ) ) != 0 ) {
DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
netvsc->name, strerror ( rc ) );
/* Continue to attempt to tear down the GPA descriptor
* list, which should forcibly prevent the host from
* subsequently accessing this memory.
*/
}

/* Unregister transfer pages */
vmbus_unregister_pages ( vmdev, &buffer->pages );

Expand Down Expand Up @@ -704,6 +691,10 @@ static int netvsc_open ( struct rndis_device *rndis ) {
struct netvsc_device *netvsc = rndis->priv;
int rc;

/* Initialise receive buffer */
if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
goto err_create_rx;

/* Open channel */
if ( ( rc = vmbus_open ( netvsc->vmdev, &netvsc_channel_operations,
PAGE_SIZE, PAGE_SIZE, NETVSC_MTU ) ) != 0 ) {
Expand All @@ -722,20 +713,22 @@ static int netvsc_open ( struct rndis_device *rndis ) {
if ( ( rc = netvsc_create_ring ( netvsc, &netvsc->tx ) ) != 0 )
goto err_create_tx;

/* Initialise receive buffer */
if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
goto err_create_rx;
/* Establish receive buffer */
if ( ( rc = netvsc_establish_buffer ( netvsc, &netvsc->rx ) ) != 0 )
goto err_establish_rx;

return 0;

netvsc_destroy_buffer ( netvsc, &netvsc->rx );
err_create_rx:
netvsc_revoke_buffer ( netvsc, &netvsc->rx );
err_establish_rx:
netvsc_destroy_ring ( netvsc, &netvsc->tx, NULL );
err_create_tx:
err_ndis_version:
err_initialise:
vmbus_close ( netvsc->vmdev );
err_vmbus_open:
netvsc_destroy_buffer ( netvsc, &netvsc->rx );
err_create_rx:
return rc;
}

Expand All @@ -747,14 +740,17 @@ static int netvsc_open ( struct rndis_device *rndis ) {
static void netvsc_close ( struct rndis_device *rndis ) {
struct netvsc_device *netvsc = rndis->priv;

/* Destroy receive buffer */
netvsc_destroy_buffer ( netvsc, &netvsc->rx );
/* Revoke receive buffer */
netvsc_revoke_buffer ( netvsc, &netvsc->rx );

/* Destroy transmit ring */
netvsc_destroy_ring ( netvsc, &netvsc->tx, netvsc_cancel_transmit );

/* Close channel */
vmbus_close ( netvsc->vmdev );

/* Destroy receive buffer */
netvsc_destroy_buffer ( netvsc, &netvsc->rx );
}

/** RNDIS operations */
Expand Down

0 comments on commit cd68d93

Please sign in to comment.