]>
Commit | Line | Data |
---|---|---|
94bcd1f7 GKH |
1 | From b29ef3546aecb253a5552b198cef23750d56e1e4 Mon Sep 17 00:00:00 2001 |
2 | From: "K. Y. Srinivasan" <kys@microsoft.com> | |
3 | Date: Thu, 28 Aug 2014 18:29:52 -0700 | |
4 | Subject: Drivers: hv: vmbus: Cleanup hv_post_message() | |
5 | ||
6 | From: "K. Y. Srinivasan" <kys@microsoft.com> | |
7 | ||
8 | commit b29ef3546aecb253a5552b198cef23750d56e1e4 upstream. | |
9 | ||
10 | Minimize failures in this function by pre-allocating the buffer | |
11 | for posting messages. The hypercall for posting the message can fail | |
12 | for a number of reasons: | |
13 | ||
14 | 1. Transient resource related issues | |
15 | 2. Buffer alignment | |
16 | 3. Buffer cannot span a page boundry | |
17 | ||
18 | We address issues 2 and 3 by preallocating a per-cpu page for the buffer. | |
19 | Transient resource related failures are handled by retrying by the callers | |
20 | of this function. | |
21 | ||
22 | This patch is based on the investigation | |
23 | done by Dexuan Cui <decui@microsoft.com>. | |
24 | ||
25 | I would like to thank Sitsofe Wheeler <sitsofe@yahoo.com> | |
26 | for reporting the issue and helping in debuggging. | |
27 | ||
28 | Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> | |
29 | Reported-by: Sitsofe Wheeler <sitsofe@yahoo.com> | |
30 | Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com> | |
31 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
32 | ||
33 | --- | |
34 | drivers/hv/hv.c | 27 +++++++++++++++------------ | |
35 | drivers/hv/hyperv_vmbus.h | 4 ++++ | |
36 | 2 files changed, 19 insertions(+), 12 deletions(-) | |
37 | ||
38 | --- a/drivers/hv/hv.c | |
39 | +++ b/drivers/hv/hv.c | |
40 | @@ -138,6 +138,8 @@ int hv_init(void) | |
41 | memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); | |
42 | memset(hv_context.synic_message_page, 0, | |
43 | sizeof(void *) * NR_CPUS); | |
44 | + memset(hv_context.post_msg_page, 0, | |
45 | + sizeof(void *) * NR_CPUS); | |
46 | memset(hv_context.vp_index, 0, | |
47 | sizeof(int) * NR_CPUS); | |
48 | memset(hv_context.event_dpc, 0, | |
49 | @@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_ | |
50 | enum hv_message_type message_type, | |
51 | void *payload, size_t payload_size) | |
52 | { | |
53 | - struct aligned_input { | |
54 | - u64 alignment8; | |
55 | - struct hv_input_post_message msg; | |
56 | - }; | |
57 | ||
58 | struct hv_input_post_message *aligned_msg; | |
59 | u16 status; | |
60 | - unsigned long addr; | |
61 | ||
62 | if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) | |
63 | return -EMSGSIZE; | |
64 | ||
65 | - addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC); | |
66 | - if (!addr) | |
67 | - return -ENOMEM; | |
68 | - | |
69 | aligned_msg = (struct hv_input_post_message *) | |
70 | - (ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN)); | |
71 | + hv_context.post_msg_page[get_cpu()]; | |
72 | ||
73 | aligned_msg->connectionid = connection_id; | |
74 | + aligned_msg->reserved = 0; | |
75 | aligned_msg->message_type = message_type; | |
76 | aligned_msg->payload_size = payload_size; | |
77 | memcpy((void *)aligned_msg->payload, payload, payload_size); | |
78 | @@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_ | |
79 | status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) | |
80 | & 0xFFFF; | |
81 | ||
82 | - kfree((void *)addr); | |
83 | - | |
84 | + put_cpu(); | |
85 | return status; | |
86 | } | |
87 | ||
88 | @@ -294,6 +287,14 @@ int hv_synic_alloc(void) | |
89 | pr_err("Unable to allocate SYNIC event page\n"); | |
90 | goto err; | |
91 | } | |
92 | + | |
93 | + hv_context.post_msg_page[cpu] = | |
94 | + (void *)get_zeroed_page(GFP_ATOMIC); | |
95 | + | |
96 | + if (hv_context.post_msg_page[cpu] == NULL) { | |
97 | + pr_err("Unable to allocate post msg page\n"); | |
98 | + goto err; | |
99 | + } | |
100 | } | |
101 | ||
102 | return 0; | |
103 | @@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu) | |
104 | free_page((unsigned long)hv_context.synic_event_page[cpu]); | |
105 | if (hv_context.synic_message_page[cpu]) | |
106 | free_page((unsigned long)hv_context.synic_message_page[cpu]); | |
107 | + if (hv_context.post_msg_page[cpu]) | |
108 | + free_page((unsigned long)hv_context.post_msg_page[cpu]); | |
109 | } | |
110 | ||
111 | void hv_synic_free(void) | |
112 | --- a/drivers/hv/hyperv_vmbus.h | |
113 | +++ b/drivers/hv/hyperv_vmbus.h | |
114 | @@ -515,6 +515,10 @@ struct hv_context { | |
115 | * per-cpu list of the channels based on their CPU affinity. | |
116 | */ | |
117 | struct list_head percpu_list[NR_CPUS]; | |
118 | + /* | |
119 | + * buffer to post messages to the host. | |
120 | + */ | |
121 | + void *post_msg_page[NR_CPUS]; | |
122 | }; | |
123 | ||
124 | extern struct hv_context hv_context; |