Skip to content

Commit 3848e4e

Browse files
jgross1bostrovs
authored andcommitted
xen/xenbus: avoid large structs and arrays on the stack
xenbus_map_ring_valloc() and its sub-functions are putting quite large structs and arrays on the stack. This is problematic at runtime, but might also result in build failures (e.g. with clang due to the option -Werror,-Wframe-larger-than=... used). Fix that by moving most of the data from the stack into a dynamically allocated struct. Performance is no issue here, as xenbus_map_ring_valloc() is used only when adding a new PV device to a backend driver. While at it move some duplicated code from pv/hvm specific mapping functions to the single caller. Reported-by: Arnd Bergmann <[email protected]> Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Boris Ostrovsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Boris Ostrovsky <[email protected]>
1 parent caef73c commit 3848e4e

File tree

1 file changed

+83
-78
lines changed

1 file changed

+83
-78
lines changed

drivers/xen/xenbus/xenbus_client.c

Lines changed: 83 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,27 @@ struct xenbus_map_node {
6969
unsigned int nr_handles;
7070
};
7171

72+
struct map_ring_valloc {
73+
struct xenbus_map_node *node;
74+
75+
/* Why do we need two arrays? See comment of __xenbus_map_ring */
76+
union {
77+
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
78+
pte_t *ptes[XENBUS_MAX_RING_GRANTS];
79+
};
80+
phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
81+
82+
struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS];
83+
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
84+
85+
unsigned int idx; /* HVM only. */
86+
};
87+
7288
static DEFINE_SPINLOCK(xenbus_valloc_lock);
7389
static LIST_HEAD(xenbus_valloc_pages);
7490

7591
struct xenbus_ring_ops {
76-
int (*map)(struct xenbus_device *dev,
92+
int (*map)(struct xenbus_device *dev, struct map_ring_valloc *info,
7793
grant_ref_t *gnt_refs, unsigned int nr_grefs,
7894
void **vaddr);
7995
int (*unmap)(struct xenbus_device *dev, void *vaddr);
@@ -449,12 +465,32 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
449465
unsigned int nr_grefs, void **vaddr)
450466
{
451467
int err;
468+
struct map_ring_valloc *info;
469+
470+
*vaddr = NULL;
471+
472+
if (nr_grefs > XENBUS_MAX_RING_GRANTS)
473+
return -EINVAL;
474+
475+
info = kzalloc(sizeof(*info), GFP_KERNEL);
476+
if (!info)
477+
return -ENOMEM;
478+
479+
info->node = kzalloc(sizeof(*info->node), GFP_KERNEL);
480+
if (!info->node) {
481+
err = -ENOMEM;
482+
goto out;
483+
}
484+
485+
err = ring_ops->map(dev, info, gnt_refs, nr_grefs, vaddr);
452486

453-
err = ring_ops->map(dev, gnt_refs, nr_grefs, vaddr);
454487
/* Some hypervisors are buggy and can return 1. */
455488
if (err > 0)
456489
err = GNTST_general_error;
457490

491+
out:
492+
kfree(info->node);
493+
kfree(info);
458494
return err;
459495
}
460496
EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
@@ -466,56 +502,53 @@ static int __xenbus_map_ring(struct xenbus_device *dev,
466502
grant_ref_t *gnt_refs,
467503
unsigned int nr_grefs,
468504
grant_handle_t *handles,
469-
phys_addr_t *addrs,
505+
struct map_ring_valloc *info,
470506
unsigned int flags,
471507
bool *leaked)
472508
{
473-
struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS];
474-
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
475509
int i, j;
476510
int err = GNTST_okay;
477511

478512
if (nr_grefs > XENBUS_MAX_RING_GRANTS)
479513
return -EINVAL;
480514

481515
for (i = 0; i < nr_grefs; i++) {
482-
memset(&map[i], 0, sizeof(map[i]));
483-
gnttab_set_map_op(&map[i], addrs[i], flags, gnt_refs[i],
484-
dev->otherend_id);
516+
gnttab_set_map_op(&info->map[i], info->phys_addrs[i], flags,
517+
gnt_refs[i], dev->otherend_id);
485518
handles[i] = INVALID_GRANT_HANDLE;
486519
}
487520

488-
gnttab_batch_map(map, i);
521+
gnttab_batch_map(info->map, i);
489522

490523
for (i = 0; i < nr_grefs; i++) {
491-
if (map[i].status != GNTST_okay) {
492-
err = map[i].status;
493-
xenbus_dev_fatal(dev, map[i].status,
524+
if (info->map[i].status != GNTST_okay) {
525+
err = info->map[i].status;
526+
xenbus_dev_fatal(dev, info->map[i].status,
494527
"mapping in shared page %d from domain %d",
495528
gnt_refs[i], dev->otherend_id);
496529
goto fail;
497530
} else
498-
handles[i] = map[i].handle;
531+
handles[i] = info->map[i].handle;
499532
}
500533

501534
return GNTST_okay;
502535

503536
fail:
504537
for (i = j = 0; i < nr_grefs; i++) {
505538
if (handles[i] != INVALID_GRANT_HANDLE) {
506-
memset(&unmap[j], 0, sizeof(unmap[j]));
507-
gnttab_set_unmap_op(&unmap[j], (phys_addr_t)addrs[i],
539+
gnttab_set_unmap_op(&info->unmap[j],
540+
info->phys_addrs[i],
508541
GNTMAP_host_map, handles[i]);
509542
j++;
510543
}
511544
}
512545

513-
if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, j))
546+
if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, info->unmap, j))
514547
BUG();
515548

516549
*leaked = false;
517550
for (i = 0; i < j; i++) {
518-
if (unmap[i].status != GNTST_okay) {
551+
if (info->unmap[i].status != GNTST_okay) {
519552
*leaked = true;
520553
break;
521554
}
@@ -566,21 +599,12 @@ static int xenbus_unmap_ring(struct xenbus_device *dev, grant_handle_t *handles,
566599
return err;
567600
}
568601

569-
struct map_ring_valloc_hvm
570-
{
571-
unsigned int idx;
572-
573-
/* Why do we need two arrays? See comment of __xenbus_map_ring */
574-
phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
575-
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
576-
};
577-
578602
static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn,
579603
unsigned int goffset,
580604
unsigned int len,
581605
void *data)
582606
{
583-
struct map_ring_valloc_hvm *info = data;
607+
struct map_ring_valloc *info = data;
584608
unsigned long vaddr = (unsigned long)gfn_to_virt(gfn);
585609

586610
info->phys_addrs[info->idx] = vaddr;
@@ -589,39 +613,28 @@ static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn,
589613
info->idx++;
590614
}
591615

592-
static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
593-
grant_ref_t *gnt_ref,
594-
unsigned int nr_grefs,
595-
void **vaddr)
616+
static int xenbus_map_ring_hvm(struct xenbus_device *dev,
617+
struct map_ring_valloc *info,
618+
grant_ref_t *gnt_ref,
619+
unsigned int nr_grefs,
620+
void **vaddr)
596621
{
597-
struct xenbus_map_node *node;
622+
struct xenbus_map_node *node = info->node;
598623
int err;
599624
void *addr;
600625
bool leaked = false;
601-
struct map_ring_valloc_hvm info = {
602-
.idx = 0,
603-
};
604626
unsigned int nr_pages = XENBUS_PAGES(nr_grefs);
605627

606-
if (nr_grefs > XENBUS_MAX_RING_GRANTS)
607-
return -EINVAL;
608-
609-
*vaddr = NULL;
610-
611-
node = kzalloc(sizeof(*node), GFP_KERNEL);
612-
if (!node)
613-
return -ENOMEM;
614-
615628
err = alloc_xenballooned_pages(nr_pages, node->hvm.pages);
616629
if (err)
617630
goto out_err;
618631

619632
gnttab_foreach_grant(node->hvm.pages, nr_grefs,
620633
xenbus_map_ring_setup_grant_hvm,
621-
&info);
634+
info);
622635

623636
err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles,
624-
info.phys_addrs, GNTMAP_host_map, &leaked);
637+
info, GNTMAP_host_map, &leaked);
625638
node->nr_handles = nr_grefs;
626639

627640
if (err)
@@ -641,19 +654,20 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
641654
spin_unlock(&xenbus_valloc_lock);
642655

643656
*vaddr = addr;
657+
info->node = NULL;
658+
644659
return 0;
645660

646661
out_xenbus_unmap_ring:
647662
if (!leaked)
648-
xenbus_unmap_ring(dev, node->handles, nr_grefs, info.addrs);
663+
xenbus_unmap_ring(dev, node->handles, nr_grefs, info->addrs);
649664
else
650665
pr_alert("leaking %p size %u page(s)",
651666
addr, nr_pages);
652667
out_free_ballooned_pages:
653668
if (!leaked)
654669
free_xenballooned_pages(nr_pages, node->hvm.pages);
655670
out_err:
656-
kfree(node);
657671
return err;
658672
}
659673

