summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérôme Glisse <jglisse@redhat.com>2019-05-23 12:37:52 -0400
committerJérôme Glisse <jglisse@redhat.com>2019-05-23 16:34:08 -0400
commit12ccde1834b06147346259de3fa2cc65d019c43c (patch)
tree73febfe39ea715612bf55ce723929af39fc0a032
parent3fe4ee6511878a83836763f8789b0360db073948 (diff)
mm/hmm: do not try to create hmm struct from within hmm_range_register() v2
Driver should never call hmm_range_register() without a valid and active registered hmm_mirror and thus without a valid and active hmm struct. So if that happens just return -EFAULT. Changes since v1: - do not use READ_ONCE() and make it clear what is the API expectation - remove hmm variable in hmm_range_register() Signed-off-by: Jérôme Glisse <jglisse@redhat.com> Suggested-by: Ralph Campbell <rcampbell@nvidia.com> Suggested-by: Jason Gunthorpe <jgg@mellanox.com> Cc: Jason Gunthorpe <jgg@mellanox.com> Cc: John Hubbard <jhubbard@nvidia.com> Cc: Ralph Campbell <rcampbell@nvidia.com> Cc: Ira Weiny <ira.weiny@intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Souptick Joarder <jrdr.linux@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org>
-rw-r--r--mm/hmm.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/mm/hmm.c b/mm/hmm.c
index ce05732f68d4..80cfc0056359 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -912,7 +912,6 @@ int hmm_range_register(struct hmm_range *range,
unsigned page_shift)
{
unsigned long mask = ((1UL << page_shift) - 1UL);
- struct hmm *hmm;
range->valid = false;
range->hmm = NULL;
@@ -922,14 +921,18 @@ int hmm_range_register(struct hmm_range *range,
if (start >= end)
return -EINVAL;
+ /*
+ * The caller must hold a valid struct hmm_mirror to call this api,
+ * and a valid hmm_mirror guarantees mm->hmm is valid and does not
+ * change.
+ */
+ range->hmm = mm->hmm;
+ kref_get(&range->hmm->kref);
+
range->page_shift = page_shift;
range->start = start;
range->end = end;
- range->hmm = hmm_get_or_create(mm);
- if (!range->hmm)
- return -EFAULT;
-
/* Check if hmm_mm_destroy() was call. */
if (range->hmm->mm == NULL || range->hmm->dead) {
hmm_put(range->hmm);
@@ -939,15 +942,15 @@ int hmm_range_register(struct hmm_range *range,
/* Initialize range to track CPU page table updates. */
mutex_lock(&range->hmm->lock);
- list_add_rcu(&range->list, &hmm->ranges);
+ list_add_rcu(&range->list, &range->hmm->ranges);
/*
* If there are any concurrent notifiers we have to wait for them for
* the range to be valid (see hmm_range_wait_until_valid()).
*/
- if (!hmm->notifiers)
+ if (!range->hmm->notifiers)
range->valid = true;
- mutex_unlock(&hmm->lock);
+ mutex_unlock(&range->hmm->lock);
return 0;
}