2015-11-12 00:54:30

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 00/12] Drivers: hv: vmbus: Miscellaneous fixes and cleanup

Miscellaneous fixes and cleanup.
Changes from V1:
Fixed the typo in patch number 3.
Included the patch tools/hv: Use include/uapi with __EXPORTED_HEADERS__

Dexuan Cui (5):
Drivers: hv: vmbus: serialize process_chn_event() and
vmbus_close_internal()
Drivers: hv: vmbus: do sanity check of channel state in
vmbus_close_internal()
Drivers: hv: vmbus: fix rescind-offer handling for device without a
driver
Drivers: hv: vmbus: release relid on error in vmbus_process_offer()
Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex

Jake Oshins (1):
drivers:hv: Allow for MMIO claims that span ACPI _CRS records

K. Y. Srinivasan (4):
Drivers: hv: vmbus: Use uuid_le type consistently
Drivers: hv: vmbus: Use uuid_le_cmp() for comparing GUIDs
Drivers: hv: vmbus: Get rid of the unused macro
Drivers: hv: vmbus: Get rid of the unused irq variable

Kamal Mostafa (1):
tools/hv: Use include/uapi with __EXPORTED_HEADERS__

Olaf Hering (1):
Drivers: hv: vss: run only on supported host versions

drivers/hv/channel.c | 39 ++++++++++++---
drivers/hv/channel_mgmt.c | 42 ++++++++++-------
drivers/hv/connection.c | 7 +--
drivers/hv/hv_snapshot.c | 5 ++
drivers/hv/hyperv_vmbus.h | 2 +-
drivers/hv/vmbus_drv.c | 61 +++++++++++------------
include/linux/hyperv.h | 101 ++++++++++++---------------------------
include/linux/mod_devicetable.h | 2 +-
scripts/mod/file2alias.c | 2 +-
tools/hv/Makefile | 2 +
10 files changed, 128 insertions(+), 135 deletions(-)

--
1.7.4.1


2015-11-12 00:57:00

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 01/12] Drivers: hv: vss: run only on supported host versions

From: Olaf Hering <[email protected]>

The Backup integration service on WS2012 has appearently trouble to
negotiate with a guest which does not support the provided util version.
Currently the VSS driver supports only version 5/0. A WS2012 offers only
version 1/x and 3/x, and vmbus_prep_negotiate_resp correctly returns an
empty icframe_vercnt/icmsg_vercnt. But the host ignores that and
continues to send ICMSGTYPE_NEGOTIATE messages. The result are weird
errors during boot and general misbehaviour.

Check the Windows version to work around the host bug, skip hv_vss_init
on WS2012 and older.

Signed-off-by: Olaf Hering <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/hv_snapshot.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index a548ae4..81882d4 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -331,6 +331,11 @@ static void vss_on_reset(void)
int
hv_vss_init(struct hv_util_service *srv)
{
+ if (vmbus_proto_version < VERSION_WIN8_1) {
+ pr_warn("Integration service 'Backup (volume snapshot)'"
+ " not supported on this host version.\n");
+ return -ENOTSUPP;
+ }
recv_buffer = srv->recv_buffer;

/*
--
1.7.4.1

2015-11-12 00:54:57

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 02/12] Drivers: hv: vmbus: Use uuid_le type consistently

Consistently use uuid_le type in the Hyper-V driver code.

Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel_mgmt.c | 2 +-
drivers/hv/vmbus_drv.c | 10 ++--
include/linux/hyperv.h | 92 +++++++++++++-------------------------
include/linux/mod_devicetable.h | 2 +-
scripts/mod/file2alias.c | 2 +-
5 files changed, 40 insertions(+), 68 deletions(-)

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index a77646b..38470aa 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -408,7 +408,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
struct cpumask *alloced_mask;

for (i = IDE; i < MAX_PERF_CHN; i++) {
- if (!memcmp(type_guid->b, hp_devs[i].guid,
+ if (!memcmp(type_guid->b, &hp_devs[i].guid,
sizeof(uuid_le))) {
perf_chn = true;
break;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index c01b689..7078b5f 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -531,7 +531,7 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)

static const uuid_le null_guid;

-static inline bool is_null_guid(const __u8 *guid)
+static inline bool is_null_guid(const uuid_le *guid)
{
if (memcmp(guid, &null_guid, sizeof(uuid_le)))
return false;
@@ -544,9 +544,9 @@ static inline bool is_null_guid(const __u8 *guid)
*/
static const struct hv_vmbus_device_id *hv_vmbus_get_id(
const struct hv_vmbus_device_id *id,
- const __u8 *guid)
+ const uuid_le *guid)
{
- for (; !is_null_guid(id->guid); id++)
+ for (; !is_null_guid(&id->guid); id++)
if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
return id;

@@ -563,7 +563,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct hv_driver *drv = drv_to_hv_drv(driver);
struct hv_device *hv_dev = device_to_hv_device(device);

- if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b))
+ if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
return 1;

return 0;
@@ -580,7 +580,7 @@ static int vmbus_probe(struct device *child_device)
struct hv_device *dev = device_to_hv_device(child_device);
const struct hv_vmbus_device_id *dev_id;

- dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b);
+ dev_id = hv_vmbus_get_id(drv->id_table, &dev->dev_type);
if (drv->probe) {
ret = drv->probe(dev, dev_id);
if (ret != 0)
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 5587899..ee243a7 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -996,6 +996,8 @@ u64 hv_do_hypercall(u64 control, void *input, void *output);
.guid = { g0, g1, g2, g3, g4, g5, g6, g7, \
g8, g9, ga, gb, gc, gd, ge, gf },

+
+
/*
* GUID definitions of various offer types - services offered to the guest.
*/
@@ -1005,118 +1007,94 @@ u64 hv_do_hypercall(u64 control, void *input, void *output);
* {f8615163-df3e-46c5-913f-f2d2f965ed0e}
*/
#define HV_NIC_GUID \
- .guid = { \
- 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, \
- 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e \
- }
+ .guid = UUID_LE(0xf8615163, 0xdf3e, 0x46c5, 0x91, 0x3f, \
+ 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e)

/*
* IDE GUID
* {32412632-86cb-44a2-9b5c-50d1417354f5}
*/
#define HV_IDE_GUID \
- .guid = { \
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 \
- }
+ .guid = UUID_LE(0x32412632, 0x86cb, 0x44a2, 0x9b, 0x5c, \
+ 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5)

/*
* SCSI GUID
* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
*/
#define HV_SCSI_GUID \
- .guid = { \
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f \
- }
+ .guid = UUID_LE(0xba6163d9, 0x04a1, 0x4d29, 0xb6, 0x05, \
+ 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f)

/*
* Shutdown GUID
* {0e0b6031-5213-4934-818b-38d90ced39db}
*/
#define HV_SHUTDOWN_GUID \
- .guid = { \
- 0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, \
- 0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb \
- }
+ .guid = UUID_LE(0x0e0b6031, 0x5213, 0x4934, 0x81, 0x8b, \
+ 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb)

/*
* Time Synch GUID
* {9527E630-D0AE-497b-ADCE-E80AB0175CAF}
*/
#define HV_TS_GUID \
- .guid = { \
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, \
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf \
- }
+ .guid = UUID_LE(0x9527e630, 0xd0ae, 0x497b, 0xad, 0xce, \
+ 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)

/*
* Heartbeat GUID
* {57164f39-9115-4e78-ab55-382f3bd5422d}
*/
#define HV_HEART_BEAT_GUID \
- .guid = { \
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, \
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d \
- }
+ .guid = UUID_LE(0x57164f39, 0x9115, 0x4e78, 0xab, 0x55, \
+ 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)

/*
* KVP GUID
* {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}
*/
#define HV_KVP_GUID \
- .guid = { \
- 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, \
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6 \
- }
+ .guid = UUID_LE(0xa9a0f4e7, 0x5a45, 0x4d96, 0xb8, 0x27, \
+ 0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6)

/*
* Dynamic memory GUID
* {525074dc-8985-46e2-8057-a307dc18a502}
*/
#define HV_DM_GUID \
- .guid = { \
- 0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, \
- 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02 \
- }
+ .guid = UUID_LE(0x525074dc, 0x8985, 0x46e2, 0x80, 0x57, \
+ 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02)

/*
* Mouse GUID
* {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}
*/
#define HV_MOUSE_GUID \
- .guid = { \
- 0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c, \
- 0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a \
- }
+ .guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \
+ 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a)

/*
* VSS (Backup/Restore) GUID
*/
#define HV_VSS_GUID \
- .guid = { \
- 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \
- 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40 \
- }
+ .guid = UUID_LE(0x35fa2e29, 0xea23, 0x4236, 0x96, 0xae, \
+ 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40)
/*
* Synthetic Video GUID
* {DA0A7802-E377-4aac-8E77-0558EB1073F8}
*/
#define HV_SYNTHVID_GUID \
- .guid = { \
- 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
- 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
- }
+ .guid = UUID_LE(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \
+ 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8)

/*
* Synthetic FC GUID
* {2f9bcc4a-0069-4af3-b76b-6fd0be528cda}
*/
#define HV_SYNTHFC_GUID \
- .guid = { \
- 0x4A, 0xCC, 0x9B, 0x2F, 0x69, 0x00, 0xF3, 0x4A, \
- 0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \
- }
+ .guid = UUID_LE(0x2f9bcc4a, 0x0069, 0x4af3, 0xb7, 0x6b, \
+ 0x6f, 0xd0, 0xbe, 0x52, 0x8c, 0xda)

/*
* Guest File Copy Service
@@ -1124,20 +1102,16 @@ u64 hv_do_hypercall(u64 control, void *input, void *output);
*/

#define HV_FCOPY_GUID \
- .guid = { \
- 0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \
- 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
- }
+ .guid = UUID_LE(0x34d14be3, 0xdee4, 0x41c8, 0x9a, 0xe7, \
+ 0x6b, 0x17, 0x49, 0x77, 0xc1, 0x92)

/*
* NetworkDirect. This is the guest RDMA service.
* {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}
*/
#define HV_ND_GUID \
- .guid = { \
- 0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \
- 0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \
- }
+ .guid = UUID_LE(0x8c2eaf3d, 0x32a7, 0x4b09, 0xab, 0x99, \
+ 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01)

/*
* PCI Express Pass Through
@@ -1145,10 +1119,8 @@ u64 hv_do_hypercall(u64 control, void *input, void *output);
*/

#define HV_PCIE_GUID \
- .guid = { \
- 0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44, \
- 0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F \
- }
+ .guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \
+ 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)

/*
* Common header for Hyper-V ICs
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 6975cbf..10f83a4 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -396,7 +396,7 @@ struct virtio_device_id {
* For Hyper-V devices we use the device guid as the id.
*/
struct hv_vmbus_device_id {
- __u8 guid[16];
+ uuid_le guid;
kernel_ulong_t driver_data; /* Data private to the driver */
};

diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 9bc2cfe..4f62291 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -917,7 +917,7 @@ static int do_vmbus_entry(const char *filename, void *symval,
char guid_name[(sizeof(*guid) + 1) * 2];

for (i = 0; i < (sizeof(*guid) * 2); i += 2)
- sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2]));
+ sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));

strcpy(alias, "vmbus:");
strcat(alias, guid_name);
--
1.7.4.1

2015-11-12 00:55:55

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 03/12] Drivers: hv: vmbus: Use uuid_le_cmp() for comparing GUIDs

Use uuid_le_cmp() for comparing GUIDs.

Signed-off-by: K. Y. Srinivasan <[email protected]>
---
V2: Fixed the typo in both the commit log and Subject line.

drivers/hv/channel_mgmt.c | 3 +--
drivers/hv/vmbus_drv.c | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 38470aa..dc4fb0b 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -408,8 +408,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
struct cpumask *alloced_mask;

for (i = IDE; i < MAX_PERF_CHN; i++) {
- if (!memcmp(type_guid->b, &hp_devs[i].guid,
- sizeof(uuid_le))) {
+ if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) {
perf_chn = true;
break;
}
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 7078b5f..9e0e25c 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -533,7 +533,7 @@ static const uuid_le null_guid;

static inline bool is_null_guid(const uuid_le *guid)
{
- if (memcmp(guid, &null_guid, sizeof(uuid_le)))
+ if (uuid_le_cmp(*guid, null_guid))
return false;
return true;
}
@@ -547,7 +547,7 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(
const uuid_le *guid)
{
for (; !is_null_guid(&id->guid); id++)
- if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
+ if (!uuid_le_cmp(id->guid, *guid))
return id;

return NULL;
--
1.7.4.1

2015-11-12 00:54:58

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 04/12] Drivers: hv: vmbus: Get rid of the unused macro

The macro VMBUS_DEVICE() is unused; get rid of it.

Signed-off-by: K. Y. Srinivasan <[email protected]>
---
include/linux/hyperv.h | 13 -------------
1 files changed, 0 insertions(+), 13 deletions(-)

diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index ee243a7..437c9c8 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -985,19 +985,6 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
int vmbus_cpu_number_to_vp_number(int cpu_number);
u64 hv_do_hypercall(u64 control, void *input, void *output);

-/**
- * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device
- *
- * This macro is used to create a struct hv_vmbus_device_id that matches a
- * specific device.
- */
-#define VMBUS_DEVICE(g0, g1, g2, g3, g4, g5, g6, g7, \
- g8, g9, ga, gb, gc, gd, ge, gf) \
- .guid = { g0, g1, g2, g3, g4, g5, g6, g7, \
- g8, g9, ga, gb, gc, gd, ge, gf },
-
-
-
/*
* GUID definitions of various offer types - services offered to the guest.
*/
--
1.7.4.1

2015-11-12 00:55:54

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 05/12] Drivers: hv: vmbus: Get rid of the unused irq variable

The irq we extract from ACPI is not used - we deliver hypervisor
interrupts on a special vector. Make the necessary adjustments.

Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/vmbus_drv.c | 16 +++-------------
1 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 9e0e25c..ab888a1 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -47,7 +47,6 @@ static struct acpi_device *hv_acpi_dev;

static struct tasklet_struct msg_dpc;
static struct completion probe_event;
-static int irq;


static void hyperv_report_panic(struct pt_regs *regs)
@@ -835,10 +834,9 @@ static void vmbus_isr(void)
* Here, we
* - initialize the vmbus driver context
* - invoke the vmbus hv main init routine
- * - get the irq resource
* - retrieve the channel offers
*/
-static int vmbus_bus_init(int irq)
+static int vmbus_bus_init(void)
{
int ret;

@@ -1033,9 +1031,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
struct resource **prev_res = NULL;

switch (res->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- irq = res->data.irq.interrupts[0];
- return AE_OK;

/*
* "Address" descriptors are for bus windows. Ignore
@@ -1294,7 +1289,7 @@ static int __init hv_acpi_init(void)
init_completion(&probe_event);

/*
- * Get irq resources first.
+ * Get ACPI resources first.
*/
ret = acpi_bus_register_driver(&vmbus_acpi_driver);

@@ -1307,12 +1302,7 @@ static int __init hv_acpi_init(void)
goto cleanup;
}

- if (irq <= 0) {
- ret = -ENODEV;
- goto cleanup;
- }
-
- ret = vmbus_bus_init(irq);
+ ret = vmbus_bus_init();
if (ret)
goto cleanup;

--
1.7.4.1

2015-11-12 00:56:59

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 06/12] Drivers: hv: vmbus: serialize process_chn_event() and vmbus_close_internal()

From: Dexuan Cui <[email protected]>

process_chn_event(), running in the tasklet, can race with
vmbus_close_internal() in the case of SMP guest, e.g., when the former is
accessing channel->inbound.ring_buffer, the latter could be freeing the
ring_buffer pages.

To resolve the race, we can serialize them by disabling the tasklet when
the latter is running here.

Signed-off-by: Dexuan Cui <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index c4dcab0..f7f3d5c 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/hyperv.h>
#include <linux/uio.h>
+#include <linux/interrupt.h>

#include "hyperv_vmbus.h"

@@ -496,8 +497,21 @@ static void reset_channel_cb(void *arg)
static int vmbus_close_internal(struct vmbus_channel *channel)
{
struct vmbus_channel_close_channel *msg;
+ struct tasklet_struct *tasklet;
int ret;

+ /*
+ * process_chn_event(), running in the tasklet, can race
+ * with vmbus_close_internal() in the case of SMP guest, e.g., when
+ * the former is accessing channel->inbound.ring_buffer, the latter
+ * could be freeing the ring_buffer pages.
+ *
+ * To resolve the race, we can serialize them by disabling the
+ * tasklet when the latter is running here.
+ */
+ tasklet = hv_context.event_dpc[channel->target_cpu];
+ tasklet_disable(tasklet);
+
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
@@ -525,7 +539,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to post the close msg,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}

/* Tear down the gpadl for the channel's ring buffer */
@@ -538,7 +552,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to teardown gpadl,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}
}

@@ -555,6 +569,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
if (channel->rescind)
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
+out:
+ tasklet_enable(tasklet);
+
return ret;
}

--
1.7.4.1

2015-11-12 00:55:00

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 07/12] Drivers: hv: vmbus: do sanity check of channel state in vmbus_close_internal()

From: Dexuan Cui <[email protected]>

This fixes an incorrect assumption of channel state in the function.

Signed-off-by: Dexuan Cui <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index f7f3d5c..00e1be7 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -512,6 +512,18 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
tasklet = hv_context.event_dpc[channel->target_cpu];
tasklet_disable(tasklet);

+ /*
+ * In case a device driver's probe() fails (e.g.,
+ * util_probe() -> vmbus_open() returns -ENOMEM) and the device is
+ * rescinded later (e.g., we dynamically disble an Integrated Service
+ * in Hyper-V Manager), the driver's remove() invokes vmbus_close():
+ * here we should skip most of the below cleanup work.
+ */
+ if (channel->state != CHANNEL_OPENED_STATE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
--
1.7.4.1

2015-11-12 00:55:53

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 08/12] Drivers: hv: vmbus: fix rescind-offer handling for device without a driver

From: Dexuan Cui <[email protected]>

In the path vmbus_onoffer_rescind() -> vmbus_device_unregister() ->
device_unregister() -> ... -> __device_release_driver(), we can see for a
device without a driver loaded: dev->driver is NULL, so
dev->bus->remove(dev), namely vmbus_remove(), isn't invoked.

As a result, vmbus_remove() -> hv_process_channel_removal() isn't invoked
and some cleanups(like sending a CHANNELMSG_RELID_RELEASED message to the
host) aren't done.

We can demo the issue this way:
1. rmmod hv_utils;
2. disable the Heartbeat Integration Service in Hyper-V Manager and lsvmbus
shows the device disappears.
3. re-enable the Heartbeat in Hyper-V Manager and modprobe hv_utils, but
lsvmbus shows the device can't appear again.
This is because, the host thinks the VM hasn't released the relid, so can't
re-offer the device to the VM.

We can fix the issue by moving hv_process_channel_removal()
from vmbus_close_internal() to vmbus_device_release(), since the latter is
always invoked on device_unregister(), whether or not the dev has a driver
loaded.

Signed-off-by: Dexuan Cui <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel.c | 6 ------
drivers/hv/channel_mgmt.c | 6 +++---
drivers/hv/vmbus_drv.c | 15 +++------------
3 files changed, 6 insertions(+), 21 deletions(-)

diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 00e1be7..77d2579 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -575,12 +575,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));

- /*
- * If the channel has been rescinded; process device removal.
- */
- if (channel->rescind)
- hv_process_channel_removal(channel,
- channel->offermsg.child_relid);
out:
tasklet_enable(tasklet);

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index dc4fb0b..7903acc 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -191,6 +191,8 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
if (channel == NULL)
return;

+ BUG_ON(!channel->rescind);
+
if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu,
@@ -230,9 +232,7 @@ void vmbus_free_channels(void)

list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
- /* if we don't set rescind to true, vmbus_close_internal()
- * won't invoke hv_process_channel_removal().
- */
+ /* hv_process_channel_removal() needs this */
channel->rescind = true;

vmbus_device_unregister(channel->device_obj);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index ab888a1..f123bca 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -601,23 +601,11 @@ static int vmbus_remove(struct device *child_device)
{
struct hv_driver *drv;
struct hv_device *dev = device_to_hv_device(child_device);
- u32 relid = dev->channel->offermsg.child_relid;

if (child_device->driver) {
drv = drv_to_hv_drv(child_device->driver);
if (drv->remove)
drv->remove(dev);
- else {
- hv_process_channel_removal(dev->channel, relid);
- pr_err("remove not set for driver %s\n",
- dev_name(child_device));
- }
- } else {
- /*
- * We don't have a driver for this device; deal with the
- * rescind message by removing the channel.
- */
- hv_process_channel_removal(dev->channel, relid);
}

return 0;
@@ -652,7 +640,10 @@ static void vmbus_shutdown(struct device *child_device)
static void vmbus_device_release(struct device *device)
{
struct hv_device *hv_dev = device_to_hv_device(device);
+ struct vmbus_channel *channel = hv_dev->channel;

+ hv_process_channel_removal(channel,
+ channel->offermsg.child_relid);
kfree(hv_dev);

}
--
1.7.4.1

2015-11-12 00:55:57

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 09/12] Drivers: hv: vmbus: release relid on error in vmbus_process_offer()

From: Dexuan Cui <[email protected]>

We want to simplify vmbus_onoffer_rescind() by not invoking
hv_process_channel_removal(NULL, ...).

Signed-off-by: Dexuan Cui <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel_mgmt.c | 21 +++++++++++++++------
1 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 7903acc..9c9da3a 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -177,19 +177,22 @@ static void percpu_channel_deq(void *arg)
}


-void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+static void vmbus_release_relid(u32 relid)
{
struct vmbus_channel_relid_released msg;
- unsigned long flags;
- struct vmbus_channel *primary_channel;

memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+}

- if (channel == NULL)
- return;
+void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+{
+ unsigned long flags;
+ struct vmbus_channel *primary_channel;
+
+ vmbus_release_relid(relid);

BUG_ON(!channel->rescind);

@@ -336,6 +339,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
return;

err_deq_chan:
+ vmbus_release_relid(newchannel->offermsg.child_relid);
+
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
list_del(&newchannel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
@@ -587,7 +592,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
channel = relid2channel(rescind->child_relid);

if (channel == NULL) {
- hv_process_channel_removal(NULL, rescind->child_relid);
+ /*
+ * This is very impossible, because in
+ * vmbus_process_offer(), we have already invoked
+ * vmbus_release_relid() on error.
+ */
return;
}

--
1.7.4.1

2015-11-12 00:57:01

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 10/12] Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex

From: Dexuan Cui <[email protected]>

spinlock is unnecessary here.
mutex is enough.

Signed-off-by: Dexuan Cui <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/channel_mgmt.c | 12 ++++++------
drivers/hv/connection.c | 7 +++----
drivers/hv/hyperv_vmbus.h | 2 +-
3 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 9c9da3a..d013171 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -206,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
}

if (channel->primary_channel == NULL) {
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&channel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);

primary_channel = channel;
} else {
@@ -253,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
unsigned long flags;

/* Make sure this is a new offer */
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);

list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (!uuid_le_cmp(channel->offermsg.offer.if_type,
@@ -269,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list);

- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);

if (!fnew) {
/*
@@ -341,9 +341,9 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
err_deq_chan:
vmbus_release_relid(newchannel->offermsg.child_relid);

- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&newchannel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);

if (newchannel->target_cpu != get_cpu()) {
put_cpu();
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 4fc2e88..521f48e 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -146,7 +146,7 @@ int vmbus_connect(void)
spin_lock_init(&vmbus_connection.channelmsg_lock);

INIT_LIST_HEAD(&vmbus_connection.chn_list);
- spin_lock_init(&vmbus_connection.channel_lock);
+ mutex_init(&vmbus_connection.channel_mutex);

/*
* Setup the vmbus event connection for channel interrupt
@@ -282,11 +282,10 @@ struct vmbus_channel *relid2channel(u32 relid)
{
struct vmbus_channel *channel;
struct vmbus_channel *found_channel = NULL;
- unsigned long flags;
struct list_head *cur, *tmp;
struct vmbus_channel *cur_sc;

- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) {
found_channel = channel;
@@ -305,7 +304,7 @@ struct vmbus_channel *relid2channel(u32 relid)
}
}
}
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);

return found_channel;
}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 64950d8..0af6dce 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -688,7 +688,7 @@ struct vmbus_connection {

/* List of channels */
struct list_head chn_list;
- spinlock_t channel_lock;
+ struct mutex channel_mutex;

struct workqueue_struct *work_queue;
};
--
1.7.4.1

2015-11-12 00:56:58

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH V2 11/12] drivers:hv: Allow for MMIO claims that span ACPI _CRS records

From: Jake Oshins <[email protected]>

