Skip to content

Commit 2608fb6

Browse files
jasowanggregkh
authored andcommitted
drivers: hv: allocate synic structures before hv_synic_init()
We currently allocate synic structures in hv_sync_init(), but there's no way for the driver to know about the allocation failure and it may continue to use the uninitialized pointers. Solve this by introducing helpers for allocating and freeing and doing the allocation before the on_each_cpu() call in vmbus_bus_init(). Cc: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent e91e84f commit 2608fb6

File tree

3 files changed

+63
-34
lines changed

3 files changed

+63
-34
lines changed

drivers/hv/hv.c

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,59 @@ u16 hv_signal_event(void *con_id)
265265
return status;
266266
}
267267

268+
269+
int hv_synic_alloc(void)
270+
{
271+
size_t size = sizeof(struct tasklet_struct);
272+
int cpu;
273+
274+
for_each_online_cpu(cpu) {
275+
hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
276+
if (hv_context.event_dpc[cpu] == NULL) {
277+
pr_err("Unable to allocate event dpc\n");
278+
goto err;
279+
}
280+
tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
281+
282+
hv_context.synic_message_page[cpu] =
283+
(void *)get_zeroed_page(GFP_ATOMIC);
284+
285+
if (hv_context.synic_message_page[cpu] == NULL) {
286+
pr_err("Unable to allocate SYNIC message page\n");
287+
goto err;
288+
}
289+
290+
hv_context.synic_event_page[cpu] =
291+
(void *)get_zeroed_page(GFP_ATOMIC);
292+
293+
if (hv_context.synic_event_page[cpu] == NULL) {
294+
pr_err("Unable to allocate SYNIC event page\n");
295+
goto err;
296+
}
297+
}
298+
299+
return 0;
300+
err:
301+
return -ENOMEM;
302+
}
303+
304+
void hv_synic_free_cpu(int cpu)
305+
{
306+
kfree(hv_context.event_dpc[cpu]);
307+
if (hv_context.synic_message_page[cpu])
308+
free_page((unsigned long)hv_context.synic_event_page[cpu]);
309+
if (hv_context.synic_message_page[cpu])
310+
free_page((unsigned long)hv_context.synic_message_page[cpu]);
311+
}
312+
313+
void hv_synic_free(void)
314+
{
315+
int cpu;
316+
317+
for_each_online_cpu(cpu)
318+
hv_synic_free_cpu(cpu);
319+
}
320+
268321
/*
269322
* hv_synic_init - Initialize the Synthethic Interrupt Controller.
270323
*
@@ -289,30 +342,6 @@ void hv_synic_init(void *arg)
289342
/* Check the version */
290343
rdmsrl(HV_X64_MSR_SVERSION, version);
291344

292-
hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
293-
GFP_ATOMIC);
294-
if (hv_context.event_dpc[cpu] == NULL) {
295-
pr_err("Unable to allocate event dpc\n");
296-
goto cleanup;
297-
}
298-
tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
299-
300-
hv_context.synic_message_page[cpu] =
301-
(void *)get_zeroed_page(GFP_ATOMIC);
302-
303-
if (hv_context.synic_message_page[cpu] == NULL) {
304-
pr_err("Unable to allocate SYNIC message page\n");
305-
goto cleanup;
306-
}
307-
308-
hv_context.synic_event_page[cpu] =
309-
(void *)get_zeroed_page(GFP_ATOMIC);
310-
311-
if (hv_context.synic_event_page[cpu] == NULL) {
312-
pr_err("Unable to allocate SYNIC event page\n");
313-
goto cleanup;
314-
}
315-
316345
/* Setup the Synic's message page */
317346
rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
318347
simp.simp_enabled = 1;
@@ -355,14 +384,6 @@ void hv_synic_init(void *arg)
355384
rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
356385
hv_context.vp_index[cpu] = (u32)vp_index;
357386
return;
358-
359-
cleanup:
360-
if (hv_context.synic_event_page[cpu])
361-
free_page((unsigned long)hv_context.synic_event_page[cpu]);
362-
363-
if (hv_context.synic_message_page[cpu])
364-
free_page((unsigned long)hv_context.synic_message_page[cpu]);
365-
return;
366387
}
367388

368389
/*

drivers/hv/hyperv_vmbus.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,10 @@ extern int hv_post_message(union hv_connection_id connection_id,
527527

528528
extern u16 hv_signal_event(void *con_id);
529529

530+
extern int hv_synic_alloc(void);
531+
532+
extern void hv_synic_free(void);
533+
530534
extern void hv_synic_init(void *irqarg);
531535

532536
extern void hv_synic_cleanup(void *arg);

drivers/hv/vmbus_drv.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,20 +563,24 @@ static int vmbus_bus_init(int irq)
563563
*/
564564
hv_register_vmbus_handler(irq, vmbus_isr);
565565

566+
ret = hv_synic_alloc();
567+
if (ret)
568+
goto err_alloc;
566569
/*
567570
* Initialize the per-cpu interrupt state and
568571
* connect to the host.
569572
*/
570573
on_each_cpu(hv_synic_init, NULL, 1);
571574
ret = vmbus_connect();
572575
if (ret)
573-
goto err_irq;
576+
goto err_alloc;
574577

575578
vmbus_request_offers();
576579

577580
return 0;
578581

579-
err_irq:
582+
err_alloc:
583+
hv_synic_free();
580584
free_irq(irq, hv_acpi_dev);
581585

582586
err_unregister:

0 commit comments

Comments
 (0)