[PATCH 09/14] drm/amdkfd: Make kfd_process reference counted
Oded Gabbay
oded.gabbay at gmail.com
Sun Dec 10 10:00:18 UTC 2017
On Tue, Nov 28, 2017 at 1:29 AM, Felix Kuehling <Felix.Kuehling at amd.com> wrote:
> This will be used to elliminate the use of the process lock for
> preventing concurrent process destruction. This will simplify lock
> dependencies between KFD and KGD.
>
> This also simplifies the process destruction in a few ways:
> * Don't allocate work struct dynamically
> * Remove unnecessary hack that increments mm reference counter
> * Remove unnecessary process locking during destruction
>
> Signed-off-by: Felix Kuehling <Felix.Kuehling at amd.com>
> ---
> drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 +++
> drivers/gpu/drm/amd/amdkfd/kfd_process.c | 58 ++++++++++++--------------------
> 2 files changed, 26 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> index dca493b..248e4f5 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> @@ -34,6 +34,7 @@
> #include <linux/idr.h>
> #include <linux/kfifo.h>
> #include <linux/seq_file.h>
> +#include <linux/kref.h>
> #include <kgd_kfd_interface.h>
>
> #include "amd_shared.h"
> @@ -537,6 +538,9 @@ struct kfd_process {
> */
> void *mm;
>
> + struct kref ref;
> + struct work_struct release_work;
> +
> struct mutex mutex;
>
> /*
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> index 660d8bc..e02e8a2 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> @@ -48,11 +48,6 @@ DEFINE_STATIC_SRCU(kfd_processes_srcu);
>
> static struct workqueue_struct *kfd_process_wq;
>
> -struct kfd_process_release_work {
> - struct work_struct kfd_work;
> - struct kfd_process *p;
> -};
> -
> static struct kfd_process *find_process(const struct task_struct *thread);
> static struct kfd_process *create_process(const struct task_struct *thread);
> static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep);
> @@ -151,21 +146,20 @@ static struct kfd_process *find_process(const struct task_struct *thread)
> return p;
> }
>
> +/* No process locking is needed in this function, because the process
> + * is not findable any more. We must assume that no other thread is
> + * using it any more, otherwise we couldn't safely free the process
> + * structure in the end.
> + */
> static void kfd_process_wq_release(struct work_struct *work)
> {
> - struct kfd_process_release_work *my_work;
> + struct kfd_process *p = container_of(work, struct kfd_process,
> + release_work);
> struct kfd_process_device *pdd, *temp;
> - struct kfd_process *p;
> -
> - my_work = (struct kfd_process_release_work *) work;
> -
> - p = my_work->p;
>
> pr_debug("Releasing process (pasid %d) in workqueue\n",
> p->pasid);
>
> - mutex_lock(&p->mutex);
> -
> list_for_each_entry_safe(pdd, temp, &p->per_device_data,
> per_device_list) {
> pr_debug("Releasing pdd (topology id %d) for process (pasid %d) in workqueue\n",
> @@ -188,33 +182,26 @@ static void kfd_process_wq_release(struct work_struct *work)
> kfd_pasid_free(p->pasid);
> kfd_free_process_doorbells(p);
>
> - mutex_unlock(&p->mutex);
> -
> mutex_destroy(&p->mutex);
>
> put_task_struct(p->lead_thread);
>
> kfree(p);
> -
> - kfree(work);
> }
>
> -static void kfd_process_destroy_delayed(struct rcu_head *rcu)
> +static void kfd_process_ref_release(struct kref *ref)
> {
> - struct kfd_process_release_work *work;
> - struct kfd_process *p;
> -
> - p = container_of(rcu, struct kfd_process, rcu);
> + struct kfd_process *p = container_of(ref, struct kfd_process, ref);
>
> - mmdrop(p->mm);
> + INIT_WORK(&p->release_work, kfd_process_wq_release);
> + queue_work(kfd_process_wq, &p->release_work);
> +}
>
> - work = kmalloc(sizeof(struct kfd_process_release_work), GFP_ATOMIC);
> +static void kfd_process_destroy_delayed(struct rcu_head *rcu)
> +{
> + struct kfd_process *p = container_of(rcu, struct kfd_process, rcu);
>
> - if (work) {
> - INIT_WORK((struct work_struct *) work, kfd_process_wq_release);
> - work->p = p;
> - queue_work(kfd_process_wq, (struct work_struct *) work);
> - }
> + kref_put(&p->ref, kfd_process_ref_release);
> }
>
> static void kfd_process_notifier_release(struct mmu_notifier *mn,
> @@ -258,15 +245,12 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn,
> kfd_process_dequeue_from_all_devices(p);
> pqm_uninit(&p->pqm);
>
> + /* Indicate to other users that MM is no longer valid */
> + p->mm = NULL;
> +
> mutex_unlock(&p->mutex);
>
> - /*
> - * Because we drop mm_count inside kfd_process_destroy_delayed
> - * and because the mmu_notifier_unregister function also drop
> - * mm_count we need to take an extra count here.
> - */
> - mmgrab(p->mm);
> - mmu_notifier_unregister_no_release(&p->mmu_notifier, p->mm);
> + mmu_notifier_unregister_no_release(&p->mmu_notifier, mm);
> mmu_notifier_call_srcu(&p->rcu, &kfd_process_destroy_delayed);
> }
>
> @@ -331,6 +315,8 @@ static struct kfd_process *create_process(const struct task_struct *thread)
> if (kfd_alloc_process_doorbells(process) < 0)
> goto err_alloc_doorbells;
>
> + kref_init(&process->ref);
> +
> mutex_init(&process->mutex);
>
> process->mm = thread->mm;
> --
> 2.7.4
>
This patch is:
Reviewed-by: Oded Gabbay <oded.gabbay at gmail.com>
More information about the amd-gfx
mailing list