@@ -676,40 +690,30 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
676690
EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
677691

678692
#ifdef CONFIG_XEN_PV
679-
static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
680-
grant_ref_t *gnt_refs,
681-
unsigned int nr_grefs,
682-
void **vaddr)
693+
static int xenbus_map_ring_pv(struct xenbus_device *dev,
694+
struct map_ring_valloc *info,
695+
grant_ref_t *gnt_refs,
696+
unsigned int nr_grefs,
697+
void **vaddr)
683698
{
684-
struct xenbus_map_node *node;
699+
struct xenbus_map_node *node = info->node;
685700
struct vm_struct *area;
686-
pte_t *ptes[XENBUS_MAX_RING_GRANTS];
687-
phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
688701
int err = GNTST_okay;
689702
int i;
690703
bool leaked;
691704

692-
*vaddr = NULL;
693-
694-
if (nr_grefs > XENBUS_MAX_RING_GRANTS)
695-
return -EINVAL;
696-
697-
node = kzalloc(sizeof(*node), GFP_KERNEL);
698-
if (!node)
699-
return -ENOMEM;
700-
701-
area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes);
705+
area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, info->ptes);
702706
if (!area) {
703707
kfree(node);
704708
return -ENOMEM;
705709
}
706710

707711
for (i = 0; i < nr_grefs; i++)
708-
phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr;
712+
info->phys_addrs[i] =
713+
arbitrary_virt_to_machine(info->ptes[i]).maddr;
709714

710715
err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles,
711-
phys_addrs,
712-
GNTMAP_host_map | GNTMAP_contains_pte,
716+
info, GNTMAP_host_map | GNTMAP_contains_pte,
713717
&leaked);
714718
if (err)
715719
goto failed;
@@ -722,6 +726,8 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
722726
spin_unlock(&xenbus_valloc_lock);
723727

724728
*vaddr = area->addr;
729+
info->node = NULL;
730+
725731
return 0;
726732

727733
failed:
@@ -730,11 +736,10 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
730736
else
731737
pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs);
732738

733-
kfree(node);
734739
return err;
735740
}
736741

737-
static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
742+
static int xenbus_unmap_ring_pv(struct xenbus_device *dev, void *vaddr)
738743
{
739744
struct xenbus_map_node *node;
740745
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
@@ -798,12 +803,12 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
798803
}
799804

800805
static const struct xenbus_ring_ops ring_ops_pv = {
801-
.map = xenbus_map_ring_valloc_pv,
802-
.unmap = xenbus_unmap_ring_vfree_pv,
806+
.map = xenbus_map_ring_pv,
807+
.unmap = xenbus_unmap_ring_pv,
803808
};
804809
#endif
805810

806-
struct unmap_ring_vfree_hvm
811+
struct unmap_ring_hvm
807812
{
808813
unsigned int idx;
809814
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
@@ -814,19 +819,19 @@ static void xenbus_unmap_ring_setup_grant_hvm(unsigned long gfn,
814819
unsigned int len,
815820
void *data)
816821
{
817-
struct unmap_ring_vfree_hvm *info = data;
822+
struct unmap_ring_hvm *info = data;
818823

819824
info->addrs[info->idx] = (unsigned long)gfn_to_virt(gfn);
820825

821826
info->idx++;
822827
}
823828

824-
static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
829+
static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
825830
{
826831
int rv;
827832
struct xenbus_map_node *node;
828833
void *addr;
829-
struct unmap_ring_vfree_hvm info = {
834+
struct unmap_ring_hvm info = {
830835
.idx = 0,
831836
};
832837
unsigned int nr_pages;
@@ -887,8 +892,8 @@ enum xenbus_state xenbus_read_driver_state(const char *path)
887892
EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
888893

889894
static const struct xenbus_ring_ops ring_ops_hvm = {
890-
.map = xenbus_map_ring_valloc_hvm,
891-
.unmap = xenbus_unmap_ring_vfree_hvm,
895+
.map = xenbus_map_ring_hvm,
896+
.unmap = xenbus_unmap_ring_hvm,
892897
};
893898

894899
void __init xenbus_ring_ops_init(void)

0 commit comments

Comments
 (0)