forked from mirrors/linux
		
	Drivers: hv: vmbus: Cleanup hv_post_message()
Minimize failures in this function by pre-allocating the buffer
for posting messages. The hypercall for posting the message can fail
for a number of reasons:
        1. Transient resource related issues
        2. Buffer alignment
        3. Buffer cannot span a page boundry
We address issues 2 and 3 by preallocating a per-cpu page for the buffer.
Transient resource related failures are handled by retrying by the callers
of this function.
This patch is based on the investigation
done by Dexuan Cui <decui@microsoft.com>.
I would like to thank Sitsofe Wheeler <sitsofe@yahoo.com>
for reporting the issue and helping in debuggging.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reported-by: Sitsofe Wheeler <sitsofe@yahoo.com>
Cc: <stable@vger.kernel.org>
Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									98d731bb06
								
							
						
					
					
						commit
						b29ef3546a
					
				
					 2 changed files with 19 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -138,6 +138,8 @@ int hv_init(void)
 | 
			
		|||
	memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
 | 
			
		||||
	memset(hv_context.synic_message_page, 0,
 | 
			
		||||
	       sizeof(void *) * NR_CPUS);
 | 
			
		||||
	memset(hv_context.post_msg_page, 0,
 | 
			
		||||
	       sizeof(void *) * NR_CPUS);
 | 
			
		||||
	memset(hv_context.vp_index, 0,
 | 
			
		||||
	       sizeof(int) * NR_CPUS);
 | 
			
		||||
	memset(hv_context.event_dpc, 0,
 | 
			
		||||
| 
						 | 
				
			
			@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_id connection_id,
 | 
			
		|||
		  enum hv_message_type message_type,
 | 
			
		||||
		  void *payload, size_t payload_size)
 | 
			
		||||
{
 | 
			
		||||
	struct aligned_input {
 | 
			
		||||
		u64 alignment8;
 | 
			
		||||
		struct hv_input_post_message msg;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct hv_input_post_message *aligned_msg;
 | 
			
		||||
	u16 status;
 | 
			
		||||
	unsigned long addr;
 | 
			
		||||
 | 
			
		||||
	if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
 | 
			
		||||
		return -EMSGSIZE;
 | 
			
		||||
 | 
			
		||||
	addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
 | 
			
		||||
	if (!addr)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	aligned_msg = (struct hv_input_post_message *)
 | 
			
		||||
			(ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN));
 | 
			
		||||
			hv_context.post_msg_page[get_cpu()];
 | 
			
		||||
 | 
			
		||||
	aligned_msg->connectionid = connection_id;
 | 
			
		||||
	aligned_msg->reserved = 0;
 | 
			
		||||
	aligned_msg->message_type = message_type;
 | 
			
		||||
	aligned_msg->payload_size = payload_size;
 | 
			
		||||
	memcpy((void *)aligned_msg->payload, payload, payload_size);
 | 
			
		||||
| 
						 | 
				
			
			@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_id connection_id,
 | 
			
		|||
	status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
 | 
			
		||||
		& 0xFFFF;
 | 
			
		||||
 | 
			
		||||
	kfree((void *)addr);
 | 
			
		||||
 | 
			
		||||
	put_cpu();
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -294,6 +287,14 @@ int hv_synic_alloc(void)
 | 
			
		|||
			pr_err("Unable to allocate SYNIC event page\n");
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		hv_context.post_msg_page[cpu] =
 | 
			
		||||
			(void *)get_zeroed_page(GFP_ATOMIC);
 | 
			
		||||
 | 
			
		||||
		if (hv_context.post_msg_page[cpu] == NULL) {
 | 
			
		||||
			pr_err("Unable to allocate post msg page\n");
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu)
 | 
			
		|||
		free_page((unsigned long)hv_context.synic_event_page[cpu]);
 | 
			
		||||
	if (hv_context.synic_message_page[cpu])
 | 
			
		||||
		free_page((unsigned long)hv_context.synic_message_page[cpu]);
 | 
			
		||||
	if (hv_context.post_msg_page[cpu])
 | 
			
		||||
		free_page((unsigned long)hv_context.post_msg_page[cpu]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hv_synic_free(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -515,6 +515,10 @@ struct hv_context {
 | 
			
		|||
	 * per-cpu list of the channels based on their CPU affinity.
 | 
			
		||||
	 */
 | 
			
		||||
	struct list_head percpu_list[NR_CPUS];
 | 
			
		||||
	/*
 | 
			
		||||
	 * buffer to post messages to the host.
 | 
			
		||||
	 */
 | 
			
		||||
	void *post_msg_page[NR_CPUS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct hv_context hv_context;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue