if (!net_device)
return NULL;
- /* Set to 2 to allow both inbound and outbound traffic */
- atomic_set(&net_device->refcnt, 2);
net_device->destroy = false;
net_device->dev = device;
return net_device;
}
-/* Get the net device object iff exists and its refcount > 1 */
static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
net_device = device->ext;
- if (net_device && (atomic_read(&net_device->refcnt) > 1) &&
- !net_device->destroy)
- atomic_inc(&net_device->refcnt);
- else
+ if (net_device && net_device->destroy)
net_device = NULL;
return net_device;
}
-/* Get the net device object iff exists and its refcount > 0 */
static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
+ unsigned long flags;
+ spin_lock_irqsave(&device->channel->inbound_lock, flags);
net_device = device->ext;
- if (net_device && atomic_read(&net_device->refcnt))
- atomic_inc(&net_device->refcnt);
- else
+
+ if (!net_device)
+ goto get_in_err;
+
+ if (net_device->destroy &&
+ atomic_read(&net_device->num_outstanding_sends) == 0)
net_device = NULL;
+get_in_err:
+ spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
return net_device;
}
-static void put_net_device(struct hv_device *device)
-{
- struct netvsc_device *net_device;
-
- net_device = device->ext;
-
- atomic_dec(&net_device->refcnt);
-}
static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
{
netvsc_destroy_recv_buf(net_device);
exit:
- put_net_device(device);
return ret;
}
ret = netvsc_init_recv_buf(device);
cleanup:
- put_net_device(device);
return ret;
}
unsigned long flags;
net_device = (struct netvsc_device *)device->ext;
- atomic_dec(&net_device->refcnt);
spin_lock_irqsave(&device->channel->inbound_lock, flags);
net_device->destroy = true;
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
netvsc_disconnect_vsp(net_device);
- atomic_dec(&net_device->refcnt);
- device->ext = NULL;
/*
- * Wait until the ref cnt falls to 0.
- * We have already stopped any new references
- * for outgoing traffic. Also, at this point we don't have any
- * incoming traffic as well. So this must be outgoing refrences
- * established prior to marking the device as being destroyed.
- * Since the send path is non-blocking, it is reasonable to busy
- * wait here.
+ * Since we have already drained, we don't need to busy wait
+ * as was done in final_release_stor_device()
+ * Note that we cannot set the ext pointer to NULL until
+ * we have drained - to drain the outgoing packets, we need to
+ * allow incoming packets.
*/
- while (atomic_read(&net_device->refcnt))
- udelay(100);
+
+ spin_lock_irqsave(&device->channel->inbound_lock, flags);
+ device->ext = NULL;
+ spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
/* At this point, no one should be accessing netDevice except in here */
dev_notice(&device->device, "net device safe to remove");
"%d received!!", nvsp_packet->hdr.msg_type);
}
- put_net_device(device);
}
int netvsc_send(struct hv_device *device,
packet, ret);
atomic_inc(&net_device->num_outstanding_sends);
- put_net_device(device);
return ret;
}
if (fsend_receive_comp)
netvsc_send_recv_completion(device, transaction_id);
- put_net_device(device);
}
static void netvsc_receive(struct hv_device *device,
if (packet->type != VM_PKT_DATA_USING_XFER_PAGES) {
dev_err(&device->device, "Unknown packet type received - %d",
packet->type);
- put_net_device(device);
return;
}
NVSP_MSG1_TYPE_SEND_RNDIS_PKT) {
dev_err(&device->device, "Unknown nvsp packet type received-"
" %d", nvsp_packet->hdr.msg_type);
- put_net_device(device);
return;
}
dev_err(&device->device, "Invalid xfer page set id - "
"expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID,
vmxferpage_packet->xfer_pageset_id);
- put_net_device(device);
return;
}
netvsc_send_recv_completion(device,
vmxferpage_packet->d.trans_id);
- put_net_device(device);
return;
}
completion.recv.recv_completion_ctx);
}
- put_net_device(device);
}
static void netvsc_channel_cb(void *context)
}
} while (1);
- put_net_device(device);
out:
kfree(buffer);
return;