Linux virtualization list
 help / color / mirror / Atom feed
* [PATCH 075/117] Staging: hv: storvsc: Inline free_stor_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Inline the code for  free_stor_device() and get rid of the function.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 827b6a3..8c62829 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -51,10 +51,6 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 	return stor_device;
 }
 
-static inline void free_stor_device(struct storvsc_device *device)
-{
-	kfree(device);
-}
 
 /* Get the stordevice object iff exists and its refcount > 0 */
 static inline struct storvsc_device *must_get_stor_device(
@@ -394,7 +390,7 @@ int storvsc_dev_add(struct hv_device *device,
 	/* Send it back up */
 	ret = storvsc_connect_to_vsp(device, device_info->ring_buffer_size);
 	if (ret) {
-		free_stor_device(stor_device);
+		kfree(stor_device);
 		return ret;
 	}
 	device_info->path_id = stor_device->path_id;
@@ -422,7 +418,7 @@ int storvsc_dev_remove(struct hv_device *device)
 	/* Close the channel */
 	vmbus_close(device->channel);
 
-	free_stor_device(stor_device);
+	kfree(stor_device);
 	return 0;
 }
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 0000/0117] Staging: hv: Driver cleanup
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: K. Y. Srinivasan

Further cleanup of the hv drivers. Back in June I had sent two patch
sets to address these issues. I have addressed the comments I got from
the community on my earlier patches here:

	1) Implement code for autoloading the vmbus drivers without using PCI or DMI
	   signatures. I have implemented this based on Greg's feedback on my earlier
	   implementation.

	2) Cleanup error handling across the board and use standard Linux error codes.

	3) General cleanup

	4) Some bug fixes.

	5) Cleanup the reference counting mess for both stor and net devices.

	6) Handle all block devices using the storvsc driver. I have modified
	   the implementation here based on Christoph's feedback on my earlier
	   implementation.

	7) Accomodate some host side scsi emulation bugs.

	8) In case of scsi errors off-line the device.

This patch-set further reduces the size of Hyper-V drivers - the code is
about 10% smaller. This reduction is mainly because we have eliminated the
blkvsc driver.
	  

Regards,

K. Y 

^ permalink raw reply

* [PATCH 076/117] Staging: hv: storvsc: Do not aquire an unnecessary reference on stor_device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

On entry into storvsc_on_io_completion() we have already acquired a reference
on the stor_device; there is no need to acquire an additional reference here.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 8c62829..cd38cd6 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -232,9 +232,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
 	struct storvsc_device *stor_device;
 	struct vstor_packet *stor_pkt;
 
-	stor_device = must_get_stor_device(device);
-	if (!stor_device)
-		return;
+	stor_device = (struct storvsc_device *)device->ext;
 
 	stor_pkt = &request->vstor_packet;
 
@@ -279,7 +277,6 @@ static void storvsc_on_io_completion(struct hv_device *device,
 		wake_up(&stor_device->waiting_to_drain);
 
 
-	put_stor_device(device);
 }
 
 static void storvsc_on_receive(struct hv_device *device,
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 077/117] Staging: hv: storvsc: Rename must_get_stor_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

In preparation for cleaning up how we manage reference counts on the stor
device, clearly distinguish why we are attempting to acquire a reference.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index cd38cd6..89708b1 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -41,7 +41,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 		return NULL;
 
 	/* Set to 2 to allow both inbound and outbound traffics */
-	/* (ie get_stor_device() and must_get_stor_device()) to proceed. */
+	/* (ie get_stor_device() and get_in_stor_device()) to proceed. */
 	atomic_cmpxchg(&stor_device->ref_count, 0, 2);
 
 	init_waitqueue_head(&stor_device->waiting_to_drain);
@@ -53,7 +53,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 
 
 /* Get the stordevice object iff exists and its refcount > 0 */
