linux/virt/kvm/async_pf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * kvm asynchronous fault support
   4 *
   5 * Copyright 2010 Red Hat, Inc.
   6 *
   7 * Author:
   8 *      Gleb Natapov <gleb@redhat.com>
   9 */
  10
  11#include <linux/kvm_host.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include <linux/mmu_context.h>
  15#include <linux/sched/mm.h>
  16
  17#include "async_pf.h"
  18#include <trace/events/kvm.h>
  19
  20static struct kmem_cache *async_pf_cache;
  21
  22int kvm_async_pf_init(void)
  23{
  24        async_pf_cache = KMEM_CACHE(kvm_async_pf, 0);
  25
  26        if (!async_pf_cache)
  27                return -ENOMEM;
  28
  29        return 0;
  30}
  31
  32void kvm_async_pf_deinit(void)
  33{
  34        kmem_cache_destroy(async_pf_cache);
  35        async_pf_cache = NULL;
  36}
  37
  38void kvm_async_pf_vcpu_init(struct kvm_vcpu *vcpu)
  39{
  40        INIT_LIST_HEAD(&vcpu->async_pf.done);
  41        INIT_LIST_HEAD(&vcpu->async_pf.queue);
  42        spin_lock_init(&vcpu->async_pf.lock);
  43}
  44
  45static void async_pf_execute(struct work_struct *work)
  46{
  47        struct kvm_async_pf *apf =
  48                container_of(work, struct kvm_async_pf, work);
  49        struct mm_struct *mm = apf->mm;
  50        struct kvm_vcpu *vcpu = apf->vcpu;
  51        unsigned long addr = apf->addr;
  52        gpa_t cr2_or_gpa = apf->cr2_or_gpa;
  53        int locked = 1;
  54        bool first;
  55
  56        might_sleep();
  57
  58        /*
  59         * This work is run asynchronously to the task which owns
  60         * mm and might be done in another context, so we must
  61         * access remotely.
  62         */
  63        mmap_read_lock(mm);
  64        get_user_pages_remote(mm, addr, 1, FOLL_WRITE, NULL, NULL,
  65                        &locked);
  66        if (locked)
  67                mmap_read_unlock(mm);
  68
  69        if (IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC))
  70                kvm_arch_async_page_present(vcpu, apf);
  71
  72        spin_lock(&vcpu->async_pf.lock);
  73        first = list_empty(&vcpu->async_pf.done);
  74        list_add_tail(&apf->link, &vcpu->async_pf.done);
  75        apf->vcpu = NULL;
  76        spin_unlock(&vcpu->async_pf.lock);
  77
  78        if (!IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC) && first)
  79                kvm_arch_async_page_present_queued(vcpu);
  80
  81        /*
  82         * apf may be freed by kvm_check_async_pf_completion() after
  83         * this point
  84         */
  85
  86        trace_kvm_async_pf_completed(addr, cr2_or_gpa);
  87
  88        rcuwait_wake_up(&vcpu->wait);
  89
  90        mmput(mm);
  91        kvm_put_kvm(vcpu->kvm);
  92}
  93
  94void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
  95{
  96        spin_lock(&vcpu->async_pf.lock);
  97
  98        /* cancel outstanding work queue item */
  99        while (!list_empty(&vcpu->async_pf.queue)) {
 100                struct kvm_async_pf *work =
 101                        list_first_entry(&vcpu->async_pf.queue,
 102                                         typeof(*work), queue);
 103                list_del(&work->queue);
 104
 105                /*
 106                 * We know it's present in vcpu->async_pf.done, do
 107                 * nothing here.
 108                 */
 109                if (!work->vcpu)
 110                        continue;
 111
 112                spin_unlock(&vcpu->async_pf.lock);
 113#ifdef CONFIG_KVM_ASYNC_PF_SYNC
 114                flush_work(&work->work);
 115#else
 116                if (cancel_work_sync(&work->work)) {
 117                        mmput(work->mm);
 118                        kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
 119                        kmem_cache_free(async_pf_cache, work);
 120                }
 121#endif
 122                spin_lock(&vcpu->async_pf.lock);
 123        }
 124
 125        while (!list_empty(&vcpu->async_pf.done)) {
 126                struct kvm_async_pf *work =
 127                        list_first_entry(&vcpu->async_pf.done,
 128                                         typeof(*work), link);
 129                list_del(&work->link);
 130                kmem_cache_free(async_pf_cache, work);
 131        }
 132        spin_unlock(&vcpu->async_pf.lock);
 133
 134        vcpu->async_pf.queued = 0;
 135}
 136
 137void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)
 138{
 139        struct kvm_async_pf *work;
 140
 141        while (!list_empty_careful(&vcpu->async_pf.done) &&
 142              kvm_arch_can_dequeue_async_page_present(vcpu)) {
 143                spin_lock(&vcpu->async_pf.lock);
 144                work = list_first_entry(&vcpu->async_pf.done, typeof(*work),
 145                                              link);
 146                list_del(&work->link);
 147                spin_unlock(&vcpu->async_pf.lock);
 148
 149                kvm_arch_async_page_ready(vcpu, work);
 150                if (!IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC))
 151                        kvm_arch_async_page_present(vcpu, work);
 152
 153                list_del(&work->queue);
 154                vcpu->async_pf.queued--;
 155                kmem_cache_free(async_pf_cache, work);
 156        }
 157}
 158
 159/*
 160 * Try to schedule a job to handle page fault asynchronously. Returns 'true' on
 161 * success, 'false' on failure (page fault has to be handled synchronously).
 162 */
 163bool kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
 164                        unsigned long hva, struct kvm_arch_async_pf *arch)
 165{
 166        struct kvm_async_pf *work;
 167
 168        if (vcpu->async_pf.queued >= ASYNC_PF_PER_VCPU)
 169                return false;
 170
 171        /* Arch specific code should not do async PF in this case */
 172        if (unlikely(kvm_is_error_hva(hva)))
 173                return false;
 174
 175        /*
 176         * do alloc nowait since if we are going to sleep anyway we
 177         * may as well sleep faulting in page
 178         */
 179        work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN);
 180        if (!work)
 181                return false;
 182
 183        work->wakeup_all = false;
 184        work->vcpu = vcpu;
 185        work->cr2_or_gpa = cr2_or_gpa;
 186        work->addr = hva;
 187        work->arch = *arch;
 188        work->mm = current->mm;
 189        mmget(work->mm);
 190        kvm_get_kvm(work->vcpu->kvm);
 191
 192        INIT_WORK(&work->work, async_pf_execute);
 193
 194        list_add_tail(&work->queue, &vcpu->async_pf.queue);
 195        vcpu->async_pf.queued++;
 196        work->notpresent_injected = kvm_arch_async_page_not_present(vcpu, work);
 197
 198        schedule_work(&work->work);
 199
 200        return true;
 201}
 202
 203int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu)
 204{
 205        struct kvm_async_pf *work;
 206        bool first;
 207
 208        if (!list_empty_careful(&vcpu->async_pf.done))
 209                return 0;
 210
 211        work = kmem_cache_zalloc(async_pf_cache, GFP_ATOMIC);
 212        if (!work)
 213                return -ENOMEM;
 214
 215        work->wakeup_all = true;
 216        INIT_LIST_HEAD(&work->queue); /* for list_del to work */
 217
 218        spin_lock(&vcpu->async_pf.lock);
 219        first = list_empty(&vcpu->async_pf.done);
 220        list_add_tail(&work->link, &vcpu->async_pf.done);
 221        spin_unlock(&vcpu->async_pf.lock);
 222
 223        if (!IS_ENABLED(CONFIG_KVM_ASYNC_PF_SYNC) && first)
 224                kvm_arch_async_page_present_queued(vcpu);
 225
 226        vcpu->async_pf.queued++;
 227        return 0;
 228}
 229