On Mon, 10 Jan 2022 21:04:40 +0000,
Jing Zhang <[email protected]> wrote:
>
> To reduce MMU lock contention during dirty logging, all permission
> relaxation operations would be performed under read lock.
>
> Signed-off-by: Jing Zhang <[email protected]>
> ---
> arch/arm64/kvm/mmu.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 50 insertions(+)
>
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index cafd5813c949..dd1f43fba4b0 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1063,6 +1063,54 @@ static int sanitise_mte_tags(struct kvm *kvm,
> kvm_pfn_t pfn,
> return 0;
> }
>
> +static bool fast_mark_writable(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
> + struct kvm_memory_slot *memslot, unsigned long fault_status)
> +{
> + int ret;
> + bool writable;
> + bool write_fault = kvm_is_write_fault(vcpu);
> + gfn_t gfn = fault_ipa >> PAGE_SHIFT;
> + kvm_pfn_t pfn;
> + struct kvm *kvm = vcpu->kvm;
> + bool logging_active = memslot_is_logging(memslot);
> + unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
> + unsigned long fault_granule;
> +
> + fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
> +
> + /* Make sure the fault can be handled in the fast path.
> + * Only handle write permission fault on non-hugepage during dirty
> + * logging period.
> + */
Not the correct comment format.
> + if (fault_status != FSC_PERM || fault_granule != PAGE_SIZE
> + || !logging_active || !write_fault)
> + return false;
This is all reinventing the logic that already exists in
user_mem_abort(). I'm sympathetic to the effort not to bloat it even
more, but code duplication doesn't help either.
> +
> +
> + /* Pin the pfn to make sure it couldn't be freed and be resued for
> + * another gfn.
> + */
> + pfn = __gfn_to_pfn_memslot(memslot, gfn, true, NULL,
> + write_fault, &writable, NULL);
> + if (is_error_pfn(pfn) || !writable)
> + return false;
What happens if we hit a non-writable mapping? Don't we leak a page
reference?
> +
> + read_lock(&kvm->mmu_lock);
> + ret = kvm_pgtable_stage2_relax_perms(
> + vcpu->arch.hw_mmu->pgt, fault_ipa, PAGE_HYP);
PAGE_HYP? Err... no. KVM_PGTABLE_PROT_RW, more likely. Yes, they
expand to the same thing, but you are not dealing with nVHE EL2 S1
page tables here.
> +
> + if (!ret) {
> + kvm_set_pfn_dirty(pfn);
> + mark_page_dirty_in_slot(kvm, memslot, gfn);
> + }
> + read_unlock(&kvm->mmu_lock);
> +
> + kvm_set_pfn_accessed(pfn);
> + kvm_release_pfn_clean(pfn);
> +
> + return true;
> +}
> +
> static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
> struct kvm_memory_slot *memslot, unsigned long hva,
> unsigned long fault_status)
> @@ -1085,6 +1133,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu,
> phys_addr_t fault_ipa,
> enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
> struct kvm_pgtable *pgt;
>
> + if (fast_mark_writable(vcpu, fault_ipa, memslot, fault_status))
> + return 0;
> fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
> write_fault = kvm_is_write_fault(vcpu);
> exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
You are bypassing all sort of checks that I want to keep. Please
integrate this in user_mem_abort instead of this side hack.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm