Skip to content

Commit acba648

Browse files
committed
Merge tag 'stable/for-linus-3.16-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull Xen fix from David Vrabel: "Fix BUG when trying to expand the grant table. This seems to occur often during boot with Ubuntu 14.04 PV guests" * tag 'stable/for-linus-3.16-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: x86/xen: safely map and unmap grant frames when in atomic context
2 parents d877215 + b7dd0e3 commit acba648

File tree

4 files changed

+105
-58
lines changed

4 files changed

+105
-58
lines changed

arch/arm/xen/grant-table.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,8 @@ int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
5151
{
5252
return -ENOSYS;
5353
}
54+
55+
int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status)
56+
{
57+
return 0;
58+
}

arch/x86/xen/grant-table.c

Lines changed: 91 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -36,99 +36,133 @@
3636

3737
#include <linux/sched.h>
3838
#include <linux/mm.h>
39+
#include <linux/slab.h>
3940
#include <linux/vmalloc.h>
4041

4142
#include <xen/interface/xen.h>
4243
#include <xen/page.h>
4344
#include <xen/grant_table.h>
45+
#include <xen/xen.h>
4446

4547
#include <asm/pgtable.h>
4648

47-
static int map_pte_fn(pte_t *pte, struct page *pmd_page,
48-
unsigned long addr, void *data)
49+
static struct gnttab_vm_area {
50+
struct vm_struct *area;
51+
pte_t **ptes;
52+
} gnttab_shared_vm_area, gnttab_status_vm_area;
53+
54+
int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
55+
unsigned long max_nr_gframes,
56+
void **__shared)
4957
{
50-
unsigned long **frames = (unsigned long **)data;
58+
void *shared = *__shared;
59+
unsigned long addr;
60+
unsigned long i;
5161

52-
set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
53-
(*frames)++;
54-
return 0;
55-
}
62+
if (shared == NULL)
63+
*__shared = shared = gnttab_shared_vm_area.area->addr;
5664

57-
/*
58-
* This function is used to map shared frames to store grant status. It is
59-
* different from map_pte_fn above, the frames type here is uint64_t.
60-
*/
61-
static int map_pte_fn_status(pte_t *pte, struct page *pmd_page,
62-
unsigned long addr, void *data)
63-
{
64-
uint64_t **frames = (uint64_t **)data;
65+
addr = (unsigned long)shared;
66+
67+
for (i = 0; i < nr_gframes; i++) {
68+
set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
69+
mfn_pte(frames[i], PAGE_KERNEL));
70+
addr += PAGE_SIZE;
71+
}
6572

66-
set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
67-
(*frames)++;
6873
return 0;
6974
}
7075

71-
static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
72-
unsigned long addr, void *data)
76+
int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
77+
unsigned long max_nr_gframes,
78+
grant_status_t **__shared)
7379
{
80+
grant_status_t *shared = *__shared;
81+
unsigned long addr;
82+
unsigned long i;
83+
84+
if (shared == NULL)
85+
*__shared = shared = gnttab_status_vm_area.area->addr;
86+
87+
addr = (unsigned long)shared;
88+
89+
for (i = 0; i < nr_gframes; i++) {
90+
set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i],
91+
mfn_pte(frames[i], PAGE_KERNEL));
92+
addr += PAGE_SIZE;
93+
}
7494

75-
set_pte_at(&init_mm, addr, pte, __pte(0));
7695
return 0;
7796
}
7897

79-
int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
80-
unsigned long max_nr_gframes,
81-
void **__shared)
98+
void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
8299
{
83-
int rc;
84-
void *shared = *__shared;
100+
pte_t **ptes;
101+
unsigned long addr;
102+
unsigned long i;
85103

86-
if (shared == NULL) {
87-
struct vm_struct *area =
88-
alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
89-
BUG_ON(area == NULL);
90-
shared = area->addr;
91-
*__shared = shared;
92-
}
104+
if (shared == gnttab_status_vm_area.area->addr)
105+
ptes = gnttab_status_vm_area.ptes;
106+
else
107+
ptes = gnttab_shared_vm_area.ptes;
93108

94-
rc = apply_to_page_range(&init_mm, (unsigned long)shared,
95-
PAGE_SIZE * nr_gframes,
96-
map_pte_fn, &frames);
97-
return rc;
109+
addr = (unsigned long)shared;
110+
111+
for (i = 0; i < nr_gframes; i++) {
112+
set_pte_at(&init_mm, addr, ptes[i], __pte(0));
113+
addr += PAGE_SIZE;
114+
}
98115
}
99116

100-
int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
101-
unsigned long max_nr_gframes,
102-
grant_status_t **__shared)
117+
static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames)
103118
{
104-
int rc;
105-
grant_status_t *shared = *__shared;
119+
area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL);
120+
if (area->ptes == NULL)
121+
return -ENOMEM;
106122

107-
if (shared == NULL) {
108-
/* No need to pass in PTE as we are going to do it
109-
* in apply_to_page_range anyhow. */
110-
struct vm_struct *area =
111-
alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
112-
BUG_ON(area == NULL);
113-
shared = area->addr;
114-
*__shared = shared;
123+
area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes);
124+
if (area->area == NULL) {
125+
kfree(area->ptes);
126+
return -ENOMEM;
115127
}
116128

117-
rc = apply_to_page_range(&init_mm, (unsigned long)shared,
118-
PAGE_SIZE * nr_gframes,
119-
map_pte_fn_status, &frames);
120-
return rc;
129+
return 0;
121130
}
122131

123-
void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
132+
static void arch_gnttab_vfree(struct gnttab_vm_area *area)
133+
{
134+
free_vm_area(area->area);
135+
kfree(area->ptes);
136+
}
137+
138+
int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status)
124139
{
125-
apply_to_page_range(&init_mm, (unsigned long)shared,
126-
PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
140+
int ret;
141+
142+
if (!xen_pv_domain())
143+
return 0;
144+
145+
ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared);
146+
if (ret < 0)
147+
return ret;
148+
149+
/*
150+
* Always allocate the space for the status frames in case
151+
* we're migrated to a host with V2 support.
152+
*/
153+
ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status);
154+
if (ret < 0)
155+
goto err;
156+
157+
return 0;
158+
err:
159+
arch_gnttab_vfree(&gnttab_shared_vm_area);
160+
return -ENOMEM;
127161
}
162+
128163
#ifdef CONFIG_XEN_PVH
129164
#include <xen/balloon.h>
130165
#include <xen/events.h>
131-
#include <xen/xen.h>
132166
#include <linux/slab.h>
133167
static int __init xlated_setup_gnttab_pages(void)
134168
{

drivers/xen/grant-table.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1195,18 +1195,20 @@ static int gnttab_expand(unsigned int req_entries)
11951195
int gnttab_init(void)
11961196
{
11971197
int i;
1198+
unsigned long max_nr_grant_frames;
11981199
unsigned int max_nr_glist_frames, nr_glist_frames;
11991200
unsigned int nr_init_grefs;
12001201
int ret;
12011202

12021203
gnttab_request_version();
1204+
max_nr_grant_frames = gnttab_max_grant_frames();
12031205
nr_grant_frames = 1;
12041206

12051207
/* Determine the maximum number of frames required for the
12061208
* grant reference free list on the current hypervisor.
12071209
*/
12081210
BUG_ON(grefs_per_grant_frame == 0);
1209-
max_nr_glist_frames = (gnttab_max_grant_frames() *
1211+
max_nr_glist_frames = (max_nr_grant_frames *
12101212
grefs_per_grant_frame / RPP);
12111213

12121214
gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
@@ -1223,6 +1225,11 @@ int gnttab_init(void)
12231225
}
12241226
}
12251227

1228+
ret = arch_gnttab_init(max_nr_grant_frames,
1229+
nr_status_frames(max_nr_grant_frames));
1230+
if (ret < 0)
1231+
goto ini_nomem;
1232+
12261233
if (gnttab_setup() < 0) {
12271234
ret = -ENODEV;
12281235
goto ini_nomem;

include/xen/grant_table.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, phys_addr_t addr,
170170
unmap->dev_bus_addr = 0;
171171
}
172172

173+
int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status);
173174
int arch_gnttab_map_shared(xen_pfn_t *frames, unsigned long nr_gframes,
174175
unsigned long max_nr_gframes,
175176
void **__shared);

0 commit comments

Comments
 (0)