Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lguest: cache last cpu we ran on.

This optimizes the frobbing of our Switcher map.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

+55 -26
+1
drivers/lguest/lg.h
··· 17 17 struct pgdir { 18 18 unsigned long gpgdir; 19 19 bool switcher_mapped; 20 + int last_host_cpu; 20 21 pgd_t *pgdir; 21 22 }; 22 23
+54 -26
drivers/lguest/page_tables.c
··· 7 7 * converted Guest pages when running the Guest. 8 8 :*/ 9 9 10 - /* Copyright (C) Rusty Russell IBM Corporation 2006. 10 + /* Copyright (C) Rusty Russell IBM Corporation 2013. 11 11 * GPL v2 and any later version */ 12 12 #include <linux/mm.h> 13 13 #include <linux/gfp.h> ··· 731 731 /* Release all the non-kernel mappings. */ 732 732 flush_user_mappings(cpu->lg, next); 733 733 734 + /* This hasn't run on any CPU at all. */ 735 + cpu->lg->pgdirs[next].last_host_cpu = -1; 736 + 734 737 return next; 735 738 } 736 739 ··· 793 790 for (j = 0; j < PTRS_PER_PGD; j++) 794 791 release_pgd(lg->pgdirs[i].pgdir + j); 795 792 lg->pgdirs[i].switcher_mapped = false; 793 + lg->pgdirs[i].last_host_cpu = -1; 796 794 } 797 795 } 798 796 ··· 1090 1086 free_page((long)lg->pgdirs[i].pgdir); 1091 1087 } 1092 1088 1089 + /*H:481 1090 + * This clears the Switcher mappings for cpu #i. 1091 + */ 1092 + static void remove_switcher_percpu_map(struct lg_cpu *cpu, unsigned int i) 1093 + { 1094 + unsigned long base = switcher_addr + PAGE_SIZE + i * PAGE_SIZE*2; 1095 + pte_t *pte; 1096 + 1097 + /* Clear the mappings for both pages. */ 1098 + pte = find_spte(cpu, base, false, 0, 0); 1099 + release_pte(*pte); 1100 + set_pte(pte, __pte(0)); 1101 + 1102 + pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0); 1103 + release_pte(*pte); 1104 + set_pte(pte, __pte(0)); 1105 + } 1106 + 1093 1107 /*H:480 1094 1108 * (vi) Mapping the Switcher when the Guest is about to run. 1095 1109 * 1096 - * The Switcher and the two pages for this CPU need to be visible in the 1097 - * Guest (and not the pages for other CPUs). 1110 + * The Switcher and the two pages for this CPU need to be visible in the Guest 1111 + * (and not the pages for other CPUs). 1098 1112 * 1099 - * The pages have all been allocate 1113 + * The pages for the pagetables have all been allocated before: we just need 1114 + * to make sure the actual PTEs are up-to-date for the CPU we're about to run 1115 + * on. 1100 1116 */ 1101 1117 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) 1102 1118 { 1103 - unsigned long base, i; 1119 + unsigned long base; 1104 1120 struct page *percpu_switcher_page, *regs_page; 1105 1121 pte_t *pte; 1122 + struct pgdir *pgdir = &cpu->lg->pgdirs[cpu->cpu_pgd]; 1106 1123 1107 - /* Switcher page should always be mapped! */ 1108 - BUG_ON(!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped); 1124 + /* Switcher page should always be mapped by now! */ 1125 + BUG_ON(!pgdir->switcher_mapped); 1109 1126 1110 - /* Clear all the Switcher mappings for any other CPUs. */ 1111 - /* FIXME: This is dumb: update only when Host CPU changes. */ 1112 - for_each_possible_cpu(i) { 1113 - /* Get location of lguest_pages (indexed by Host CPU) */ 1114 - base = switcher_addr + PAGE_SIZE 1115 - + i * sizeof(struct lguest_pages); 1127 + /* 1128 + * Remember that we have two pages for each Host CPU, so we can run a 1129 + * Guest on each CPU without them interfering. We need to make sure 1130 + * those pages are mapped correctly in the Guest, but since we usually 1131 + * run on the same CPU, we cache that, and only update the mappings 1132 + * when we move. 1133 + */ 1134 + if (pgdir->last_host_cpu == raw_smp_processor_id()) 1135 + return; 1116 1136 1117 - /* Get shadow PTE for first page (where we put guest regs). */ 1118 - pte = find_spte(cpu, base, false, 0, 0); 1119 - set_pte(pte, __pte(0)); 1120 - 1121 - /* This is where we put R/O state. */ 1122 - pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0); 1123 - set_pte(pte, __pte(0)); 1137 + /* -1 means unknown so we remove everything. */ 1138 + if (pgdir->last_host_cpu == -1) { 1139 + unsigned int i; 1140 + for_each_possible_cpu(i) 1141 + remove_switcher_percpu_map(cpu, i); 1142 + } else { 1143 + /* We know exactly what CPU mapping to remove. */ 1144 + remove_switcher_percpu_map(cpu, pgdir->last_host_cpu); 1124 1145 } 1125 1146 1126 1147 /* ··· 1169 1140 * the Guest: the IDT, GDT and other things it's not supposed to 1170 1141 * change. 1171 1142 */ 1172 - base += PAGE_SIZE; 1173 - pte = find_spte(cpu, base, false, 0, 0); 1174 - 1143 + pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0); 1175 1144 percpu_switcher_page 1176 1145 = lg_switcher_pages[1 + raw_smp_processor_id()*2 + 1]; 1177 1146 get_page(percpu_switcher_page); 1178 1147 set_pte(pte, mk_pte(percpu_switcher_page, 1179 1148 __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL))); 1180 - } 1181 - /*:*/ 1182 1149 1183 - /* 1150 + pgdir->last_host_cpu = raw_smp_processor_id(); 1151 + } 1152 + 1153 + /*H:490 1184 1154 * We've made it through the page table code. Perhaps our tired brains are 1185 1155 * still processing the details, or perhaps we're simply glad it's over. 1186 1156 *