1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
diff --exclude=debian --exclude='.git*' -Naur ubuntu-xen/arch/i386/mm/fault-xen.c ubuntu-xen-tip-3.1/arch/i386/mm/fault-xen.c
--- ubuntu-xen/arch/i386/mm/fault-xen.c 2007-09-24 13:00:02.000000000 -0400
+++ ubuntu-xen-tip-3.1/arch/i386/mm/fault-xen.c 2007-09-24 13:16:48.000000000 -0400
@@ -708,8 +708,11 @@
* problematic: insync can only get set bits added, and updates to
* start are only improving performance (without affecting correctness
* if undone).
+ * XEN: To work on PAE, we need to iterate over PMDs rather than PGDs.
+ * This change works just fine with 2-level paging too.
*/
- static DECLARE_BITMAP(insync, PTRS_PER_PGD);
+#define sync_index(a) ((a) >> PMD_SHIFT)
+ static DECLARE_BITMAP(insync, PTRS_PER_PGD*PTRS_PER_PMD);
static unsigned long start = TASK_SIZE;
unsigned long address;
@@ -717,12 +720,22 @@
return;
BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
- for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
- if (!test_bit(pgd_index(address), insync)) {
+ for (address = start;
+ address >= TASK_SIZE && address < hypervisor_virt_start;
+ address += 1UL << PMD_SHIFT) {
+ if (!test_bit(sync_index(address), insync)) {
unsigned long flags;
struct page *page;
spin_lock_irqsave(&pgd_lock, flags);
+ /*
+ * XEN: vmalloc_sync_one() failure path logic assumes
+ * pgd_list is not empty.
+ */
+ if (unlikely(!pgd_list)) {
+ spin_unlock_irqrestore(&pgd_lock, flags);
+ return;
+ }
for (page = pgd_list; page; page =
(struct page *)page->index)
if (!vmalloc_sync_one(page_address(page),
@@ -732,9 +745,9 @@
}
spin_unlock_irqrestore(&pgd_lock, flags);
if (!page)
- set_bit(pgd_index(address), insync);
+ set_bit(sync_index(address), insync);
}
- if (address == start && test_bit(pgd_index(address), insync))
- start = address + PGDIR_SIZE;
+ if (address == start && test_bit(sync_index(address), insync))
+ start = address + (1UL << PGDIR_SIZE);
}
}
|