summaryrefslogtreecommitdiff
blob: 913b79c265861b1f1c44891dabdb7fdea0abb280 (plain)
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);
 	}
 }