channel_mgmt.c 18.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Copyright (c) 2009, Microsoft Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Authors:
 *   Haiyang Zhang <haiyangz@microsoft.com>
 *   Hank Janssen  <hjanssen@microsoft.com>
 */
21
22
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

23
#include <linux/kernel.h>
24
25
#include <linux/sched.h>
#include <linux/wait.h>
26
#include <linux/mm.h>
27
#include <linux/slab.h>
28
#include <linux/list.h>
29
#include <linux/module.h>
30
#include <linux/completion.h>
31
#include <linux/hyperv.h>
32

33
#include "hyperv_vmbus.h"
34

35
struct vmbus_channel_message_table_entry {
36
	enum vmbus_channel_message_type message_type;
37
	void (*message_handler)(struct vmbus_channel_message_header *msg);
38
};
39

40
41

/**
42
 * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
43
44
45
46
47
48
 * @icmsghdrp: Pointer to msg header structure
 * @icmsg_negotiate: Pointer to negotiate message structure
 * @buf: Raw buffer channel data
 *
 * @icmsghdrp is of type &struct icmsg_hdr.
 * @negop is of type &struct icmsg_negotiate.
49
50
51
52
53
54
55
 * Set up and fill in default negotiate response message.
 *
 * The max_fw_version specifies the maximum framework version that
 * we can support and max _srv_version specifies the maximum service
 * version we can support. A special value MAX_SRV_VER can be
 * specified to indicate that we can handle the maximum version
 * exposed by the host.
56
57
58
 *
 * Mainly used by Hyper-V drivers.
 */
59
void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
60
61
				struct icmsg_negotiate *negop, u8 *buf,
				int max_fw_version, int max_srv_version)
62
{
63
64
65
66
	int icframe_vercnt;
	int icmsg_vercnt;
	int i;

67
	icmsghdrp->icmsgsize = 0x10;
68

69
70
71
	negop = (struct icmsg_negotiate *)&buf[
		sizeof(struct vmbuspipe_hdr) +
		sizeof(struct icmsg_hdr)];
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
	icframe_vercnt = negop->icframe_vercnt;
	icmsg_vercnt = negop->icmsg_vercnt;

	/*
	 * Select the framework version number we will
	 * support.
	 */

	for (i = 0; i < negop->icframe_vercnt; i++) {
		if (negop->icversion_data[i].major <= max_fw_version)
			icframe_vercnt = negop->icversion_data[i].major;
	}

	for (i = negop->icframe_vercnt;
		 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
		if (negop->icversion_data[i].major <= max_srv_version)
			icmsg_vercnt = negop->icversion_data[i].major;
90
	}
91

92
93
94
95
	/*
	 * Respond with the maximum framework and service
	 * version numbers we can support.
	 */
96
97
	negop->icframe_vercnt = 1;
	negop->icmsg_vercnt = 1;
98
99
100
101
	negop->icversion_data[0].major = icframe_vercnt;
	negop->icversion_data[0].minor = 0;
	negop->icversion_data[1].major = icmsg_vercnt;
	negop->icversion_data[1].minor = 0;
102
}
103

104
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
105

106
/*
107
 * alloc_channel - Allocate and initialize a vmbus channel object
108
 */
109
static struct vmbus_channel *alloc_channel(void)
110
{
111
	struct vmbus_channel *channel;
112

113
	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
114
115
116
	if (!channel)
		return NULL;

117
	spin_lock_init(&channel->inbound_lock);
118

119
120
	channel->controlwq = create_workqueue("hv_vmbus_ctl");
	if (!channel->controlwq) {
121
		kfree(channel);
122
123
124
125
126
127
		return NULL;
	}

	return channel;
}

128
/*
129
 * release_hannel - Release the vmbus channel object itself
130
 */
131
static void release_channel(struct work_struct *work)
132
{
133
134
135
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);
136

137
	destroy_workqueue(channel->controlwq);
138

139
	kfree(channel);
140
141
}

142
/*
143
 * free_channel - Release the resources used by the vmbus channel object
144
 */
145
static void free_channel(struct vmbus_channel *channel)
146
147
{

148
149
150
151
152
	/*
	 * We have to release the channel's workqueue/thread in the vmbus's
	 * workqueue/thread context
	 * ie we can't destroy ourselves.
	 */
153
	INIT_WORK(&channel->work, release_channel);
154
	queue_work(vmbus_connection.work_queue, &channel->work);
155
156
}

