From: Jason Gunthorpe <jgg@ziepe.ca>
To: Christoph Hellwig <hch@infradead.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>,
Philip Yang <Philip.Yang@amd.com>,
Ralph Campbell <rcampbell@nvidia.com>,
linux-rdma@vger.kernel.org, John Hubbard <jhubbard@nvidia.com>,
Felix.Kuehling@amd.com, dri-devel@lists.freedesktop.org,
linux-mm@kvack.org, Jerome Glisse <jglisse@redhat.com>,
amd-gfx@lists.freedesktop.org, Ira Weiny <ira.weiny@intel.com>,
Ben Skeggs <bskeggs@redhat.com>
Subject: Re: [PATCH v3 hmm 04/12] mm/hmm: Simplify hmm_get_or_create and make it reliable
Date: Tue, 18 Jun 2019 15:55:55 -0300 [thread overview]
Message-ID: <20190618185555.GO6961@ziepe.ca> (raw)
In-Reply-To: <20190615141211.GD17724@infradead.org>
On Sat, Jun 15, 2019 at 07:12:11AM -0700, Christoph Hellwig wrote:
> > + spin_lock(&mm->page_table_lock);
> > + if (mm->hmm) {
> > + if (kref_get_unless_zero(&mm->hmm->kref)) {
> > + spin_unlock(&mm->page_table_lock);
> > + return mm->hmm;
> > + }
> > + }
> > + spin_unlock(&mm->page_table_lock);
>
> This could become:
>
> spin_lock(&mm->page_table_lock);
> hmm = mm->hmm
> if (hmm && kref_get_unless_zero(&hmm->kref))
> goto out_unlock;
> spin_unlock(&mm->page_table_lock);
>
> as the last two lines of the function already drop the page_table_lock
> and then return hmm. Or drop the "hmm = mm->hmm" asignment above and
> return mm->hmm as that should be always identical to hmm at the end
> to save another line.
>
> > + /*
> > + * The mm->hmm pointer is kept valid while notifier ops can be running
> > + * so they don't have to deal with a NULL mm->hmm value
> > + */
>
> The comment confuses me. How does the page_table_lock relate to
> possibly running notifiers, as I can't find that we take
> page_table_lock? Or is it just about the fact that we only clear
> mm->hmm in the free callback, and not in hmm_free?
Revised with:
From bdc02a1d502db08457823e6b2b983861a3574a76 Mon Sep 17 00:00:00 2001
From: Jason Gunthorpe <jgg@mellanox.com>
Date: Thu, 23 May 2019 10:24:13 -0300
Subject: [PATCH] mm/hmm: Simplify hmm_get_or_create and make it reliable
As coded this function can false-fail in various racy situations. Make it
reliable and simpler by running under the write side of the mmap_sem and
avoiding the false-failing compare/exchange pattern. Due to the mmap_sem
this no longer has to avoid racing with a 2nd parallel
hmm_get_or_create().
Unfortunately this still has to use the page_table_lock as the
non-sleeping lock protecting mm->hmm, since the contexts where we free the
hmm are incompatible with mmap_sem.
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Reviewed-by: John Hubbard <jhubbard@nvidia.com>
Reviewed-by: Ralph Campbell <rcampbell@nvidia.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Tested-by: Philip Yang <Philip.Yang@amd.com>
---
v2:
- Fix error unwind of mmgrab (Jerome)
- Use hmm local instead of 2nd container_of (Jerome)
v3:
- Can't use mmap_sem in the SRCU callback, keep using the
page_table_lock (Philip)
v4:
- Put the mm->hmm = NULL in the kref release, reduce LOC
in hmm_get_or_create() (Christoph)
---
mm/hmm.c | 77 ++++++++++++++++++++++----------------------------------
1 file changed, 30 insertions(+), 47 deletions(-)
diff --git a/mm/hmm.c b/mm/hmm.c
index 080b17a2e87e2d..0423f4ca3a7e09 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -31,16 +31,6 @@
#if IS_ENABLED(CONFIG_HMM_MIRROR)
static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
-static inline struct hmm *mm_get_hmm(struct mm_struct *mm)
-{
- struct hmm *hmm = READ_ONCE(mm->hmm);
-
- if (hmm && kref_get_unless_zero(&hmm->kref))
- return hmm;
-
- return NULL;
-}
-
/**
* hmm_get_or_create - register HMM against an mm (HMM internal)
*
@@ -55,11 +45,16 @@ static inline struct hmm *mm_get_hmm(struct mm_struct *mm)
*/
static struct hmm *hmm_get_or_create(struct mm_struct *mm)
{
- struct hmm *hmm = mm_get_hmm(mm);
- bool cleanup = false;
+ struct hmm *hmm;
+
+ lockdep_assert_held_exclusive(&mm->mmap_sem);
- if (hmm)
- return hmm;
+ /* Abuse the page_table_lock to also protect mm->hmm. */
+ spin_lock(&mm->page_table_lock);
+ hmm = mm->hmm;
+ if (mm->hmm && kref_get_unless_zero(&mm->hmm->kref))
+ goto out_unlock;
+ spin_unlock(&mm->page_table_lock);
hmm = kmalloc(sizeof(*hmm), GFP_KERNEL);
if (!hmm)
@@ -74,57 +69,45 @@ static struct hmm *hmm_get_or_create(struct mm_struct *mm)
hmm->notifiers = 0;
hmm->dead = false;
hmm->mm = mm;
- mmgrab(hmm->mm);
- spin_lock(&mm->page_table_lock);
- if (!mm->hmm)
- mm->hmm = hmm;
- else
- cleanup = true;
- spin_unlock(&mm->page_table_lock);
+ hmm->mmu_notifier.ops = &hmm_mmu_notifier_ops;
+ if (__mmu_notifier_register(&hmm->mmu_notifier, mm)) {
+ kfree(hmm);
+ return NULL;
+ }
- if (cleanup)
- goto error;
+ mmgrab(hmm->mm);
/*
- * We should only get here if hold the mmap_sem in write mode ie on
- * registration of first mirror through hmm_mirror_register()
+ * We hold the exclusive mmap_sem here so we know that mm->hmm is
+ * still NULL or 0 kref, and is safe to update.
*/
- hmm->mmu_notifier.ops = &hmm_mmu_notifier_ops;
- if (__mmu_notifier_register(&hmm->mmu_notifier, mm))
- goto error_mm;
-
- return hmm;
-
-error_mm:
spin_lock(&mm->page_table_lock);
- if (mm->hmm == hmm)
- mm->hmm = NULL;
+ mm->hmm = hmm;
+
+out_unlock:
spin_unlock(&mm->page_table_lock);
-error:
- mmdrop(hmm->mm);
- kfree(hmm);
- return NULL;
+ return hmm;
}
static void hmm_free_rcu(struct rcu_head *rcu)
{
- kfree(container_of(rcu, struct hmm, rcu));
+ struct hmm *hmm = container_of(rcu, struct hmm, rcu);
+
+ mmdrop(hmm->mm);
+ kfree(hmm);
}
static void hmm_free(struct kref *kref)
{
struct hmm *hmm = container_of(kref, struct hmm, kref);
- struct mm_struct *mm = hmm->mm;
- mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
+ spin_lock(&hmm->mm->page_table_lock);
+ if (hmm->mm->hmm == hmm)
+ hmm->mm->hmm = NULL;
+ spin_unlock(&hmm->mm->page_table_lock);
- spin_lock(&mm->page_table_lock);
- if (mm->hmm == hmm)
- mm->hmm = NULL;
- spin_unlock(&mm->page_table_lock);
-
- mmdrop(hmm->mm);
+ mmu_notifier_unregister_no_release(&hmm->mmu_notifier, hmm->mm);
mmu_notifier_call_srcu(&hmm->rcu, hmm_free_rcu);
}
--
2.21.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2019-06-18 18:55 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-14 0:44 [PATCH v3 hmm 00/12] mm/hmm: Various revisions from a locking/code review Jason Gunthorpe
2019-06-14 0:44 ` [PATCH v3 hmm 01/12] mm/hmm: fix use after free with struct hmm in the mmu notifiers Jason Gunthorpe
[not found] ` <20190614004450.20252-2-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 13:56 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 02/12] mm/hmm: Use hmm_mirror not mm as an argument for hmm_range_register Jason Gunthorpe
[not found] ` <20190614004450.20252-3-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 13:59 ` Christoph Hellwig
2019-06-18 13:05 ` Jason Gunthorpe
[not found] ` <20190618130544.GC6961-uk2M96/98Pc@public.gmane.org>
2019-06-19 8:14 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 03/12] mm/hmm: Hold a mmgrab from hmm to mm Jason Gunthorpe
[not found] ` <20190614004450.20252-4-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 13:59 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 04/12] mm/hmm: Simplify hmm_get_or_create and make it reliable Jason Gunthorpe
[not found] ` <20190614004450.20252-5-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:12 ` Christoph Hellwig
2019-06-18 0:36 ` Jason Gunthorpe
2019-06-18 18:55 ` Jason Gunthorpe [this message]
2019-06-14 0:44 ` [PATCH v3 hmm 05/12] mm/hmm: Remove duplicate condition test before wait_event_timeout Jason Gunthorpe
[not found] ` <20190614004450.20252-6-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:12 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 06/12] mm/hmm: Hold on to the mmget for the lifetime of the range Jason Gunthorpe
[not found] ` <20190614004450.20252-7-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:14 ` Christoph Hellwig
2019-06-18 15:11 ` Jason Gunthorpe
[not found] ` <20190618151100.GI6961-uk2M96/98Pc@public.gmane.org>
2019-06-19 8:18 ` Christoph Hellwig
2019-06-19 11:34 ` Jason Gunthorpe
[not found] ` <20190619113452.GB9360-uk2M96/98Pc@public.gmane.org>
2019-06-19 11:54 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 07/12] mm/hmm: Use lockdep instead of comments Jason Gunthorpe
[not found] ` <20190614004450.20252-8-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:14 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 08/12] mm/hmm: Remove racy protection against double-unregistration Jason Gunthorpe
[not found] ` <20190614004450.20252-9-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:16 ` Christoph Hellwig
2019-06-18 13:13 ` Jason Gunthorpe
[not found] ` <20190618131324.GF6961-uk2M96/98Pc@public.gmane.org>
2019-06-18 13:27 ` Christoph Hellwig
2019-06-18 18:57 ` Jason Gunthorpe
[not found] ` <20190618185757.GP6961-uk2M96/98Pc@public.gmane.org>
2019-06-19 8:19 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 09/12] mm/hmm: Poison hmm_range during unregister Jason Gunthorpe
[not found] ` <20190614004450.20252-10-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:17 ` Christoph Hellwig
2019-06-18 18:04 ` Jason Gunthorpe
2019-06-14 0:44 ` [PATCH v3 hmm 10/12] mm/hmm: Do not use list*_rcu() for hmm->ranges Jason Gunthorpe
[not found] ` <20190614004450.20252-11-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:18 ` Christoph Hellwig
2019-06-18 0:38 ` Jason Gunthorpe
2019-06-14 0:44 ` [PATCH v3 hmm 11/12] mm/hmm: Remove confusing comment and logic from hmm_release Jason Gunthorpe
[not found] ` <20190614004450.20252-12-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:21 ` Christoph Hellwig
2019-06-18 0:45 ` Jason Gunthorpe
[not found] ` <20190618004509.GE30762-uk2M96/98Pc@public.gmane.org>
2019-06-18 5:37 ` Christoph Hellwig
[not found] ` <20190618053733.GA25048-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2019-06-19 0:53 ` Kuehling, Felix
[not found] ` <be4f8573-6284-04a6-7862-23bb357bfe3c-5C7GfCeVMHo@public.gmane.org>
2019-06-19 8:07 ` Christoph Hellwig
2019-06-19 11:56 ` Jason Gunthorpe
[not found] ` <20190619115632.GC9360-uk2M96/98Pc@public.gmane.org>
2019-06-19 12:03 ` Christoph Hellwig
2019-06-14 0:44 ` [PATCH v3 hmm 12/12] mm/hmm: Fix error flows in hmm_invalidate_range_start Jason Gunthorpe
[not found] ` <20190614004450.20252-13-jgg-uk2M96/98Pc@public.gmane.org>
2019-06-15 14:25 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190618185555.GO6961@ziepe.ca \
--to=jgg@ziepe.ca \
--cc=Felix.Kuehling@amd.com \
--cc=Philip.Yang@amd.com \
--cc=aarcange@redhat.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=bskeggs@redhat.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=hch@infradead.org \
--cc=ira.weiny@intel.com \
--cc=jglisse@redhat.com \
--cc=jhubbard@nvidia.com \
--cc=linux-mm@kvack.org \
--cc=linux-rdma@vger.kernel.org \
--cc=rcampbell@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox