From 7047f17d70fc0599563d30d0791692cb5fe42ae6 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 25 Dec 2015 20:00:30 -0800 Subject: Drivers: hv: vmbus: Add vendor and device atttributes Add vendor and device attributes to VMBUS devices. These will be used by Hyper-V tools as well user-level RDMA libraries that will use the vendor/device tuple to discover the RDMA device. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/linux/hyperv.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 753dbad0bf94..3172521df805 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -633,6 +633,32 @@ enum hv_signal_policy { HV_SIGNAL_POLICY_EXPLICIT, }; +enum vmbus_device_type { + HV_IDE = 0, + HV_SCSI, + HV_FC, + HV_NIC, + HV_ND, + HV_PCIE, + HV_FB, + HV_KBD, + HV_MOUSE, + HV_KVP, + HV_TS, + HV_HB, + HV_SHUTDOWN, + HV_FCOPY, + HV_BACKUP, + HV_DM, + HV_UNKOWN, +}; + +struct vmbus_device { + u16 dev_type; + uuid_le guid; + bool perf_device; +}; + struct vmbus_channel { /* Unique channel id */ int id; @@ -959,6 +985,8 @@ struct hv_device { /* the device instance id of this device */ uuid_le dev_instance; + u16 vendor_id; + u16 device_id; struct device device; -- cgit v1.3-8-gc7d7 From 3c75354d043ad546148d6992e40033ecaefc5ea5 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:37 -0800 Subject: Drivers: hv: vmbus: add a helper function to set a channel's pending send size This will be used by the coming net/hvsock driver. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/linux/hyperv.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 3172521df805..4af51a3f98d9 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -816,6 +816,12 @@ static inline void *get_per_channel_state(struct vmbus_channel *c) return c->per_channel_state; } +static inline void set_channel_pending_send_size(struct vmbus_channel *c, + u32 size) +{ + c->outbound.ring_buffer->pending_send_sz = size; +} + void vmbus_onmessage(void *context); int vmbus_request_offers(void); -- cgit v1.3-8-gc7d7 From e8d6ca023efce3bd80050dcd9e708ee3cf8babd4 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:38 -0800 Subject: Drivers: hv: vmbus: define the new offer type for Hyper-V socket (hvsock) A helper function is also added. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/linux/hyperv.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 4af51a3f98d9..79c4aa70eff3 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -235,6 +235,7 @@ struct vmbus_channel_offer { #define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100 #define VMBUS_CHANNEL_PARENT_OFFER 0x200 #define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400 +#define VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER 0x2000 struct vmpacket_descriptor { u16 type; @@ -795,6 +796,12 @@ struct vmbus_channel { enum hv_signal_policy signal_policy; }; +static inline bool is_hvsock_channel(const struct vmbus_channel *c) +{ + return !!(c->offermsg.offer.chn_flags & + VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER); +} + static inline void set_channel_signal_state(struct vmbus_channel *c, enum hv_signal_policy policy) { -- cgit v1.3-8-gc7d7 From 5c23a1a5c60b0f472cfa61cd7d8279f8aaeb5b64 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:40 -0800 Subject: Drivers: hv: vmbus: define a new VMBus message type for hvsock A function to send the type of message is also added. The coming net/hvsock driver will use this function to proactively request the host to offer a VMBus channel for a new hvsock connection. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 15 +++++++++++++++ drivers/hv/channel_mgmt.c | 4 ++++ include/linux/hyperv.h | 13 +++++++++++++ 3 files changed, 32 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 3f0453302146..fcab234796ef 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -219,6 +219,21 @@ error0: } EXPORT_SYMBOL_GPL(vmbus_open); +/* Used for Hyper-V Socket: a guest client's connect() to the host */ +int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id, + const uuid_le *shv_host_servie_id) +{ + struct vmbus_channel_tl_connect_request conn_msg; + + memset(&conn_msg, 0, sizeof(conn_msg)); + conn_msg.header.msgtype = CHANNELMSG_TL_CONNECT_REQUEST; + conn_msg.guest_endpoint_id = *shv_guest_servie_id; + conn_msg.host_service_id = *shv_host_servie_id; + + return vmbus_post_msg(&conn_msg, sizeof(conn_msg)); +} +EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request); + /* * create_gpadl_header - Creates a gpadl for the specified buffer */ diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index d6c611457601..60ca25b93b4c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -958,6 +958,10 @@ struct vmbus_channel_message_table_entry {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response}, {CHANNELMSG_UNLOAD, 0, NULL}, {CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response}, + {CHANNELMSG_18, 0, NULL}, + {CHANNELMSG_19, 0, NULL}, + {CHANNELMSG_20, 0, NULL}, + {CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL}, }; /* diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 79c4aa70eff3..898eac9e8c13 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -392,6 +392,10 @@ enum vmbus_channel_message_type { CHANNELMSG_VERSION_RESPONSE = 15, CHANNELMSG_UNLOAD = 16, CHANNELMSG_UNLOAD_RESPONSE = 17, + CHANNELMSG_18 = 18, + CHANNELMSG_19 = 19, + CHANNELMSG_20 = 20, + CHANNELMSG_TL_CONNECT_REQUEST = 21, CHANNELMSG_COUNT }; @@ -562,6 +566,13 @@ struct vmbus_channel_initiate_contact { u64 monitor_page2; } __packed; +/* Hyper-V socket: guest's connect()-ing to host */ +struct vmbus_channel_tl_connect_request { + struct vmbus_channel_message_header header; + uuid_le guest_endpoint_id; + uuid_le host_service_id; +} __packed; + struct vmbus_channel_version_response { struct vmbus_channel_message_header header; u8 version_supported; @@ -1283,4 +1294,6 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); extern __u32 vmbus_proto_version; +int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id, + const uuid_le *shv_host_servie_id); #endif /* _HYPERV_H */ -- cgit v1.3-8-gc7d7 From 8981da320a11217589aa3c50f9e891bcdef07ece Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:41 -0800 Subject: Drivers: hv: vmbus: add a hvsock flag in struct hv_driver Only the coming hv_sock driver has a "true" value for this flag. We treat the hvsock offers/channels as special VMBus devices. Since the hv_sock driver handles all the hvsock offers/channels, we need to tweak vmbus_match() for hv_sock driver, so we introduce this flag. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 4 ++++ include/linux/hyperv.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 3668a95778ec..063e5f53ca78 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -582,6 +582,10 @@ 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); + /* The hv_sock driver handles all hv_sock offers. */ + if (is_hvsock_channel(hv_dev->channel)) + return drv->hvsock; + if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type)) return 1; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 898eac9e8c13..f636f91f104b 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -990,6 +990,20 @@ extern void vmbus_ontimer(unsigned long data); struct hv_driver { const char *name; + /* + * A hvsock offer, which has a VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER + * channel flag, actually doesn't mean a synthetic device because the + * offer's if_type/if_instance can change for every new hvsock + * connection. + * + * However, to facilitate the notification of new-offer/rescind-offer + * from vmbus driver to hvsock driver, we can handle hvsock offer as + * a special vmbus device, and hence we need the below flag to + * indicate if the driver is the hvsock driver or not: we need to + * specially treat the hvosck offer & driver in vmbus_match(). + */ + bool hvsock; + /* the device type supported by this driver */ uuid_le dev_type; const struct hv_vmbus_device_id *id_table; -- cgit v1.3-8-gc7d7 From 499e8401a515d04daa986b995da710d2b9737764 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:42 -0800 Subject: Drivers: hv: vmbus: add a per-channel rescind callback This will be used by the coming hv_sock driver. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 11 +++++++++++ include/linux/hyperv.h | 9 +++++++++ 2 files changed, 20 insertions(+) (limited to 'include/linux/hyperv.h') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 60ca25b93b4c..76864c98a110 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -741,6 +741,10 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) spin_unlock_irqrestore(&channel->lock, flags); if (channel->device_obj) { + if (channel->chn_rescind_callback) { + channel->chn_rescind_callback(channel); + return; + } /* * We will have to unregister this device from the * driver core. @@ -1110,3 +1114,10 @@ bool vmbus_are_subchannels_present(struct vmbus_channel *primary) return ret; } EXPORT_SYMBOL_GPL(vmbus_are_subchannels_present); + +void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, + void (*chn_rescind_cb)(struct vmbus_channel *)) +{ + channel->chn_rescind_callback = chn_rescind_cb; +} +EXPORT_SYMBOL_GPL(vmbus_set_chn_rescind_callback); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f636f91f104b..2e54e34e5feb 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -765,6 +765,12 @@ struct vmbus_channel { */ void (*sc_creation_callback)(struct vmbus_channel *new_sc); + /* + * Channel rescind callback. Some channels (the hvsock ones), need to + * register a callback which is invoked in vmbus_onoffer_rescind(). + */ + void (*chn_rescind_callback)(struct vmbus_channel *channel); + /* * The spinlock to protect the structure. It is being used to protect * test-and-set access to various attributes of the structure as well @@ -851,6 +857,9 @@ int vmbus_request_offers(void); void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, void (*sc_cr_cb)(struct vmbus_channel *new_sc)); +void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, + void (*chn_rescind_cb)(struct vmbus_channel *)); + /* * Retrieve the (sub) channel on which to send an outgoing request. * When a primary channel has multiple sub-channels, we choose a -- cgit v1.3-8-gc7d7 From 85d9aa705184a4504d0330017e3956fcdae8a9d6 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:43 -0800 Subject: Drivers: hv: vmbus: add an API vmbus_hvsock_device_unregister() The hvsock driver needs this API to release all the resources related to the channel. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 33 ++++++++++++++++++++++++++++----- drivers/hv/connection.c | 4 ++-- include/linux/hyperv.h | 2 ++ 3 files changed, 32 insertions(+), 7 deletions(-) (limited to 'include/linux/hyperv.h') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 76864c98a110..cf311be88cb4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -310,6 +310,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) vmbus_release_relid(relid); BUG_ON(!channel->rescind); + BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); if (channel->target_cpu != get_cpu()) { put_cpu(); @@ -321,9 +322,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) } if (channel->primary_channel == NULL) { - mutex_lock(&vmbus_connection.channel_mutex); list_del(&channel->listentry); - mutex_unlock(&vmbus_connection.channel_mutex); primary_channel = channel; } else { @@ -367,6 +366,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) bool fnew = true; unsigned long flags; u16 dev_type; + int ret; /* Make sure this is a new offer */ mutex_lock(&vmbus_connection.channel_mutex); @@ -449,7 +449,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) * binding which eventually invokes the device driver's AddDevice() * method. */ - if (vmbus_device_register(newchannel->device_obj) != 0) { + mutex_lock(&vmbus_connection.channel_mutex); + ret = vmbus_device_register(newchannel->device_obj); + mutex_unlock(&vmbus_connection.channel_mutex); + + if (ret != 0) { pr_err("unable to add child device object (relid %d)\n", newchannel->offermsg.child_relid); kfree(newchannel->device_obj); @@ -725,6 +729,8 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) struct device *dev; rescind = (struct vmbus_channel_rescind_offer *)hdr; + + mutex_lock(&vmbus_connection.channel_mutex); channel = relid2channel(rescind->child_relid); if (channel == NULL) { @@ -733,7 +739,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) * vmbus_process_offer(), we have already invoked * vmbus_release_relid() on error. */ - return; + goto out; } spin_lock_irqsave(&channel->lock, flags); @@ -743,7 +749,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) if (channel->device_obj) { if (channel->chn_rescind_callback) { channel->chn_rescind_callback(channel); - return; + goto out; } /* * We will have to unregister this device from the @@ -758,8 +764,25 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) hv_process_channel_removal(channel, channel->offermsg.child_relid); } + +out: + mutex_unlock(&vmbus_connection.channel_mutex); } +void vmbus_hvsock_device_unregister(struct vmbus_channel *channel) +{ + mutex_lock(&vmbus_connection.channel_mutex); + + BUG_ON(!is_hvsock_channel(channel)); + + channel->rescind = true; + vmbus_device_unregister(channel->device_obj); + + mutex_unlock(&vmbus_connection.channel_mutex); +} +EXPORT_SYMBOL_GPL(vmbus_hvsock_device_unregister); + + /* * vmbus_onoffers_delivered - * This is invoked when all offers have been delivered. diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 4a320e60641a..fa86b2cb28b8 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -288,7 +288,8 @@ struct vmbus_channel *relid2channel(u32 relid) struct list_head *cur, *tmp; struct vmbus_channel *cur_sc; - mutex_lock(&vmbus_connection.channel_mutex); + BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); + list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { if (channel->offermsg.child_relid == relid) { found_channel = channel; @@ -307,7 +308,6 @@ struct vmbus_channel *relid2channel(u32 relid) } } } - mutex_unlock(&vmbus_connection.channel_mutex); return found_channel; } diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 2e54e34e5feb..c056f058dcf8 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1069,6 +1069,8 @@ int __must_check __vmbus_driver_register(struct hv_driver *hv_driver, const char *mod_name); void vmbus_driver_unregister(struct hv_driver *hv_driver); +void vmbus_hvsock_device_unregister(struct vmbus_channel *channel); + int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, resource_size_t min, resource_size_t max, resource_size_t size, resource_size_t align, -- cgit v1.3-8-gc7d7 From fe760e4d64fe5c17c39e86c410d41f6587ee88bc Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 27 Jan 2016 22:29:45 -0800 Subject: Drivers: hv: vmbus: Give control over how the ring access is serialized On the channel send side, many of the VMBUS device drivers explicity serialize access to the outgoing ring buffer. Give more control to the VMBUS device drivers in terms how to serialize accesss to the outgoing ring buffer. The default behavior will be to aquire the ring lock to preserve the current behavior. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 15 +++++++++++---- drivers/hv/channel_mgmt.c | 1 + drivers/hv/hyperv_vmbus.h | 2 +- drivers/hv/ring_buffer.c | 13 ++++++++----- include/linux/hyperv.h | 16 ++++++++++++++++ 5 files changed, 37 insertions(+), 10 deletions(-) (limited to 'include/linux/hyperv.h') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index fcab234796ef..56dd261f7142 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -639,6 +639,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, u64 aligned_data = 0; int ret; bool signal = false; + bool lock = channel->acquire_ring_lock; int num_vecs = ((bufferlen != 0) ? 3 : 1); @@ -658,7 +659,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, bufferlist[2].iov_len = (packetlen_aligned - packetlen); ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs, - &signal); + &signal, lock); /* * Signalling the host is conditional on many factors: @@ -738,6 +739,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, struct kvec bufferlist[3]; u64 aligned_data = 0; bool signal = false; + bool lock = channel->acquire_ring_lock; if (pagecount > MAX_PAGE_BUFFER_COUNT) return -EINVAL; @@ -774,7 +776,8 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); + ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, + &signal, lock); /* * Signalling the host is conditional on many factors: @@ -837,6 +840,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, struct kvec bufferlist[3]; u64 aligned_data = 0; bool signal = false; + bool lock = channel->acquire_ring_lock; packetlen = desc_size + bufferlen; packetlen_aligned = ALIGN(packetlen, sizeof(u64)); @@ -856,7 +860,8 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); + ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, + &signal, lock); if (ret == 0 && signal) vmbus_setevent(channel); @@ -881,6 +886,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, struct kvec bufferlist[3]; u64 aligned_data = 0; bool signal = false; + bool lock = channel->acquire_ring_lock; u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset, multi_pagebuffer->len); @@ -919,7 +925,8 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); + ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, + &signal, lock); if (ret == 0 && signal) vmbus_setevent(channel); diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index cf311be88cb4..b40f429aaa13 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -259,6 +259,7 @@ static struct vmbus_channel *alloc_channel(void) return NULL; channel->id = atomic_inc_return(&chan_num); + channel->acquire_ring_lock = true; spin_lock_init(&channel->inbound_lock); spin_lock_init(&channel->lock); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index ac7aa303c37d..b9ea7f59036b 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -529,7 +529,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, struct kvec *kv_list, - u32 kv_count, bool *signal); + u32 kv_count, bool *signal, bool lock); int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 *buffer_actual_len, diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 1145f3b8e4e0..5613e2b5cff7 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -314,7 +314,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) /* Write to the ring buffer. */ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, - struct kvec *kv_list, u32 kv_count, bool *signal) + struct kvec *kv_list, u32 kv_count, bool *signal, bool lock) { int i = 0; u32 bytes_avail_towrite; @@ -324,14 +324,15 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, u32 next_write_location; u32 old_write; u64 prev_indices = 0; - unsigned long flags; + unsigned long flags = 0; for (i = 0; i < kv_count; i++) totalbytes_towrite += kv_list[i].iov_len; totalbytes_towrite += sizeof(u64); - spin_lock_irqsave(&outring_info->ring_lock, flags); + if (lock) + spin_lock_irqsave(&outring_info->ring_lock, flags); hv_get_ringbuffer_availbytes(outring_info, &bytes_avail_toread, @@ -343,7 +344,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, * is empty since the read index == write index. */ if (bytes_avail_towrite <= totalbytes_towrite) { - spin_unlock_irqrestore(&outring_info->ring_lock, flags); + if (lock) + spin_unlock_irqrestore(&outring_info->ring_lock, flags); return -EAGAIN; } @@ -374,7 +376,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, hv_set_next_write_location(outring_info, next_write_location); - spin_unlock_irqrestore(&outring_info->ring_lock, flags); + if (lock) + spin_unlock_irqrestore(&outring_info->ring_lock, flags); *signal = hv_need_to_signal(old_write, outring_info); return 0; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index c056f058dcf8..d23dab0d770b 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -811,8 +811,24 @@ struct vmbus_channel { * signaling control. */ enum hv_signal_policy signal_policy; + /* + * On the channel send side, many of the VMBUS + * device drivers explicity serialize access to the + * outgoing ring buffer. Give more control to the + * VMBUS device drivers in terms how to serialize + * accesss to the outgoing ring buffer. + * The default behavior will be to aquire the + * ring lock to preserve the current behavior. + */ + bool acquire_ring_lock; + }; +static inline void set_channel_lock_state(struct vmbus_channel *c, bool state) +{ + c->acquire_ring_lock = state; +} + static inline bool is_hvsock_channel(const struct vmbus_channel *c) { return !!(c->offermsg.offer.chn_flags & -- cgit v1.3-8-gc7d7