-static inline struct storvsc_device *must_get_stor_device(
+static inline struct storvsc_device *get_in_stor_device(
 					struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
@@ -305,7 +305,7 @@ static void storvsc_on_channel_callback(void *context)
 	int ret;
 
 
-	stor_device = must_get_stor_device(device);
+	stor_device = get_in_stor_device(device);
 	if (!stor_device)
 		return;
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 078/117] Staging: hv: storvsc: Rename get_stor_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

In preparation for cleaning up how we manage reference counts on the stor
device, clearly distinguish why we are attempting to acquire a reference.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    3 ++-
 drivers/staging/hv/storvsc.c        |    8 ++++----
 drivers/staging/hv/storvsc_drv.c    |    2 +-
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index a01f9a0..a224413 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -288,7 +288,8 @@ struct storvsc_device {
 
 
 /* Get the stordevice object iff exists and its refcount > 1 */
-static inline struct storvsc_device *get_stor_device(struct hv_device *device)
+static inline struct storvsc_device *get_out_stor_device(
+					struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
 
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 89708b1..313a3f8 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -41,7 +41,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 		return NULL;
 
 	/* Set to 2 to allow both inbound and outbound traffics */
-	/* (ie get_stor_device() and get_in_stor_device()) to proceed. */
+	/* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
 	atomic_cmpxchg(&stor_device->ref_count, 0, 2);
 
 	init_waitqueue_head(&stor_device->waiting_to_drain);
@@ -67,7 +67,7 @@ static inline struct storvsc_device *get_in_stor_device(
 	return stor_device;
 }
 
-/* Drop ref count to 1 to effectively disable get_stor_device() */
+/* Drop ref count to 1 to effectively disable get_out_stor_device() */
 static inline struct storvsc_device *release_stor_device(
 					struct hv_device *device)
 {
@@ -105,7 +105,7 @@ static int storvsc_channel_init(struct hv_device *device)
 	struct vstor_packet *vstor_packet;
 	int ret, t;
 
-	stor_device = get_stor_device(device);
+	stor_device = get_out_stor_device(device);
 	if (!stor_device)
 		return -ENODEV;
 
@@ -427,7 +427,7 @@ int storvsc_do_io(struct hv_device *device,
 	int ret = 0;
 
 	vstor_packet = &request->vstor_packet;
-	stor_device = get_stor_device(device);
+	stor_device = get_out_stor_device(device);
 
 	if (!stor_device)
 		return -ENODEV;
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index bc71024..0f2fc2f 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -346,7 +346,7 @@ static int storvsc_host_reset(struct hv_device *device)
 	int ret, t;
 
 
-	stor_device = get_stor_device(device);
+	stor_device = get_out_stor_device(device);
 	if (!stor_device)
 		return -ENODEV;
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 079/117] Staging: hv: storvsc: Cleanup alloc_stor_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Cleanup alloc_stor_device(), we can set the ref_count directly.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 313a3f8..48bd8da 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -42,7 +42,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 
 	/* Set to 2 to allow both inbound and outbound traffics */
 	/* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
-	atomic_cmpxchg(&stor_device->ref_count, 0, 2);
+	atomic_set(&stor_device->ref_count, 2);
 
 	init_waitqueue_head(&stor_device->waiting_to_drain);
 	stor_device->device = device;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 080/117] Staging: hv: storvsc: Introduce state to manage the lifecycle of stor device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Introduce state to manage the lifecycle of stor device. This would be the
basis for managing the references on the stor object.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    2 +-
 drivers/staging/hv/storvsc.c        |    3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index a224413..d93bf93 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -266,7 +266,7 @@ struct storvsc_device {
 
 	/* 0 indicates the device is being destroyed */
 	atomic_t ref_count;
-
+	bool	 destroy;
 	bool	 drain_notify;
 	atomic_t num_outstanding_req;
 
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 48bd8da..357b08a 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -43,7 +43,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 	/* Set to 2 to allow both inbound and outbound traffics */
 	/* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
 	atomic_set(&stor_device->ref_count, 2);
-
+	stor_device->destroy = false;
 	init_waitqueue_head(&stor_device->waiting_to_drain);
 	stor_device->device = device;
 	device->ext = stor_device;
@@ -401,6 +401,7 @@ int storvsc_dev_remove(struct hv_device *device)
 	struct storvsc_device *stor_device;
 
 	stor_device = release_stor_device(device);
+	stor_device->destroy = true;
 
 	/*
 	 * At this point, all outbound traffic should be disable. We
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 081/117] Staging: hv: vmbus: Introduce a lock to protect the ext field in hv_device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

The current mechanism for handling references in broken.
Introduce a lock to protect the ext field in hv_device.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv.h    |    3 +++
 drivers/staging/hv/vmbus_drv.c |    1 +
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/hv/hyperv.h b/drivers/staging/hv/hyperv.h
index c4a9f38..82ba110 100644
--- a/drivers/staging/hv/hyperv.h
+++ b/drivers/staging/hv/hyperv.h
@@ -826,6 +826,9 @@ struct hv_device {
 
 	struct vmbus_channel *channel;
 
+	/* This lock protects the device extension field */
+	spinlock_t ext_lock;
+
 	/* Device extension; */
 	void *ext;
 };
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index ffd6066..29c1712 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -578,6 +578,7 @@ struct hv_device *vmbus_child_device_create(uuid_le *type,
 		return NULL;
 	}
 
+	spin_lock_init(&child_device_obj->ext_lock);
 	child_device_obj->channel = channel;
 	memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
 	memcpy(&child_device_obj->dev_instance, instance,
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 082/117] Staging: hv: storvsc: Use the newly introduced lock in accessing ext field
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Use the newly introduced lock in accessing ext field.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    6 ++++++
 drivers/staging/hv/storvsc.c        |    6 ++++++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index d93bf93..6b20f1d 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -292,12 +292,15 @@ static inline struct storvsc_device *get_out_stor_device(
 					struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
 	if (stor_device && atomic_read(&stor_device->ref_count) > 1)
 		atomic_inc(&stor_device->ref_count);
 	else
 		stor_device = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	return stor_device;
 }
@@ -306,10 +309,13 @@ static inline struct storvsc_device *get_out_stor_device(
 static inline void put_stor_device(struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
 
 	atomic_dec(&stor_device->ref_count);
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
 static inline void storvsc_wait_to_drain(struct storvsc_device *dev)
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 357b08a..d1b6c4e 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -57,12 +57,15 @@ static inline struct storvsc_device *get_in_stor_device(
 					struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
 	if (stor_device && atomic_read(&stor_device->ref_count))
 		atomic_inc(&stor_device->ref_count);
 	else
 		stor_device = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	return stor_device;
 }
@@ -87,6 +90,7 @@ static inline struct storvsc_device *final_release_stor_device(
 			struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
+	unsigned long flags;
 
 	stor_device = (struct storvsc_device *)device->ext;
 
@@ -94,7 +98,9 @@ static inline struct storvsc_device *final_release_stor_device(
 	while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1)
 		udelay(100);
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	device->ext = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 	return stor_device;
 }
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 083/117] Staging: hv: storvsc: Prevent outgoing traffic when stor dev is destroyed
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Prevent outgoing traffic when stor dev is destroyed.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index 6b20f1d..53b65be 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -296,7 +296,8 @@ static inline struct storvsc_device *get_out_stor_device(
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
-	if (stor_device && atomic_read(&stor_device->ref_count) > 1)
+	if (stor_device && (atomic_read(&stor_device->ref_count) > 1) &&
+		!stor_device->destroy)
 		atomic_inc(&stor_device->ref_count);
 	else
 		stor_device = NULL;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 084/117] Staging: hv: storvsc: Get rid of release_stor_device() by inlining the code
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Get rid of release_stor_device() by inlining the code.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |   23 +++++++----------------
 1 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index d1b6c4e..f52e610 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -70,21 +70,6 @@ static inline struct storvsc_device *get_in_stor_device(
 	return stor_device;
 }
 
-/* Drop ref count to 1 to effectively disable get_out_stor_device() */
-static inline struct storvsc_device *release_stor_device(
-					struct hv_device *device)
-{
-	struct storvsc_device *stor_device;
-
-	stor_device = (struct storvsc_device *)device->ext;
-
-	/* Busy wait until the ref drop to 2, then set it to 1 */
-	while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2)
-		udelay(100);
-
-	return stor_device;
-}
-
 /* Drop ref count to 0. No one can use stor_device object. */
 static inline struct storvsc_device *final_release_stor_device(
 			struct hv_device *device)
@@ -406,7 +391,13 @@ int storvsc_dev_remove(struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
 
-	stor_device = release_stor_device(device);
+	/*
+	 * Since we currently hold a reference on the stor
+	 * device, it is safe to dereference the ext
+	 * pointer.
+	 */
+	stor_device = (struct storvsc_device *)device->ext;
+	atomic_dec(&stor_device->ref_count);
 	stor_device->destroy = true;
 
 	/*
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 085/117] Staging: hv: storvsc: Get rid of final_release_stor_device() by inlining code
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Get rid of final_release_stor_device() by inlining code.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc.c |   25 +++++--------------------
 1 files changed, 5 insertions(+), 20 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index f52e610..c4cb170 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -70,25 +70,6 @@ static inline struct storvsc_device *get_in_stor_device(
 	return stor_device;
 }
 
-/* Drop ref count to 0. No one can use stor_device object. */
-static inline struct storvsc_device *final_release_stor_device(
-			struct hv_device *device)
-{
-	struct storvsc_device *stor_device;
-	unsigned long flags;
-
-	stor_device = (struct storvsc_device *)device->ext;
-
-	/* Busy wait until the ref drop to 1, then set it to 0 */
-	while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1)
-		udelay(100);
-
-	spin_lock_irqsave(&device->ext_lock, flags);
-	device->ext = NULL;
-	spin_unlock_irqrestore(&device->ext_lock, flags);
-	return stor_device;
-}
-
 static int storvsc_channel_init(struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
@@ -390,6 +371,7 @@ int storvsc_dev_add(struct hv_device *device,
 int storvsc_dev_remove(struct hv_device *device)
 {
 	struct storvsc_device *stor_device;
+	unsigned long flags;
 
 	/*
 	 * Since we currently hold a reference on the stor
@@ -408,7 +390,10 @@ int storvsc_dev_remove(struct hv_device *device)
 
 	storvsc_wait_to_drain(stor_device);
 
-	stor_device = final_release_stor_device(device);
+	spin_lock_irqsave(&device->ext_lock, flags);
+	atomic_set(&stor_device->ref_count, 0);
+	device->ext = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	/* Close the channel */
 	vmbus_close(device->channel);
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 086/117] Staging: hv: storvsc: Leverage the spinlock to manage ref_cnt
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Now that we have a spin lock protecting access to the stor device pointer,
use it manage the reference count as well.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    8 ++++----
 drivers/staging/hv/storvsc.c        |   10 +++++-----
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index 53b65be..d946211 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -265,7 +265,7 @@ struct storvsc_device {
 	struct hv_device *device;
 
 	/* 0 indicates the device is being destroyed */
-	atomic_t ref_count;
+	int	 ref_count;
 	bool	 destroy;
 	bool	 drain_notify;
 	atomic_t num_outstanding_req;
@@ -296,9 +296,9 @@ static inline struct storvsc_device *get_out_stor_device(
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
-	if (stor_device && (atomic_read(&stor_device->ref_count) > 1) &&
+	if (stor_device && (stor_device->ref_count > 1) &&
 		!stor_device->destroy)
-		atomic_inc(&stor_device->ref_count);
+		stor_device->ref_count++;
 	else
 		stor_device = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
@@ -315,7 +315,7 @@ static inline void put_stor_device(struct hv_device *device)
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
 
-	atomic_dec(&stor_device->ref_count);
+	stor_device->ref_count--;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index c4cb170..a41be2a 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -42,7 +42,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 
 	/* Set to 2 to allow both inbound and outbound traffics */
 	/* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
-	atomic_set(&stor_device->ref_count, 2);
+	stor_device->ref_count = 2;
 	stor_device->destroy = false;
 	init_waitqueue_head(&stor_device->waiting_to_drain);
 	stor_device->device = device;
@@ -61,8 +61,8 @@ static inline struct storvsc_device *get_in_stor_device(
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
-	if (stor_device && atomic_read(&stor_device->ref_count))
-		atomic_inc(&stor_device->ref_count);
+	if (stor_device && stor_device->ref_count)
+		stor_device->ref_count++;
 	else
 		stor_device = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
@@ -379,7 +379,7 @@ int storvsc_dev_remove(struct hv_device *device)
 	 * pointer.
 	 */
 	stor_device = (struct storvsc_device *)device->ext;
-	atomic_dec(&stor_device->ref_count);
+
 	stor_device->destroy = true;
 
 	/*
@@ -391,7 +391,7 @@ int storvsc_dev_remove(struct hv_device *device)
 	storvsc_wait_to_drain(stor_device);
 
 	spin_lock_irqsave(&device->ext_lock, flags);
-	atomic_set(&stor_device->ref_count, 0);
+	stor_device->ref_count = 0;
 	device->ext = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 087/117] Staging: hv: storvsc: Further cleanup reference counting of stor_device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Further cleanup reference counting of stor_device - when the device is being
destroyed, we will permit incoming traffic only to drain outstanding
requests.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_storage.h |    3 +--
 drivers/staging/hv/storvsc.c        |   22 +++++++++++++---------
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index d946211..a1f3e27 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -287,7 +287,6 @@ struct storvsc_device {
 };
 
 
-/* Get the stordevice object iff exists and its refcount > 1 */
 static inline struct storvsc_device *get_out_stor_device(
 					struct hv_device *device)
 {
@@ -296,7 +295,7 @@ static inline struct storvsc_device *get_out_stor_device(
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
-	if (stor_device && (stor_device->ref_count > 1) &&
+	if (stor_device && (stor_device->ref_count) &&
 		!stor_device->destroy)
 		stor_device->ref_count++;
 	else
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index a41be2a..4d13044 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -40,9 +40,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 	if (!stor_device)
 		return NULL;
 
-	/* Set to 2 to allow both inbound and outbound traffics */
-	/* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
-	stor_device->ref_count = 2;
+	stor_device->ref_count = 1;
 	stor_device->destroy = false;
 	init_waitqueue_head(&stor_device->waiting_to_drain);
 	stor_device->device = device;
@@ -51,8 +49,6 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
 	return stor_device;
 }
 
-
-/* Get the stordevice object iff exists and its refcount > 0 */
 static inline struct storvsc_device *get_in_stor_device(
 					struct hv_device *device)
 {
@@ -61,10 +57,18 @@ static inline struct storvsc_device *get_in_stor_device(
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	stor_device = (struct storvsc_device *)device->ext;
-	if (stor_device && stor_device->ref_count)
-		stor_device->ref_count++;
-	else
-		stor_device = NULL;
+	if (!stor_device)
+		goto cleanup;
+
+	/*
+	 * If the device is being destroyed; allow incoming
+	 * traffic only to cleanup outstanding requests.
+	 */
+	if (stor_device->destroy &&
+		 (atomic_read(&stor_device->num_outstanding_req) == 0))
+		goto cleanup;
+	stor_device->ref_count++;
+cleanup:
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	return stor_device;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 088/117] Staging: hv: netvsc: Inline the code for free_net_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Inline the code for free_net_device().

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |   12 ++----------
 1 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index b6e1fb9..75c6ed7 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -49,14 +49,6 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 	return net_device;
 }
 
-static void free_net_device(struct netvsc_device *device)
-{
-	WARN_ON(atomic_read(&device->refcnt) != 0);
-	device->dev->ext = NULL;
-	kfree(device);
-}
-
-
 /* Get the net device object iff exists and its refcount > 1 */
 static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 {
@@ -438,7 +430,7 @@ int netvsc_device_remove(struct hv_device *device)
 		kfree(netvsc_packet);
 	}
 
-	free_net_device(net_device);
+	kfree(net_device);
 	return 0;
 }
 
@@ -980,7 +972,7 @@ cleanup:
 		release_outbound_net_device(device);
 		release_inbound_net_device(device);
 
-		free_net_device(net_device);
+		kfree(net_device);
 	}
 
 	return ret;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 089/117] Staging: hv: netvsc: Cleanup alloc_net_device()
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Cleanup alloc_net_device(); we can directly set the refcnt.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 75c6ed7..7722102 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -41,7 +41,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 		return NULL;
 
 	/* Set to 2 to allow both inbound and outbound traffic */
-	atomic_cmpxchg(&net_device->refcnt, 0, 2);
+	atomic_set(&net_device->refcnt, 2);
 
 	net_device->dev = device;
 	device->ext = net_device;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 090/117] Staging: hv: netvsc: Introduce state to manage the lifecycle of net device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Introduce state to manage the lifecycle of net device.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_net.h |    1 +
 drivers/staging/hv/netvsc.c     |    3 +++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/hv/hyperv_net.h b/drivers/staging/hv/hyperv_net.h
index 5782fea..0b347c1 100644
--- a/drivers/staging/hv/hyperv_net.h
+++ b/drivers/staging/hv/hyperv_net.h
@@ -371,6 +371,7 @@ struct netvsc_device {
 
 	atomic_t refcnt;
 	atomic_t num_outstanding_sends;
+	bool destroy;
 	/*
 	 * List of free preallocated hv_netvsc_packet to represent receive
 	 * packet
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 7722102..67cf7fb 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -43,6 +43,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 	/* Set to 2 to allow both inbound and outbound traffic */
 	atomic_set(&net_device->refcnt, 2);
 
+	net_device->destroy = false;
 	net_device->dev = device;
 	device->ext = net_device;
 
@@ -404,6 +405,8 @@ int netvsc_device_remove(struct hv_device *device)
 		return -ENODEV;
 	}
 
+	net_device->destroy = true;
+
 	/* Wait for all send completions */
 	while (atomic_read(&net_device->num_outstanding_sends)) {
 		dev_err(&device->device,
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 091/117] Staging: hv: netvsc: Use the newly introduced lock in accessing ext field
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Use the newly introduced lock in accessing ext field.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |   33 ++++++++++++++++++++++++++++++---
 1 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 67cf7fb..c38c669 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -54,12 +54,15 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 {
 	struct netvsc_device *net_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
 	if (net_device && atomic_read(&net_device->refcnt) > 1)
 		atomic_inc(&net_device->refcnt);
 	else
 		net_device = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	return net_device;
 }
@@ -68,33 +71,46 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
 {
 	struct netvsc_device *net_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
 	if (net_device && atomic_read(&net_device->refcnt))
 		atomic_inc(&net_device->refcnt);
 	else
 		net_device = NULL;
 
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 	return net_device;
 }
 
 static void put_net_device(struct hv_device *device)
 {
 	struct netvsc_device *net_device;
+	unsigned long flags;
+
+	spin_lock_irqsave(&device->ext_lock, flags);
 
 	net_device = device->ext;
 
 	atomic_dec(&net_device->refcnt);
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
 static struct netvsc_device *release_outbound_net_device(
 		struct hv_device *device)
 {
 	struct netvsc_device *net_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device == NULL)
+	if (net_device == NULL) {
+		spin_unlock_irqrestore(&device->ext_lock, flags);
 		return NULL;
+	}
+
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	/* Busy wait until the ref drop to 2, then set it to 1 */
 	while (atomic_cmpxchg(&net_device->refcnt, 2, 1) != 2)
@@ -107,16 +123,23 @@ static struct netvsc_device *release_inbound_net_device(
 		struct hv_device *device)
 {
 	struct netvsc_device *net_device;
+	unsigned long flags;
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device == NULL)
+	if (net_device == NULL) {
+		spin_unlock_irqrestore(&device->ext_lock, flags);
 		return NULL;
+	}
 
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 	/* Busy wait until the ref drop to 1, then set it to 0 */
 	while (atomic_cmpxchg(&net_device->refcnt, 1, 0) != 1)
 		udelay(100);
 
+	spin_lock_irqsave(&device->ext_lock, flags);
 	device->ext = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 	return net_device;
 }
 
@@ -397,6 +420,8 @@ int netvsc_device_remove(struct hv_device *device)
 {
 	struct netvsc_device *net_device;
 	struct hv_netvsc_packet *netvsc_packet, *pos;
+	unsigned long flags;
+
 
 	/* Stop outbound traffic ie sends and receives completions */
 	net_device = release_outbound_net_device(device);
@@ -404,8 +429,10 @@ int netvsc_device_remove(struct hv_device *device)
 		dev_err(&device->device, "No net device present!!");
 		return -ENODEV;
 	}
-
+	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device->destroy = true;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
+
 
 	/* Wait for all send completions */
 	while (atomic_read(&net_device->num_outstanding_sends)) {
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 092/117] Staging: hv: netvsc: Prevent outgoing traffic when netvsc dev is destroyed
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Prevent outgoing traffic when netvsc dev is destroyed.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 2ee3f07..538259d 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -58,7 +58,8 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device && atomic_read(&net_device->refcnt) > 1)
+	if (net_device && (atomic_read(&net_device->refcnt) > 1) &&
+		!net_device->destroy)
 		atomic_inc(&net_device->refcnt);
 	else
 		net_device = NULL;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 093/117] Staging: hv: netvsc: Get rid of release_outbound_net_device() by inlining the code
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization
  Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Get rid of release_outbound_net_device() by inlining the code.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |   45 ++++++++++++++++--------------------------
 1 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 7c3d7ac..3975219 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -98,28 +98,6 @@ static void put_net_device(struct hv_device *device)
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
-static struct netvsc_device *release_outbound_net_device(
-		struct hv_device *device)
-{
-	struct netvsc_device *net_device;
-	unsigned long flags;
-
-	spin_lock_irqsave(&device->ext_lock, flags);
-	net_device = device->ext;
-	if (net_device == NULL) {
-		spin_unlock_irqrestore(&device->ext_lock, flags);
-		return NULL;
-	}
-
-	spin_unlock_irqrestore(&device->ext_lock, flags);
-
-	/* Busy wait until the ref drop to 2, then set it to 1 */
-	while (atomic_cmpxchg(&net_device->refcnt, 2, 1) != 2)
-		udelay(100);
-
-	return net_device;
-}
-
 static struct netvsc_device *release_inbound_net_device(
 		struct hv_device *device)
 {
@@ -424,13 +402,13 @@ int netvsc_device_remove(struct hv_device *device)
 	unsigned long flags;
 
 
-	/* Stop outbound traffic ie sends and receives completions */
-	net_device = release_outbound_net_device(device);
-	if (!net_device) {
-		dev_err(&device->device, "No net device present!!");
+	spin_lock_irqsave(&device->ext_lock, flags);
+	net_device = (struct netvsc_device *)device->ext;
+	if (net_device == NULL) {
+		spin_unlock_irqrestore(&device->ext_lock, flags);
 		return -ENODEV;
 	}
-	spin_lock_irqsave(&device->ext_lock, flags);
+	atomic_dec(&net_device->refcnt);
 	net_device->destroy = true;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
@@ -448,6 +426,18 @@ int netvsc_device_remove(struct hv_device *device)
 	/* Stop inbound traffic ie receives and sends completions */
 	net_device = release_inbound_net_device(device);
 
+	/*
+	 * 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.
+	 */
+	while (atomic_read(&net_device->refcnt))
+		udelay(100);
+
 	/* At this point, no one should be accessing netDevice except in here */
 	dev_notice(&device->device, "net device safe to remove");
 
@@ -1000,7 +990,6 @@ cleanup:
 			kfree(packet);
 		}
 
-		release_outbound_net_device(device);
 		release_inbound_net_device(device);
 
 		kfree(net_device);
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 094/117] Staging: hv: netvsc: Get rid of release_inbound_net_device() by inlining the code
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Get rid of release_inbound_net_device() by inlining the code.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |   32 ++++----------------------------
 1 files changed, 4 insertions(+), 28 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 3975219..6805137 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -98,30 +98,6 @@ static void put_net_device(struct hv_device *device)
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
-static struct netvsc_device *release_inbound_net_device(
-		struct hv_device *device)
-{
-	struct netvsc_device *net_device;
-	unsigned long flags;
-
-	spin_lock_irqsave(&device->ext_lock, flags);
-	net_device = device->ext;
-	if (net_device == NULL) {
-		spin_unlock_irqrestore(&device->ext_lock, flags);
-		return NULL;
-	}
-
-	spin_unlock_irqrestore(&device->ext_lock, flags);
-	/* Busy wait until the ref drop to 1, then set it to 0 */
-	while (atomic_cmpxchg(&net_device->refcnt, 1, 0) != 1)
-		udelay(100);
-
-	spin_lock_irqsave(&device->ext_lock, flags);
-	device->ext = NULL;
-	spin_unlock_irqrestore(&device->ext_lock, flags);
-	return net_device;
-}
-
 static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
 {
 	struct nvsp_message *revoke_packet;
@@ -423,8 +399,10 @@ int netvsc_device_remove(struct hv_device *device)
 
 	netvsc_disconnect_vsp(net_device);
 
-	/* Stop inbound traffic ie receives and sends completions */
-	net_device = release_inbound_net_device(device);
+	spin_lock_irqsave(&device->ext_lock, flags);
+	atomic_dec(&net_device->refcnt);
+	device->ext = NULL;
+	spin_unlock_irqrestore(&device->ext_lock, flags);
 
 	/*
 	 * Wait until the ref cnt falls to 0.
@@ -990,8 +968,6 @@ cleanup:
 			kfree(packet);
 		}
 
-		release_inbound_net_device(device);
-
 		kfree(net_device);
 	}
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 095/117] Staging: hv: netvsc: Leverage the spinlock to manage refcnt
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Now that we have a spin lock protecting the device pointer, use it to also
protect the refrence count.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/hyperv_net.h |    2 +-
 drivers/staging/hv/netvsc.c     |   18 +++++++++---------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/staging/hv/hyperv_net.h b/drivers/staging/hv/hyperv_net.h
index 0b347c1..5c8fc31 100644
--- a/drivers/staging/hv/hyperv_net.h
+++ b/drivers/staging/hv/hyperv_net.h
@@ -369,7 +369,7 @@ struct nvsp_message {
 struct netvsc_device {
 	struct hv_device *dev;
 
-	atomic_t refcnt;
+	int refcnt;
 	atomic_t num_outstanding_sends;
 	bool destroy;
 	/*
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 0411332..3b234a3 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -41,7 +41,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 		return NULL;
 
 	/* Set to 2 to allow both inbound and outbound traffic */
-	atomic_set(&net_device->refcnt, 2);
+	net_device->refcnt = 2;
 
 	net_device->destroy = false;
 	net_device->dev = device;
@@ -58,9 +58,9 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device && (atomic_read(&net_device->refcnt) > 1) &&
+	if (net_device && (net_device->refcnt > 1) &&
 		!net_device->destroy)
-		atomic_inc(&net_device->refcnt);
+		net_device->refcnt++;
 	else
 		net_device = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
@@ -76,8 +76,8 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device && atomic_read(&net_device->refcnt))
-		atomic_inc(&net_device->refcnt);
+	if (net_device && net_device->refcnt)
+		net_device->refcnt++;
 	else
 		net_device = NULL;
 
@@ -94,7 +94,7 @@ static void put_net_device(struct hv_device *device)
 
 	net_device = device->ext;
 
-	atomic_dec(&net_device->refcnt);
+	net_device->refcnt--;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 }
 
@@ -385,7 +385,7 @@ int netvsc_device_remove(struct hv_device *device)
 		spin_unlock_irqrestore(&device->ext_lock, flags);
 		return -ENODEV;
 	}
-	atomic_dec(&net_device->refcnt);
+	net_device->refcnt--;
 	net_device->destroy = true;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
@@ -401,7 +401,7 @@ int netvsc_device_remove(struct hv_device *device)
 	netvsc_disconnect_vsp(net_device);
 
 	spin_lock_irqsave(&device->ext_lock, flags);
-	atomic_dec(&net_device->refcnt);
+	net_device->refcnt--;
 	device->ext = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
@@ -414,7 +414,7 @@ int netvsc_device_remove(struct hv_device *device)
 	 * Since the send path is non-blocking, it is reasonable to busy
 	 * wait here.
 	 */
-	while (atomic_read(&net_device->refcnt))
+	while (net_device->refcnt != 0)
 		udelay(100);
 
 	/* At this point, no one should be accessing netDevice except in here */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 096/117] Staging: hv: netvsc: Further cleanup reference counting of netvsc_device
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Further cleanup reference counting of netvsc_device. Since once the device
is marked for destruction, we only allow incoming traffic to drain out
outstanding sends, we can simplify reference counting.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/netvsc.c |   27 ++++++++++++++++++---------
 1 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 4ef17d8..16a80b1 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -17,6 +17,7 @@
  * Authors:
  *   Haiyang Zhang <haiyangz@microsoft.com>
  *   Hank Janssen  <hjanssen@microsoft.com>
+ *   K. Y. Srinivasan <kys@microsoft.com>
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -40,8 +41,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
 	if (!net_device)
 		return NULL;
 
-	/* Set to 2 to allow both inbound and outbound traffic */
-	net_device->refcnt = 2;
+	net_device->refcnt = 1;
 
 	net_device->destroy = false;
 	net_device->dev = device;
@@ -50,7 +50,6 @@ static struct netvsc_device *alloc_net_device(struct hv_device *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;
@@ -58,7 +57,7 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device && (net_device->refcnt > 1) &&
+	if (net_device && (net_device->refcnt) &&
 		!net_device->destroy)
 		net_device->refcnt++;
 	else
@@ -68,7 +67,6 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 	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;
@@ -76,11 +74,23 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
 
 	spin_lock_irqsave(&device->ext_lock, flags);
 	net_device = device->ext;
-	if (net_device && net_device->refcnt)
-		net_device->refcnt++;
-	else
+
+	if (!net_device)
+		goto cleanup;
+
+	/*
+	 * If the device is being destroyed; allow incoming
+	 * traffic only to cleanup outstanding requests.
+	 */
+	if (net_device->destroy &&
+		(atomic_read(&net_device->num_outstanding_sends) == 0)) {
 		net_device = NULL;
+		goto cleanup;
+	}
 
+	net_device->refcnt++;
+
+cleanup:
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 	return net_device;
 }
@@ -400,7 +410,6 @@ int netvsc_device_remove(struct hv_device *device)
 	netvsc_disconnect_vsp(net_device);
 
 	spin_lock_irqsave(&device->ext_lock, flags);
-	net_device->refcnt--;
 	device->ext = NULL;
 	spin_unlock_irqrestore(&device->ext_lock, flags);
 
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 097/117] Staging: hv: storvsc: Add code to handle IDE devices using the storvsc driver
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization; +Cc: Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Add code to handle IDE devices using the storvsc driver. The storvsc_probe()
is modified so that the storvsc driver can surface all disks presented to the
guest as scsi devices using generic upper level Linux scsi drivers.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/storvsc_drv.c |   62 +++++++++++++++++++++++++++++++-------
 1 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 0f2fc2f..efbc603 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -61,6 +61,17 @@ struct storvsc_cmd_request {
 	struct hv_storvsc_request request;
 };
 
+static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
+{
+	*target =
+		dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4];
+
+	*path =
+		dev->dev_instance.b[3] << 24 |
+		dev->dev_instance.b[2] << 16 |
+		dev->dev_instance.b[1] << 8  | dev->dev_instance.b[0];
+}
+
 
 static int storvsc_device_alloc(struct scsi_device *sdevice)
 {
@@ -654,6 +665,14 @@ static const struct hv_vmbus_device_id id_table[] = {
 };
 
 MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static const uuid_le blk_guid = {
+	.b = {
+		0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+		0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+	}
+};
+
 /*
  * storvsc_probe - Add a new device for this driver
  */
@@ -664,6 +683,14 @@ static int storvsc_probe(struct hv_device *device)
 	struct Scsi_Host *host;
 	struct hv_host_device *host_dev;
 	struct storvsc_device_info device_info;
+	bool dev_is_ide;
+	int path = 0;
+	int target = 0;
+
+	if (!uuid_le_cmp(device->dev_type, blk_guid))
+		dev_is_ide = true;
+	else
+		dev_is_ide = false;
 
 	host = scsi_host_alloc(&scsi_driver,
 			       sizeof(struct hv_host_device));
@@ -699,8 +726,14 @@ static int storvsc_probe(struct hv_device *device)
 		return -ENODEV;
 	}
 
-	host_dev->path = device_info.path_id;
-	host_dev->target = device_info.target_id;
+	if (dev_is_ide) {
+		storvsc_get_ide_info(device, &target, &path);
+		host_dev->path = device_info.path_id;
+		host_dev->target = device_info.target_id;
+	} else {
+		host_dev->path = device_info.path_id;
+		host_dev->target = device_info.target_id;
+	}
 
 	/* max # of devices per target */
 	host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
@@ -711,17 +744,24 @@ static int storvsc_probe(struct hv_device *device)
 
 	/* Register the HBA and start the scsi bus scan */
 	ret = scsi_add_host(host, &device->device);
-	if (ret != 0) {
-
-		storvsc_dev_remove(device);
-
-		kmem_cache_destroy(host_dev->request_pool);
-		scsi_host_put(host);
-		return -ENODEV;
-	}
+	if (ret != 0)
+		goto err_out;
 
-	scsi_scan_host(host);
+	if (dev_is_ide) {
+		ret = scsi_add_device(host, 0, target, 0);
+		if (ret) {
+			scsi_remove_host(host);
+			goto err_out;
+		}
+	} else
+		scsi_scan_host(host);
 	return ret;
+
+err_out:
+	storvsc_dev_remove(device);
+	kmem_cache_destroy(host_dev->request_pool);
+	scsi_host_put(host);
+	return -ENODEV;
 }
 
 /* The one and only one */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 098/117] Staging: hv: storvsc: Handle IDE devices using the storvsc driver
From: K. Y. Srinivasan @ 2011-07-15 17:47 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization
  Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1310752065-27895-1-git-send-email-kys@microsoft.com>

Now, enable handling of all IDE devices by extending the storvsc
device id table to handle IDE guid. As part of this cleanup Kconfig
and Hyper-V Makefile to not build the IDE driver (blkvsc).

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/staging/hv/Kconfig       |    7 -------
 drivers/staging/hv/Makefile      |    2 --
 drivers/staging/hv/storvsc_drv.c |    7 +++++++
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 5e0c9f6..26b5064 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -15,13 +15,6 @@ config HYPERV_STORAGE
 	help
 	 Select this option to enable the Hyper-V virtual storage driver.
 
-config HYPERV_BLOCK
-	tristate "Microsoft Hyper-V virtual block driver"
-	depends on BLOCK && SCSI && (LBDAF || 64BIT)
-	default HYPERV
-	help
-	  Select this option to enable the Hyper-V virtual block driver.
-
 config HYPERV_NET
 	tristate "Microsoft Hyper-V virtual network driver"
 	depends on NET
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index 3004674..bb89437 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -1,6 +1,5 @@
 obj-$(CONFIG_HYPERV)		+= hv_vmbus.o hv_timesource.o
 obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
-obj-$(CONFIG_HYPERV_BLOCK)	+= hv_blkvsc.o
 obj-$(CONFIG_HYPERV_NET)	+= hv_netvsc.o
 obj-$(CONFIG_HYPERV_UTILS)	+= hv_utils.o
 obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
@@ -9,6 +8,5 @@ hv_vmbus-y := vmbus_drv.o \
 		 hv.o connection.o channel.o \
 		 channel_mgmt.o ring_buffer.o
 hv_storvsc-y := storvsc_drv.o storvsc.o
-hv_blkvsc-y := blkvsc_drv.o  storvsc.o
 hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
 hv_utils-y := hv_util.o hv_kvp.o
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index efbc603..5777482 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -657,6 +657,13 @@ static const struct hv_vmbus_device_id id_table[] = {
 		}
 	},
 	{
+		/* IDE guid */
+		.guid = {
+			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+		}
+	},
+	{
 		.guid = {
 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-- 
1.7.4.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox