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

xen: implement ptep_modify_prot_start/commit

Xen has a pte update function which will update a pte while preserving
its accessed and dirty bits. This means that ptep_modify_prot_start() can be
implemented as a simple read of the pte value. The hardware may
update the pte in the meantime, but ptep_modify_prot_commit() updates it while
preserving any changes that may have happened in the meantime.

The updates in ptep_modify_prot_commit() are batched if we're currently in lazy
mmu mode.

The mmu_update hypercall can take a batch of updates to perform, but
this code doesn't make particular use of that feature, in favour of
using generic multicall batching to get them all into the hypervisor.

The net effect of this is that each mprotect pte update turns from two
expensive trap-and-emulate faults into they hypervisor into a single
hypercall whose cost is amortized in a batched multicall.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Jeremy Fitzhardinge and committed by
Ingo Molnar
e57778a1 08b882c6

+45 -5
+10 -3
arch/x86/xen/enlighten.c
··· 168 168 { 169 169 printk(KERN_INFO "Booting paravirtualized kernel on %s\n", 170 170 pv_info.name); 171 - printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic); 171 + printk(KERN_INFO "Hypervisor signature: %s%s\n", 172 + xen_start_info->magic, 173 + xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); 172 174 } 173 175 174 176 static void xen_cpuid(unsigned int *ax, unsigned int *bx, ··· 1245 1243 1246 1244 BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0); 1247 1245 1246 + xen_setup_features(); 1247 + 1248 1248 /* Install Xen paravirt ops */ 1249 1249 pv_info = xen_info; 1250 1250 pv_init_ops = xen_init_ops; ··· 1256 1252 pv_apic_ops = xen_apic_ops; 1257 1253 pv_mmu_ops = xen_mmu_ops; 1258 1254 1255 + if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { 1256 + pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; 1257 + pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; 1258 + } 1259 + 1259 1260 machine_ops = xen_machine_ops; 1260 1261 1261 1262 #ifdef CONFIG_SMP 1262 1263 smp_ops = xen_smp_ops; 1263 1264 #endif 1264 - 1265 - xen_setup_features(); 1266 1265 1267 1266 /* Get mfn list */ 1268 1267 if (!xen_feature(XENFEAT_auto_translated_physmap))
+21
arch/x86/xen/mmu.c
··· 323 323 preempt_enable(); 324 324 } 325 325 326 + pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep) 327 + { 328 + /* Just return the pte as-is. We preserve the bits on commit */ 329 + return *ptep; 330 + } 331 + 332 + void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, 333 + pte_t *ptep, pte_t pte) 334 + { 335 + struct multicall_space mcs; 336 + struct mmu_update *u; 337 + 338 + mcs = xen_mc_entry(sizeof(*u)); 339 + u = mcs.args; 340 + u->ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD; 341 + u->val = pte_val_ma(pte); 342 + MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF); 343 + 344 + xen_mc_issue(PARAVIRT_LAZY_MMU); 345 + } 346 + 326 347 /* Assume pteval_t is equivalent to all the other *val_t types. */ 327 348 static pteval_t pte_mfn_to_pfn(pteval_t val) 328 349 {
+4
arch/x86/xen/mmu.h
··· 52 52 void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); 53 53 void xen_pmd_clear(pmd_t *pmdp); 54 54 55 + pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep); 56 + void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, 57 + pte_t *ptep, pte_t pte); 58 + 55 59 #endif /* _XEN_MMU_H */
+3
include/xen/interface/features.h
··· 38 38 */ 39 39 #define XENFEAT_pae_pgdir_above_4gb 4 40 40 41 + /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ 42 + #define XENFEAT_mmu_pt_update_preserve_ad 5 43 + 41 44 #define XENFEAT_NR_SUBMAPS 1 42 45 43 46 #endif /* __XEN_PUBLIC_FEATURES_H__ */
+7 -2
include/xen/interface/xen.h
··· 114 114 * ptr[:2] -- Machine address within the frame whose mapping to modify. 115 115 * The frame must belong to the FD, if one is specified. 116 116 * val -- Value to write into the mapping entry. 117 + * 118 + * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD: 119 + * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed 120 + * with those in @val. 117 121 */ 118 - #define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ 119 - #define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ 122 + #define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ 123 + #define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ 124 + #define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */ 120 125 121 126 /* 122 127 * MMU EXTENDED OPERATIONS