]>
Commit | Line | Data |
---|---|---|
bf9ffb20 GKH |
1 | From c12784c3d14a2110468ec4d1383f60cfd2665576 Mon Sep 17 00:00:00 2001 |
2 | From: David Vrabel <david.vrabel@citrix.com> | |
3 | Date: Thu, 31 Jul 2014 16:22:24 +0100 | |
4 | Subject: xen/events/fifo: reset control block and local HEADs on resume | |
5 | ||
6 | From: David Vrabel <david.vrabel@citrix.com> | |
7 | ||
8 | commit c12784c3d14a2110468ec4d1383f60cfd2665576 upstream. | |
9 | ||
10 | When using the FIFO-based event channel ABI, if the control block or | |
11 | the local HEADs are not reset after resuming the guest may see stale | |
12 | HEAD values and will fail to traverse the FIFO correctly. | |
13 | ||
14 | This may prevent one or more VCPUs from receiving any events following | |
15 | a resume. | |
16 | ||
17 | Signed-off-by: David Vrabel <david.vrabel@citrix.com> | |
18 | Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
20 | ||
21 | --- | |
22 | drivers/xen/events/events_fifo.c | 48 ++++++++++++++++++++++----------------- | |
23 | 1 file changed, 28 insertions(+), 20 deletions(-) | |
24 | ||
25 | --- a/drivers/xen/events/events_fifo.c | |
26 | +++ b/drivers/xen/events/events_fifo.c | |
27 | @@ -99,6 +99,25 @@ static unsigned evtchn_fifo_nr_channels( | |
28 | return event_array_pages * EVENT_WORDS_PER_PAGE; | |
29 | } | |
30 | ||
31 | +static int init_control_block(int cpu, | |
32 | + struct evtchn_fifo_control_block *control_block) | |
33 | +{ | |
34 | + struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); | |
35 | + struct evtchn_init_control init_control; | |
36 | + unsigned int i; | |
37 | + | |
38 | + /* Reset the control block and the local HEADs. */ | |
39 | + clear_page(control_block); | |
40 | + for (i = 0; i < EVTCHN_FIFO_MAX_QUEUES; i++) | |
41 | + q->head[i] = 0; | |
42 | + | |
43 | + init_control.control_gfn = virt_to_mfn(control_block); | |
44 | + init_control.offset = 0; | |
45 | + init_control.vcpu = cpu; | |
46 | + | |
47 | + return HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control); | |
48 | +} | |
49 | + | |
50 | static void free_unused_array_pages(void) | |
51 | { | |
52 | unsigned i; | |
53 | @@ -323,7 +342,6 @@ static void evtchn_fifo_resume(void) | |
54 | ||
55 | for_each_possible_cpu(cpu) { | |
56 | void *control_block = per_cpu(cpu_control_block, cpu); | |
57 | - struct evtchn_init_control init_control; | |
58 | int ret; | |
59 | ||
60 | if (!control_block) | |
61 | @@ -340,12 +358,7 @@ static void evtchn_fifo_resume(void) | |
62 | continue; | |
63 | } | |
64 | ||
65 | - init_control.control_gfn = virt_to_mfn(control_block); | |
66 | - init_control.offset = 0; | |
67 | - init_control.vcpu = cpu; | |
68 | - | |
69 | - ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control, | |
70 | - &init_control); | |
71 | + ret = init_control_block(cpu, control_block); | |
72 | if (ret < 0) | |
73 | BUG(); | |
74 | } | |
75 | @@ -373,30 +386,25 @@ static const struct evtchn_ops evtchn_op | |
76 | .resume = evtchn_fifo_resume, | |
77 | }; | |
78 | ||
79 | -static int evtchn_fifo_init_control_block(unsigned cpu) | |
80 | +static int evtchn_fifo_alloc_control_block(unsigned cpu) | |
81 | { | |
82 | - struct page *control_block = NULL; | |
83 | - struct evtchn_init_control init_control; | |
84 | + void *control_block = NULL; | |
85 | int ret = -ENOMEM; | |
86 | ||
87 | - control_block = alloc_page(GFP_KERNEL|__GFP_ZERO); | |
88 | + control_block = (void *)__get_free_page(GFP_KERNEL); | |
89 | if (control_block == NULL) | |
90 | goto error; | |
91 | ||
92 | - init_control.control_gfn = virt_to_mfn(page_address(control_block)); | |
93 | - init_control.offset = 0; | |
94 | - init_control.vcpu = cpu; | |
95 | - | |
96 | - ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control); | |
97 | + ret = init_control_block(cpu, control_block); | |
98 | if (ret < 0) | |
99 | goto error; | |
100 | ||
101 | - per_cpu(cpu_control_block, cpu) = page_address(control_block); | |
102 | + per_cpu(cpu_control_block, cpu) = control_block; | |
103 | ||
104 | return 0; | |
105 | ||
106 | error: | |
107 | - __free_page(control_block); | |
108 | + free_page((unsigned long)control_block); | |
109 | return ret; | |
110 | } | |
111 | ||
112 | @@ -410,7 +418,7 @@ static int evtchn_fifo_cpu_notification( | |
113 | switch (action) { | |
114 | case CPU_UP_PREPARE: | |
115 | if (!per_cpu(cpu_control_block, cpu)) | |
116 | - ret = evtchn_fifo_init_control_block(cpu); | |
117 | + ret = evtchn_fifo_alloc_control_block(cpu); | |
118 | break; | |
119 | default: | |
120 | break; | |
121 | @@ -427,7 +435,7 @@ int __init xen_evtchn_fifo_init(void) | |
122 | int cpu = get_cpu(); | |
123 | int ret; | |
124 | ||
125 | - ret = evtchn_fifo_init_control_block(cpu); | |
126 | + ret = evtchn_fifo_alloc_control_block(cpu); | |
127 | if (ret < 0) | |
128 | goto out; | |
129 |