diff options
author | Hank Janssen <hjanssen@microsoft.com> | 2010-12-13 19:23:36 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-12-16 15:37:51 -0500 |
commit | 45241e50e3e741ee2a148693888b48e90e806de9 (patch) | |
tree | 86609094a15f5e5c8f8b66c59e600124115c7f7d /drivers/staging | |
parent | 244ba85606b567e6e990d2fac61e3bde5ff8f0ad (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.c | 87 |
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 | ||
41 | static u8 *shut_txf_buf; | ||
42 | static u8 *time_txf_buf; | ||
43 | static u8 *hbeat_txf_buf; | ||
41 | 44 | ||
42 | static void shutdown_onchannelcallback(void *context) | 45 | static 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) | |||
150 | static void timesync_onchannelcallback(void *context) | 149 | static 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) | |||
196 | static void heartbeat_onchannelcallback(void *context) | 190 | static 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 | ||
241 | static const struct pci_device_id __initconst | 231 | static 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 | ||
303 | module_init(init_hyperv_utils); | 310 | module_init(init_hyperv_utils); |