diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
| -rw-r--r-- | virt/kvm/kvm_main.c | 54 | 
1 files changed, 40 insertions, 14 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2500178cf444..486800a7024b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -345,7 +345,6 @@ bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req)  }  EXPORT_SYMBOL_GPL(kvm_make_all_cpus_request); -#ifndef CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL  void kvm_flush_remote_tlbs(struct kvm *kvm)  {  	++kvm->stat.generic.remote_tlb_flush_requests; @@ -361,12 +360,38 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)  	 * kvm_make_all_cpus_request() reads vcpu->mode. We reuse that  	 * barrier here.  	 */ -	if (!kvm_arch_flush_remote_tlb(kvm) +	if (!kvm_arch_flush_remote_tlbs(kvm)  	    || kvm_make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH))  		++kvm->stat.generic.remote_tlb_flush;  }  EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs); -#endif + +void kvm_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages) +{ +	if (!kvm_arch_flush_remote_tlbs_range(kvm, gfn, nr_pages)) +		return; + +	/* +	 * Fall back to a flushing entire TLBs if the architecture range-based +	 * TLB invalidation is unsupported or can't be performed for whatever +	 * reason. +	 */ +	kvm_flush_remote_tlbs(kvm); +} + +void kvm_flush_remote_tlbs_memslot(struct kvm *kvm, +				   const struct kvm_memory_slot *memslot) +{ +	/* +	 * All current use cases for flushing the TLBs for a specific memslot +	 * are related to dirty logging, and many do the TLB flush out of +	 * mmu_lock. The interaction between the various operations on memslot +	 * must be serialized by slots_locks to ensure the TLB flush from one +	 * operation is observed by any other operation on the same memslot. +	 */ +	lockdep_assert_held(&kvm->slots_lock); +	kvm_flush_remote_tlbs_range(kvm, memslot->base_gfn, memslot->npages); +}  static void kvm_flush_shadow_all(struct kvm *kvm)  { @@ -526,7 +551,7 @@ typedef void (*on_unlock_fn_t)(struct kvm *kvm);  struct kvm_hva_range {  	unsigned long start;  	unsigned long end; -	pte_t pte; +	union kvm_mmu_notifier_arg arg;  	hva_handler_t handler;  	on_lock_fn_t on_lock;  	on_unlock_fn_t on_unlock; @@ -547,6 +572,8 @@ static void kvm_null_fn(void)  }  #define IS_KVM_NULL_FN(fn) ((fn) == (void *)kvm_null_fn) +static const union kvm_mmu_notifier_arg KVM_MMU_NOTIFIER_NO_ARG; +  /* Iterate over each memslot intersecting [start, last] (inclusive) range */  #define kvm_for_each_memslot_in_hva_range(node, slots, start, last)	     \  	for (node = interval_tree_iter_first(&slots->hva_tree, start, last); \ @@ -591,7 +618,7 @@ static __always_inline int __kvm_handle_hva_range(struct kvm *kvm,  			 * bother making these conditional (to avoid writes on  			 * the second or later invocation of the handler).  			 */ -			gfn_range.pte = range->pte; +			gfn_range.arg = range->arg;  			gfn_range.may_block = range->may_block;  			/* @@ -632,14 +659,14 @@ static __always_inline int __kvm_handle_hva_range(struct kvm *kvm,  static __always_inline int kvm_handle_hva_range(struct mmu_notifier *mn,  						unsigned long start,  						unsigned long end, -						pte_t pte, +						union kvm_mmu_notifier_arg arg,  						hva_handler_t handler)  {  	struct kvm *kvm = mmu_notifier_to_kvm(mn);  	const struct kvm_hva_range range = {  		.start		= start,  		.end		= end, -		.pte		= pte, +		.arg		= arg,  		.handler	= handler,  		.on_lock	= (void *)kvm_null_fn,  		.on_unlock	= (void *)kvm_null_fn, @@ -659,7 +686,6 @@ static __always_inline int kvm_handle_hva_range_no_flush(struct mmu_notifier *mn  	const struct kvm_hva_range range = {  		.start		= start,  		.end		= end, -		.pte		= __pte(0),  		.handler	= handler,  		.on_lock	= (void *)kvm_null_fn,  		.on_unlock	= (void *)kvm_null_fn, @@ -693,6 +719,7 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,  					pte_t pte)  {  	struct kvm *kvm = mmu_notifier_to_kvm(mn); +	const union kvm_mmu_notifier_arg arg = { .pte = pte };  	trace_kvm_set_spte_hva(address); @@ -708,7 +735,7 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,  	if (!READ_ONCE(kvm->mmu_invalidate_in_progress))  		return; -	kvm_handle_hva_range(mn, address, address + 1, pte, kvm_change_spte_gfn); +	kvm_handle_hva_range(mn, address, address + 1, arg, kvm_change_spte_gfn);  }  void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start, @@ -747,7 +774,6 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,  	const struct kvm_hva_range hva_range = {  		.start		= range->start,  		.end		= range->end, -		.pte		= __pte(0),  		.handler	= kvm_unmap_gfn_range,  		.on_lock	= kvm_mmu_invalidate_begin,  		.on_unlock	= kvm_arch_guest_memory_reclaimed, @@ -812,7 +838,6 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,  	const struct kvm_hva_range hva_range = {  		.start		= range->start,  		.end		= range->end, -		.pte		= __pte(0),  		.handler	= (void *)kvm_null_fn,  		.on_lock	= kvm_mmu_invalidate_end,  		.on_unlock	= (void *)kvm_null_fn, @@ -845,7 +870,8 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn,  {  	trace_kvm_age_hva(start, end); -	return kvm_handle_hva_range(mn, start, end, __pte(0), kvm_age_gfn); +	return kvm_handle_hva_range(mn, start, end, KVM_MMU_NOTIFIER_NO_ARG, +				    kvm_age_gfn);  }  static int kvm_mmu_notifier_clear_young(struct mmu_notifier *mn, @@ -2180,7 +2206,7 @@ static int kvm_get_dirty_log_protect(struct kvm *kvm, struct kvm_dirty_log *log)  	}  	if (flush) -		kvm_arch_flush_remote_tlbs_memslot(kvm, memslot); +		kvm_flush_remote_tlbs_memslot(kvm, memslot);  	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))  		return -EFAULT; @@ -2297,7 +2323,7 @@ static int kvm_clear_dirty_log_protect(struct kvm *kvm,  	KVM_MMU_UNLOCK(kvm);  	if (flush) -		kvm_arch_flush_remote_tlbs_memslot(kvm, memslot); +		kvm_flush_remote_tlbs_memslot(kvm, memslot);  	return 0;  }  |