157
158


159
160
161
162
163
164
165
166
167
168
/*
 * vmbus_process_rescind_offer -
 * Rescind the offer by initiating a device removal
 */
static void vmbus_process_rescind_offer(struct work_struct *work)
{
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);

169
	vmbus_device_unregister(channel->device_obj);
170
}
171

172
173
174
175
176
177
178
179
180
181
182
void vmbus_free_channels(void)
{
	struct vmbus_channel *channel;

	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
		vmbus_device_unregister(channel->device_obj);
		kfree(channel->device_obj);
		free_channel(channel);
	}
}

183
/*
184
 * vmbus_process_offer - Process the offer by creating a channel/device
185
 * associated with this offer
186
 */
187
static void vmbus_process_offer(struct work_struct *work)
188
{
189
190
191
	struct vmbus_channel *newchannel = container_of(work,
							struct vmbus_channel,
							work);
192
	struct vmbus_channel *channel;
193
	bool fnew = true;
194
	int ret;
195
	unsigned long flags;
196

197
198
199
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

200
	/* Make sure this is a new offer */
201
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
202

203
	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
204
205
206
207
		if (!uuid_le_cmp(channel->offermsg.offer.if_type,
			newchannel->offermsg.offer.if_type) &&
			!uuid_le_cmp(channel->offermsg.offer.if_instance,
				newchannel->offermsg.offer.if_instance)) {
208
			fnew = false;
209
210
211
212
			break;
		}
	}

213
	if (fnew)
214
		list_add_tail(&newchannel->listentry,
215
			      &vmbus_connection.chn_list);
216

217
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
218

219
	if (!fnew) {
220
		free_channel(newchannel);
221
222
223
		return;
	}

224
225
226
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
227
	 * vmbus_child_dev_add()
228
	 */
229
	newchannel->device_obj = vmbus_device_create(
230
231
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
232
		newchannel);
233

234
235
236
237
238
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
239
	ret = vmbus_device_register(newchannel->device_obj);
240
	if (ret != 0) {
241
		pr_err("unable to add child device object (relid %d)\n",
242
			   newchannel->offermsg.child_relid);
243

244
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
245
		list_del(&newchannel->listentry);
246
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
247
		kfree(newchannel->device_obj);
248

249
		free_channel(newchannel);
250
	} else {
251
252
253
254
255
		/*
		 * This state is used to indicate a successful open
		 * so that when we do close the channel normally, we
		 * can cleanup properly
		 */
256
		newchannel->state = CHANNEL_OPEN_STATE;
257
258
259
	}
}

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
enum {
	IDE = 0,
	SCSI,
	NIC,
	MAX_PERF_CHN,
};

/*
 * This is an array of channels (devices) that are performance critical.
 * We attempt to distribute the interrupt load for these devices across
 * all available CPUs.
 */
static const uuid_le hp_devs[] = {
	/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
	/* IDE */
	{
		.b = {
			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
		}
	},
	/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
	/* Storage - SCSI */
	{
		.b  = {
			0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
			0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
		}
	},
	/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
	/* Network */
	{
		.b = {
			0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
			0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
		}
	},

};


/*
 * We use this state to statically distribute the channel interrupt load.
 */
static u32  next_vp;

/*
 * Starting with Win8, we can statically distribute the incoming
 * channel interrupt load by binding a channel to VCPU. We
 * implement here a simple round robin scheme for distributing
 * the interrupt load.
 * We will bind channels that are not performance critical to cpu 0 and
 * performance critical channels (IDE, SCSI and Network) will be uniformly
 * distributed across all available CPUs.
 */
static u32 get_vp_index(uuid_le *type_guid)
{
	u32 cur_cpu;
	int i;
	bool perf_chn = false;
	u32 max_cpus = num_online_cpus();

	for (i = IDE; i < MAX_PERF_CHN; i++) {
		if (!memcmp(type_guid->b, hp_devs[i].b,
				 sizeof(uuid_le))) {
			perf_chn = true;
			break;
		}
	}
	if ((vmbus_proto_version == VERSION_WS2008) ||
	    (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
		/*
		 * Prior to win8, all channel interrupts are
		 * delivered on cpu 0.
		 * Also if the channel is not a performance critical
		 * channel, bind it to cpu 0.
		 */
		return 0;
	}
	cur_cpu = (++next_vp % max_cpus);
	return hv_context.vp_index[cur_cpu];
}

343
/*
344
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
345
346
 *
 */
347
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
348
{
349
	struct vmbus_channel_offer_channel *offer;
350
	struct vmbus_channel *newchannel;
351

352
	offer = (struct vmbus_channel_offer_channel *)hdr;
353

354
	/* Allocate the channel object and save this offer. */
355
	newchannel = alloc_channel();
356
	if (!newchannel) {
357
		pr_err("Unable to allocate channel object\n");
358
359
360
		return;
	}

361
362
363
364
365
366
367
	/*
	 * By default we setup state to enable batched
	 * reading. A specific service can choose to
	 * disable this prior to opening the channel.
	 */
	newchannel->batched_reading = true;

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
	/*
	 * Setup state for signalling the host.
	 */
	newchannel->sig_event = (struct hv_input_signal_event *)
				(ALIGN((unsigned long)
				&newchannel->sig_buf,
				HV_HYPERCALL_PARAM_ALIGN));

	newchannel->sig_event->connectionid.asu32 = 0;
	newchannel->sig_event->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID;
	newchannel->sig_event->flag_number = 0;
	newchannel->sig_event->rsvdz = 0;

	if (vmbus_proto_version != VERSION_WS2008) {
		newchannel->is_dedicated_interrupt =
				(offer->is_dedicated_interrupt != 0);
		newchannel->sig_event->connectionid.u.id =
				offer->connection_id;
	}

388
	newchannel->target_vp = get_vp_index(&offer->offer.if_type);
389

390
	memcpy(&newchannel->offermsg, offer,
391
	       sizeof(struct vmbus_channel_offer_channel));
392
393
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
394

395
396
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
397
398
}

399
/*
400
 * vmbus_onoffer_rescind - Rescind offer handler.
401
402
403
 *
 * We queue a work item to process this offer synchronously
 */
404
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
405
{
406
	struct vmbus_channel_rescind_offer *rescind;
407
	struct vmbus_channel *channel;
408

409
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
410
	channel = relid2channel(rescind->child_relid);
411
412
413

	if (channel == NULL)
		/* Just return here, no channel found */
414
415
		return;

416
417
418
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
419
420
}

421
/*
422
423
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
424
425
426
 *
 * Nothing to do here.
 */
427
static void vmbus_onoffers_delivered(
428
			struct vmbus_channel_message_header *hdr)
429
430
431
{
}

432
/*
433
 * vmbus_onopen_result - Open result handler.
434
435
436
437
438
 *
 * This is invoked when we received a response to our channel open request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
439
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
440
{
441
	struct vmbus_channel_open_result *result;
442
443
444
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
445
	unsigned long flags;
446

447
	result = (struct vmbus_channel_open_result *)hdr;
448

449
450
451
	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
452
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
453

454
455
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
456
		requestheader =
457
			(struct vmbus_channel_message_header *)msginfo->msg;
458

459
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
460
			openmsg =
461
462
463
464
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
465
				       result,
466
467
468
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
469
470
471
472
				break;
			}
		}
	}
473
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
474
475
}

476
/*
477
 * vmbus_ongpadl_created - GPADL created handler.
478
479
480
481
482
 *
 * This is invoked when we received a response to our gpadl create request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
483
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
484
{
485
486
487
488
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
489
	unsigned long flags;
490

491
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
492

493
494
495
496
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
497
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
498

499
500
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
501
		requestheader =
502
			(struct vmbus_channel_message_header *)msginfo->msg;
503

504
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
505
506
507
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

508
509
510
511
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
512
				       gpadlcreated,
513
514
515
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
516
517
518
519
				break;
			}
		}
	}
520
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
521
522
}

523
/*
524
 * vmbus_ongpadl_torndown - GPADL torndown handler.
525
526
527
528
529
 *
 * This is invoked when we received a response to our gpadl teardown request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
530
static void vmbus_ongpadl_torndown(
531
			struct vmbus_channel_message_header *hdr)
532
{
533
534
535
536
	struct vmbus_channel_gpadl_torndown *gpadl_torndown;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_teardown *gpadl_teardown;
537
	unsigned long flags;
538

539
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
540
541
542
543

	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
544
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
545

546
547
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
548
		requestheader =
549
			(struct vmbus_channel_message_header *)msginfo->msg;
550

551
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
552
553
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
554

555
556
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
557
				       gpadl_torndown,
558
559
560
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
561
562
563
564
				break;
			}
		}
	}
565
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
566
567
}

568
/*
569
 * vmbus_onversion_response - Version response handler
570
571
572
573
574
 *
 * This is invoked when we received a response to our initiate contact request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
575
static void vmbus_onversion_response(
576
		struct vmbus_channel_message_header *hdr)
577
{
578
579
580
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_version_response *version_response;
581
	unsigned long flags;
582

583
	version_response = (struct vmbus_channel_version_response *)hdr;
584
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
585

586
587
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
588
		requestheader =
589
			(struct vmbus_channel_message_header *)msginfo->msg;
590

591
592
593
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
			memcpy(&msginfo->response.version_response,
594
			      version_response,
595
			      sizeof(struct vmbus_channel_version_response));
596
			complete(&msginfo->waitevent);
597
598
		}
	}
599
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
600
601
}

602
603
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
604
	channel_message_table[CHANNELMSG_COUNT] = {
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
	{CHANNELMSG_INVALID,			NULL},
	{CHANNELMSG_OFFERCHANNEL,		vmbus_onoffer},
	{CHANNELMSG_RESCIND_CHANNELOFFER,	vmbus_onoffer_rescind},
	{CHANNELMSG_REQUESTOFFERS,		NULL},
	{CHANNELMSG_ALLOFFERS_DELIVERED,	vmbus_onoffers_delivered},
	{CHANNELMSG_OPENCHANNEL,		NULL},
	{CHANNELMSG_OPENCHANNEL_RESULT,	vmbus_onopen_result},
	{CHANNELMSG_CLOSECHANNEL,		NULL},
	{CHANNELMSG_GPADL_HEADER,		NULL},
	{CHANNELMSG_GPADL_BODY,		NULL},
	{CHANNELMSG_GPADL_CREATED,		vmbus_ongpadl_created},
	{CHANNELMSG_GPADL_TEARDOWN,		NULL},
	{CHANNELMSG_GPADL_TORNDOWN,		vmbus_ongpadl_torndown},
	{CHANNELMSG_RELID_RELEASED,		NULL},
	{CHANNELMSG_INITIATE_CONTACT,		NULL},
	{CHANNELMSG_VERSION_RESPONSE,		vmbus_onversion_response},
	{CHANNELMSG_UNLOAD,			NULL},
622
623
};

624
/*
625
 * vmbus_onmessage - Handler for channel protocol messages.
626
627
628
 *
 * This is invoked in the vmbus worker thread context.
 */
629
void vmbus_onmessage(void *context)
630
{
631
	struct hv_message *msg = context;
632
	struct vmbus_channel_message_header *hdr;
633
634
	int size;

635
636
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
637

638
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
639
		pr_err("Received invalid channel message type %d size %d\n",
640
			   hdr->msgtype, size);
641
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
642
				     (unsigned char *)msg->u.payload, size);
643
644
645
		return;
	}

646
647
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
648
	else
649
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
650
651
}

652
/*
653
 * vmbus_request_offers - Send a request to get all our pending offers.
654
 */
655
int vmbus_request_offers(void)
656
{
657
	struct vmbus_channel_message_header *msg;
658
	struct vmbus_channel_msginfo *msginfo;
659
	int ret, t;
660

661
	msginfo = kmalloc(sizeof(*msginfo) +
662
663
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
664
	if (!msginfo)
665
		return -ENOMEM;
666

667
	init_completion(&msginfo->waitevent);
668

669
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
670

671
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
672
673


674
	ret = vmbus_post_msg(msg,
675
676
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
677
		pr_err("Unable to request offers - %d\n", ret);
678

679
680
		goto cleanup;
	}
681

682
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
683
	if (t == 0) {
684
685
		ret = -ETIMEDOUT;
		goto cleanup;
686
687
688
689
	}



690
cleanup:
691
	kfree(msginfo);
692
693
694
695

	return ret;
}

696
/* eof */