aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2014-07-31 11:22:24 -0400
committerDavid Vrabel <david.vrabel@citrix.com>2014-07-31 12:58:21 -0400
commitc12784c3d14a2110468ec4d1383f60cfd2665576 (patch)
tree9913e9201bc40f463eca4a8e2f908b3831d0c107 /drivers/xen
parenta91c7775e3469821711c1eadf15149b3ba2c82c9 (diff)
xen/events/fifo: reset control block and local HEADs on resume
When using the FIFO-based event channel ABI, if the control block or the local HEADs are not reset after resuming the guest may see stale HEAD values and will fail to traverse the FIFO correctly. This may prevent one or more VCPUs from receiving any events following a resume. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/events/events_fifo.c48
1 files changed, 28 insertions, 20 deletions
diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c
index 84b4bfb84344..c7ff2035b98e 100644
--- a/drivers/xen/events/events_fifo.c
+++ b/drivers/xen/events/events_fifo.c
@@ -100,6 +100,25 @@ static unsigned evtchn_fifo_nr_channels(void)
100 return event_array_pages * EVENT_WORDS_PER_PAGE; 100 return event_array_pages * EVENT_WORDS_PER_PAGE;
101} 101}
102 102
103static int init_control_block(int cpu,
104 struct evtchn_fifo_control_block *control_block)
105{
106 struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
107 struct evtchn_init_control init_control;
108 unsigned int i;
109
110 /* Reset the control block and the local HEADs. */
111 clear_page(control_block);
112 for (i = 0; i < EVTCHN_FIFO_MAX_QUEUES; i++)
113 q->head[i] = 0;
114
115 init_control.control_gfn = virt_to_mfn(control_block);
116 init_control.offset = 0;
117 init_control.vcpu = cpu;
118
119 return HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control);
120}
121
103static void free_unused_array_pages(void) 122static void free_unused_array_pages(void)
104{ 123{
105 unsigned i; 124 unsigned i;
@@ -324,7 +343,6 @@ static void evtchn_fifo_resume(void)
324 343
325 for_each_possible_cpu(cpu) { 344 for_each_possible_cpu(cpu) {
326 void *control_block = per_cpu(cpu_control_block, cpu); 345 void *control_block = per_cpu(cpu_control_block, cpu);
327 struct evtchn_init_control init_control;
328 int ret; 346 int ret;
329 347
330 if (!control_block) 348 if (!control_block)
@@ -341,12 +359,7 @@ static void evtchn_fifo_resume(void)
341 continue; 359 continue;
342 } 360 }
343 361
344 init_control.control_gfn = virt_to_mfn(control_block); 362 ret = init_control_block(cpu, control_block);
345 init_control.offset = 0;
346 init_control.vcpu = cpu;
347
348 ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control,
349 &init_control);
350 if (ret < 0) 363 if (ret < 0)
351 BUG(); 364 BUG();
352 } 365 }
@@ -374,30 +387,25 @@ static const struct evtchn_ops evtchn_ops_fifo = {
374 .resume = evtchn_fifo_resume, 387 .resume = evtchn_fifo_resume,
375}; 388};
376 389
377static int evtchn_fifo_init_control_block(unsigned cpu) 390static int evtchn_fifo_alloc_control_block(unsigned cpu)
378{ 391{
379 struct page *control_block = NULL; 392 void *control_block = NULL;
380 struct evtchn_init_control init_control;
381 int ret = -ENOMEM; 393 int ret = -ENOMEM;
382 394
383 control_block = alloc_page(GFP_KERNEL|__GFP_ZERO); 395 control_block = (void *)__get_free_page(GFP_KERNEL);
384 if (control_block == NULL) 396 if (control_block == NULL)
385 goto error; 397 goto error;
386 398
387 init_control.control_gfn = virt_to_mfn(page_address(control_block)); 399 ret = init_control_block(cpu, control_block);
388 init_control.offset = 0;
389 init_control.vcpu = cpu;
390
391 ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control);
392 if (ret < 0) 400 if (ret < 0)
393 goto error; 401 goto error;
394 402
395 per_cpu(cpu_control_block, cpu) = page_address(control_block); 403 per_cpu(cpu_control_block, cpu) = control_block;
396 404
397 return 0; 405 return 0;
398 406
399 error: 407 error:
400 __free_page(control_block); 408 free_page((unsigned long)control_block);
401 return ret; 409 return ret;
402} 410}
403 411
@@ -411,7 +419,7 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self,
411 switch (action) { 419 switch (action) {
412 case CPU_UP_PREPARE: 420 case CPU_UP_PREPARE:
413 if (!per_cpu(cpu_control_block, cpu)) 421 if (!per_cpu(cpu_control_block, cpu))
414 ret = evtchn_fifo_init_control_block(cpu); 422 ret = evtchn_fifo_alloc_control_block(cpu);
415 break; 423 break;
416 default: 424 default:
417 break; 425 break;
@@ -428,7 +436,7 @@ int __init xen_evtchn_fifo_init(void)
428 int cpu = get_cpu(); 436 int cpu = get_cpu();
429 int ret; 437 int ret;
430 438
431 ret = evtchn_fifo_init_control_block(cpu); 439 ret = evtchn_fifo_alloc_control_block(cpu);
432 if (ret < 0) 440 if (ret < 0)
433 goto out; 441 goto out;
434 442