This patch makes 16GB GPUs work in Hyper-V VMs, since, for
compatibility reasons, the Hyper-V BIOS lists MMIO ranges in 2GB
chunks in its root bus's _CRS object.

Signed-off-by: Jake Oshins <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
drivers/hv/vmbus_drv.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index f123bca..328e4c3 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1063,12 +1063,28 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
new_res->start = start;
new_res->end = end;

+ /*
+ * Stick ranges from higher in address space at the front of the list.
+ * If two ranges are adjacent, merge them.
+ */
do {
if (!*old_res) {
*old_res = new_res;
break;
}

+ if (((*old_res)->end + 1) == new_res->start) {
+ (*old_res)->end = new_res->end;
+ kfree(new_res);
+ break;
+ }
+
+ if ((*old_res)->start == new_res->end + 1) {
+ (*old_res)->start = new_res->start;
+ kfree(new_res);
+ break;
+ }
+
if ((*old_res)->end < new_res->start) {
new_res->sibling = *old_res;
if (prev_res)
--
1.7.4.1

2015-11-12 00:57:03

by KY Srinivasan

[permalink] [raw]
Subject: [PATCH 12/12] tools/hv: Use include/uapi with __EXPORTED_HEADERS__

From: Kamal Mostafa <[email protected]>

Use the local uapi headers to keep in sync with "recently" added #define's
(e.g. VSS_OP_REGISTER1).

Fixes: 3eb2094c59e89db2bedd401e23c7a870081c9edb
Signed-off-by: Kamal Mostafa <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
---
tools/hv/Makefile | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/tools/hv/Makefile b/tools/hv/Makefile
index a8ab795..a8c4644 100644
--- a/tools/hv/Makefile
+++ b/tools/hv/Makefile
@@ -5,6 +5,8 @@ PTHREAD_LIBS = -lpthread
WARNINGS = -Wall -Wextra
CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) $(shell getconf LFS_CFLAGS)

+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+
all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
%: %.c
$(CC) $(CFLAGS) -o $@ $^
--
1.7.4.1

2015-11-12 10:41:28

by Vitaly Kuznetsov

[permalink] [raw]
Subject: Re: [PATCH V2 10/12] Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex

"K. Y. Srinivasan" <[email protected]> writes:

> From: Dexuan Cui <[email protected]>
>
> spinlock is unnecessary here.
> mutex is enough.

Hm, mutex is usually required when we need to sleep and a spinlock is
enough otherwise :-)

Or are you trying to say we don't need to disable interrupts here? In
that can maybe we can just switch to spin_lock()/spin_unlock()?

