aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorHank Janssen <hjanssen@microsoft.com>2010-12-13 19:23:36 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-12-16 15:37:51 -0500
commit45241e50e3e741ee2a148693888b48e90e806de9 (patch)
tree86609094a15f5e5c8f8b66c59e600124115c7f7d /drivers/staging
parent244ba85606b567e6e990d2fac61e3bde5ff8f0ad (diff)
Staging: hv: Use only one txf buffer per channel and kmalloc/GFP_KERNEL on initialize
Correct issue with not checking kmalloc return value. This fix now only uses one receive buffer for all hv_utils channels, and will do only one kmalloc on init and will return with a -ENOMEM if kmalloc fails on initialize. And properly clean up memory on failure. Thanks to Evgeniy Polyakov <zbr@ioremap.net> for pointing this out. And thanks to Jesper Juhl <jj@chaosbits.net> and Ky Srinivasan <ksrinivasan@novell.com> for suggesting a better implementation of my original patch. Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Hank Janssen <hjanssen@microsoft.com> Reviewed-by: Jesper Juhl <jj@chaosbits.net> Cc: Evgeniy Polyakov <zbr@ioremap.net> Cc: Jesper Juhl <jj@chaosbits.net> Cc: Ky Srinivasan <ksrinivasan@novell.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/hv/hv_utils.c87
1 files changed, 47 insertions, 40 deletions
diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c
index 53e1e290b0f1..0074581f20e8 100644
--- a/drivers/staging/hv/hv_utils.c
+++ b/drivers/staging/hv/hv_utils.c
@@ -38,12 +38,14 @@
38#include "vmbus_api.h" 38#include "vmbus_api.h"
39#include "utils.h" 39#include "utils.h"
40 40
41static u8 *shut_txf_buf;
42static u8 *time_txf_buf;
43static u8 *hbeat_txf_buf;
41 44
42static void shutdown_onchannelcallback(void *context) 45static void shutdown_onchannelcallback(void *context)
43{ 46{
44 struct vmbus_channel *channel = context; 47 struct vmbus_channel *channel = context;
45 u8 *buf; 48 u32 recvlen;
46 u32 buflen, recvlen;
47 u64 requestid; 49 u64 requestid;
48 u8 execute_shutdown = false; 50 u8 execute_shutdown = false;
49 51
@@ -52,24 +54,23 @@ static void shutdown_onchannelcallback(void *context)
52 struct icmsg_hdr *icmsghdrp; 54 struct icmsg_hdr *icmsghdrp;
53 struct icmsg_negotiate *negop = NULL; 55 struct icmsg_negotiate *negop = NULL;
54 56
55 buflen = PAGE_SIZE; 57 vmbus_recvpacket(channel, shut_txf_buf,
56 buf = kmalloc(buflen, GFP_ATOMIC); 58 PAGE_SIZE, &recvlen, &requestid);
57
58 vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
59 59
60 if (recvlen > 0) { 60 if (recvlen > 0) {
61 DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld", 61 DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
62 recvlen, requestid); 62 recvlen, requestid);
63 63
64 icmsghdrp = (struct icmsg_hdr *)&buf[ 64 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
65 sizeof(struct vmbuspipe_hdr)]; 65 sizeof(struct vmbuspipe_hdr)];
66 66
67 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 67 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
68 prep_negotiate_resp(icmsghdrp, negop, buf); 68 prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
69 } else { 69 } else {
70 shutdown_msg = (struct shutdown_msg_data *)&buf[ 70 shutdown_msg =
71 sizeof(struct vmbuspipe_hdr) + 71 (struct shutdown_msg_data *)&shut_txf_buf[
72 sizeof(struct icmsg_hdr)]; 72 sizeof(struct vmbuspipe_hdr) +
73 sizeof(struct icmsg_hdr)];
73 74
74 switch (shutdown_msg->flags) { 75 switch (shutdown_msg->flags) {
75 case 0: 76 case 0:
@@ -93,13 +94,11 @@ static void shutdown_onchannelcallback(void *context)
93 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 94 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
94 | ICMSGHDRFLAG_RESPONSE; 95 | ICMSGHDRFLAG_RESPONSE;
95 96
96 vmbus_sendpacket(channel, buf, 97 vmbus_sendpacket(channel, shut_txf_buf,
97 recvlen, requestid, 98 recvlen, requestid,
98 VmbusPacketTypeDataInBand, 0); 99 VmbusPacketTypeDataInBand, 0);
99 } 100 }
100 101
101 kfree(buf);
102
103 if (execute_shutdown == true) 102 if (execute_shutdown == true)
104 orderly_poweroff(false); 103 orderly_poweroff(false);
105} 104}
@@ -150,28 +149,25 @@ static inline void adj_guesttime(u64 hosttime, u8 flags)
150static void timesync_onchannelcallback(void *context) 149static void timesync_onchannelcallback(void *context)
151{ 150{
152 struct vmbus_channel *channel = context; 151 struct vmbus_channel *channel = context;
153 u8 *buf; 152 u32 recvlen;
154 u32 buflen, recvlen;
155 u64 requestid; 153 u64 requestid;
156 struct icmsg_hdr *icmsghdrp; 154 struct icmsg_hdr *icmsghdrp;
157 struct ictimesync_data *timedatap; 155 struct ictimesync_data *timedatap;
158 156
159 buflen = PAGE_SIZE; 157 vmbus_recvpacket(channel, time_txf_buf,
160 buf = kmalloc(buflen, GFP_ATOMIC); 158 PAGE_SIZE, &recvlen, &requestid);
161
162 vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
163 159
164 if (recvlen > 0) { 160 if (recvlen > 0) {
165 DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld", 161 DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
166 recvlen, requestid); 162 recvlen, requestid);
167 163
168 icmsghdrp = (struct icmsg_hdr *)&buf[ 164 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
169 sizeof(struct vmbuspipe_hdr)]; 165 sizeof(struct vmbuspipe_hdr)];
170 166
171 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 167 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
172 prep_negotiate_resp(icmsghdrp, NULL, buf); 168 prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
173 } else { 169 } else {
174 timedatap = (struct ictimesync_data *)&buf[ 170 timedatap = (struct ictimesync_data *)&time_txf_buf[
175 sizeof(struct vmbuspipe_hdr) + 171 sizeof(struct vmbuspipe_hdr) +
176 sizeof(struct icmsg_hdr)]; 172 sizeof(struct icmsg_hdr)];
177 adj_guesttime(timedatap->parenttime, timedatap->flags); 173 adj_guesttime(timedatap->parenttime, timedatap->flags);
@@ -180,12 +176,10 @@ static void timesync_onchannelcallback(void *context)
180 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 176 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
181 | ICMSGHDRFLAG_RESPONSE; 177 | ICMSGHDRFLAG_RESPONSE;
182 178
183 vmbus_sendpacket(channel, buf, 179 vmbus_sendpacket(channel, time_txf_buf,
184 recvlen, requestid, 180 recvlen, requestid,
185 VmbusPacketTypeDataInBand, 0); 181 VmbusPacketTypeDataInBand, 0);
186 } 182 }
187
188 kfree(buf);
189} 183}
190 184
191/* 185/*
@@ -196,30 +190,28 @@ static void timesync_onchannelcallback(void *context)
196static void heartbeat_onchannelcallback(void *context) 190static void heartbeat_onchannelcallback(void *context)
197{ 191{
198 struct vmbus_channel *channel = context; 192 struct vmbus_channel *channel = context;
199 u8 *buf; 193 u32 recvlen;
200 u32 buflen, recvlen;
201 u64 requestid; 194 u64 requestid;
202 struct icmsg_hdr *icmsghdrp; 195 struct icmsg_hdr *icmsghdrp;
203 struct heartbeat_msg_data *heartbeat_msg; 196 struct heartbeat_msg_data *heartbeat_msg;
204 197
205 buflen = PAGE_SIZE; 198 vmbus_recvpacket(channel, hbeat_txf_buf,
206 buf = kmalloc(buflen, GFP_ATOMIC); 199 PAGE_SIZE, &recvlen, &requestid);
207
208 vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
209 200
210 if (recvlen > 0) { 201 if (recvlen > 0) {
211 DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld", 202 DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
212 recvlen, requestid); 203 recvlen, requestid);
213 204
214 icmsghdrp = (struct icmsg_hdr *)&buf[ 205 icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
215 sizeof(struct vmbuspipe_hdr)]; 206 sizeof(struct vmbuspipe_hdr)];
216 207
217 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 208 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
218 prep_negotiate_resp(icmsghdrp, NULL, buf); 209 prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
219 } else { 210 } else {
220 heartbeat_msg = (struct heartbeat_msg_data *)&buf[ 211 heartbeat_msg =
221 sizeof(struct vmbuspipe_hdr) + 212 (struct heartbeat_msg_data *)&hbeat_txf_buf[
222 sizeof(struct icmsg_hdr)]; 213 sizeof(struct vmbuspipe_hdr) +
214 sizeof(struct icmsg_hdr)];
223 215
224 DPRINT_DBG(VMBUS, "heartbeat seq = %lld", 216 DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
225 heartbeat_msg->seq_num); 217 heartbeat_msg->seq_num);
@@ -230,12 +222,10 @@ static void heartbeat_onchannelcallback(void *context)
230 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 222 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
231 | ICMSGHDRFLAG_RESPONSE; 223 | ICMSGHDRFLAG_RESPONSE;
232 224
233 vmbus_sendpacket(channel, buf, 225 vmbus_sendpacket(channel, hbeat_txf_buf,
234 recvlen, requestid, 226 recvlen, requestid,
235 VmbusPacketTypeDataInBand, 0); 227 VmbusPacketTypeDataInBand, 0);
236 } 228 }
237
238 kfree(buf);
239} 229}
240 230
241static const struct pci_device_id __initconst 231static const struct pci_device_id __initconst
@@ -268,6 +258,19 @@ static int __init init_hyperv_utils(void)
268 if (!dmi_check_system(hv_utils_dmi_table)) 258 if (!dmi_check_system(hv_utils_dmi_table))
269 return -ENODEV; 259 return -ENODEV;
270 260
261 shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
262 time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
263 hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
264
265 if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
266 printk(KERN_INFO
267 "Unable to allocate memory for receive buffer\n");
268 kfree(shut_txf_buf);
269 kfree(time_txf_buf);
270 kfree(hbeat_txf_buf);
271 return -ENOMEM;
272 }
273
271 hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback = 274 hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
272 &shutdown_onchannelcallback; 275 &shutdown_onchannelcallback;
273 hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback; 276 hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
@@ -298,6 +301,10 @@ static void exit_hyperv_utils(void)
298 hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = 301 hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
299 &chn_cb_negotiate; 302 &chn_cb_negotiate;
300 hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate; 303 hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
304
305 kfree(shut_txf_buf);
306 kfree(time_txf_buf);
307 kfree(hbeat_txf_buf);
301} 308}
302 309
303module_init(init_hyperv_utils); 310module_init(init_hyperv_utils);