>
> Signed-off-by: Dexuan Cui <[email protected]>
> Signed-off-by: K. Y. Srinivasan <[email protected]>
> ---
> drivers/hv/channel_mgmt.c | 12 ++++++------
> drivers/hv/connection.c | 7 +++----
> drivers/hv/hyperv_vmbus.h | 2 +-
> 3 files changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
> index 9c9da3a..d013171 100644
> --- a/drivers/hv/channel_mgmt.c
> +++ b/drivers/hv/channel_mgmt.c
> @@ -206,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
> }
>
> if (channel->primary_channel == NULL) {
> - spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
> + mutex_lock(&vmbus_connection.channel_mutex);
> list_del(&channel->listentry);
> - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
> + mutex_unlock(&vmbus_connection.channel_mutex);
>
> primary_channel = channel;
> } else {
> @@ -253,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
> unsigned long flags;
>
> /* Make sure this is a new offer */
> - spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
> + mutex_lock(&vmbus_connection.channel_mutex);
>
> list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
> if (!uuid_le_cmp(channel->offermsg.offer.if_type,
> @@ -269,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
> list_add_tail(&newchannel->listentry,
> &vmbus_connection.chn_list);
>
> - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
> + mutex_unlock(&vmbus_connection.channel_mutex);
>
> if (!fnew) {
> /*
> @@ -341,9 +341,9 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
> err_deq_chan:
> vmbus_release_relid(newchannel->offermsg.child_relid);
>
> - spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
> + mutex_lock(&vmbus_connection.channel_mutex);
> list_del(&newchannel->listentry);
> - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
> + mutex_unlock(&vmbus_connection.channel_mutex);
>
> if (newchannel->target_cpu != get_cpu()) {
> put_cpu();
> diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
> index 4fc2e88..521f48e 100644
> --- a/drivers/hv/connection.c
> +++ b/drivers/hv/connection.c
> @@ -146,7 +146,7 @@ int vmbus_connect(void)
> spin_lock_init(&vmbus_connection.channelmsg_lock);
>
> INIT_LIST_HEAD(&vmbus_connection.chn_list);
> - spin_lock_init(&vmbus_connection.channel_lock);
> + mutex_init(&vmbus_connection.channel_mutex);
>
> /*
> * Setup the vmbus event connection for channel interrupt
> @@ -282,11 +282,10 @@ struct vmbus_channel *relid2channel(u32 relid)
> {
> struct vmbus_channel *channel;
> struct vmbus_channel *found_channel = NULL;
> - unsigned long flags;
> struct list_head *cur, *tmp;
> struct vmbus_channel *cur_sc;
>
> - spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
> + mutex_lock(&vmbus_connection.channel_mutex);
> list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
> if (channel->offermsg.child_relid == relid) {
> found_channel = channel;
> @@ -305,7 +304,7 @@ struct vmbus_channel *relid2channel(u32 relid)
> }
> }
> }
> - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
> + mutex_unlock(&vmbus_connection.channel_mutex);
>
> return found_channel;
> }
> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
> index 64950d8..0af6dce 100644
> --- a/drivers/hv/hyperv_vmbus.h
> +++ b/drivers/hv/hyperv_vmbus.h
> @@ -688,7 +688,7 @@ struct vmbus_connection {
>
> /* List of channels */
> struct list_head chn_list;
> - spinlock_t channel_lock;
> + struct mutex channel_mutex;
>
> struct workqueue_struct *work_queue;
> };

--
Vitaly

2015-11-12 13:11:16

by Dexuan Cui

[permalink] [raw]
Subject: RE: [PATCH V2 10/12] Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex

> From: Vitaly Kuznetsov [mailto:[email protected]]
> Sent: Thursday, November 12, 2015 18:41
> To: Dexuan Cui <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; KY Srinivasan <[email protected]>
> Subject: Re: [PATCH V2 10/12] Drivers: hv: vmbus: channge
> vmbus_connection.channel_lock to mutex
>
> "K. Y. Srinivasan" <[email protected]> writes:
>
> > From: Dexuan Cui <[email protected]>
> >
> > spinlock is unnecessary here.
> > mutex is enough.
>
> Hm, mutex is usually required when we need to sleep and a spinlock is
> enough otherwise :-)

Sorry, I should have written a better changelog. :-)

> Or are you trying to say we don't need to disable interrupts here? In

Yes.
Here we try to protect vmbus_connection.chn_list and the related
channel pointer (see relid2channel()) from being updated in parallel.

The parallel paths, e.g., vmbus_process_offer() and
vmbus_onoffer_rescind(), are in process context and no irq context is
involved, so we don't need disable interrupts at all.

> that can maybe we can just switch to spin_lock()/spin_unlock()?

Switching to mutex actually makes preparation for a later patch (which
will be posted to LKML once this pachset is accepted):

Drivers: hv: vmbus: add an API vmbus_hvsock_device_unregister()
https://github.com/dcui/linux/commit/185afe8394a9bdae2be11ee1ea2a38d05e373025
(on branch decui/vmsock_1020)

For a vmsock socket connection, the host and the guest can be closing
the connection at the same time.

When the host tries to close the connection, a rescind offer is received
in the VM.

When the guest tries to close the connection, a new vmbus API
vmbus_hvsock_device_unregister(channel) is invoked, so
vmbus_hvsock_device_unregister() -> vmbus_device_unregister() is
invoked and this can be running in parallel with
vmbus_onoffer_rescind() -> vmbus_device_unregister().

The issue of "vmbus_onoffer_rescind () -> relid2channel()" is:
it returns a channel pointer without the spinlock held, so actually
there is no real protection for the channel pointer.

So IMO we need to serialize vmbus_onoffer_rescind() and
vmbus_hvsock_device_unregister().
Here I use mutex (rather than spinlock) because the critical section
can sleep, due to vmbus_device_unregister().

Thanks,
-- Dexuan