Skip to contentSkip to conversation

fix omission of check on FOLL_LONGTERM in gup fast path

PATCH Superseded Pingfan Liu 4 participants 15 messages Mar 16, 2020 – Mar 20, 2020

Subsystems (3)

v6 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v6 cover fix omission of check on FOLL_LONGTERM in gup fast path

v5 -> v6:
rebase code to latest linux-mm git tree

improve commit log

[3/3], rename GUP_FAST_LONGTERM_BENCHMARK as PIN_FAST_LONGTERM_BENCHMARK due to LONGTERM should be a special case of pin page.

Cc: Ira Weiny <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Mike Rapoport <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: John Hubbard <[email protected]>
Cc: "Aneesh Kumar K.V" <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Jason Gunthorpe <[email protected]>
To: [email protected]
Cc: [email protected]

Pingfan Liu (3):
mm/gup: rename nr as nr_pinned in get_user_pages_fast() mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path mm/gup_benchemark: add LONGTERM_BENCHMARK test in gup fast path

 mm/gup.c                                   | 29 +++++++++++++++++++----------
 mm/gup_benchmark.c                         |  7 +++++++
 tools/testing/selftests/vm/gup_benchmark.c |  6 +++++-
 3 files changed, 31 insertions(+), 11 deletions(-)

--
2.7.5

#1 lore raw

PATCH v6 1/3 mm/gup: rename nr as nr_pinned in get_user_pages_fast()

To better reflect the held state of pages and make code self-explaining, rename nr as nr_pinned.

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>

To: [email protected]
Cc: [email protected]

---
 mm/gup.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
mm/gup.c +10 -10
index e8aaa40..9df77b1 100644
@@ -2735,7 +2735,7 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
 					struct page **pages)
 {
 	unsigned long addr, len, end;
-	int nr = 0, ret = 0;
+	int nr_pinned = 0, ret = 0;
 
 	if (WARN_ON_ONCE(gup_flags & ~(FOLL_WRITE | FOLL_LONGTERM |
 				       FOLL_FORCE | FOLL_PIN | FOLL_GET)))
@@ -2754,25 +2754,25 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
 	if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) &&
 	    gup_fast_permitted(start, end)) {
 		local_irq_disable();
-		gup_pgd_range(addr, end, gup_flags, pages, &nr);
+		gup_pgd_range(addr, end, gup_flags, pages, &nr_pinned);
 		local_irq_enable();
-		ret = nr;
+		ret = nr_pinned;
 	}
 
-	if (nr < nr_pages) {
+	if (nr_pinned < nr_pages) {
 		/* Try to get the remaining pages with get_user_pages */
-		start += nr << PAGE_SHIFT;
-		pages += nr;
+		start += nr_pinned << PAGE_SHIFT;
+		pages += nr_pinned;
 
-		ret = __gup_longterm_unlocked(start, nr_pages - nr,
+		ret = __gup_longterm_unlocked(start, nr_pages - nr_pinned,
 					      gup_flags, pages);
 
 		/* Have to be a bit careful with return values */
-		if (nr > 0) {
+		if (nr_pinned > 0) {
 			if (ret < 0)
-				ret = nr;
+				ret = nr_pinned;
 			else
-				ret += nr;
+				ret += nr_pinned;
 		}
 	}
 

--
2.7.5

Reviewed-by on v6 1/3
#2 lore raw

Re: [PATCHv6 1/3] mm/gup: rename nr as nr_pinned in get_user_pages_fast()

Quoted 2 lines · Pingfan Liu

To better reflect the held state of pages and make code self-explaining, rename nr as nr_pinned.

Looks good,

reviewer Reviewed-by on v6 1/3
#3 lore raw

Re: [PATCHv6 1/3] mm/gup: rename nr as nr_pinned in get_user_pages_fast()

In reply to Pingfan Liu
Quoted 12 lines · Pingfan Liu

To better reflect the held state of pages and make code self-explaining, rename nr as nr_pinned.

<[email protected]> Cc: Andrew Morton <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Dan Williams <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: John Hubbard <[email protected]> Cc: "Aneesh Kumar K.V" <[email protected]> Cc: Christoph Hellwig
<[email protected]> Cc: Shuah Khan <[email protected]> To:
[email protected] Cc: [email protected] --- mm/gup.c | 20
++++++++++---------- 1 file changed, 10 insertions(+), 10
deletions(-)

Hi Pingfan,

This is correct as far as it goes, but it doesn't go quite far enough. This should at least should cover the other caller of gup_pgd_range().

Background: There are two internal-to-gup.c entry points to gup fast:
internal_get_user_pages_fast(), and __get_user_pages_fast(). Quite commonly when submitting fixes to one of these functions, the other is overlooked, as happened here.

Here's a diff on top of your patch, that I think should be squashed into your patch:

mm/gup.c +3 -3
index d0c0d084e792..56052b73abc3 100644
@@ -2676,7 +2676,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 {
 	unsigned long len, end;
 	unsigned long flags;
-	int nr = 0;
+	int nr_pinned = 0;
 	/*
 	 * Internally (within mm/gup.c), gup fast variants must set FOLL_GET,
 	 * because gup fast is always a "pin with a +1 page refcount" request.
@@ -2710,11 +2710,11 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 	if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) &&
 	    gup_fast_permitted(start, end)) {
 		local_irq_save(flags);
-		gup_pgd_range(start, end, gup_flags, pages, &nr);
+		gup_pgd_range(start, end, gup_flags, pages, &nr_pinned);
 		local_irq_restore(flags);
 	}
 
-	return nr;
+	return nr_pinned;
 }
 EXPORT_SYMBOL_GPL(__get_user_pages_fast);
 

With that applied, you can add:

thanks,

Signature · 2 lines
John Hubbard
NVIDIA
Quoted 26 lines
mm/gup.c index e8aaa40..9df77b1 100644 --- renamed from mm/gup.c +0 -0

a/mm/gup.c +++ b/mm/gup.c @@ -2735,7 +2735,7 @@ static int
internal_get_user_pages_fast(unsigned long start, int nr_pages, struct page **pages) { unsigned long addr, len, end; - int nr = 0,
ret = 0; + int nr_pinned = 0, ret = 0;

if (WARN_ON_ONCE(gup_flags & ~(FOLL_WRITE | FOLL_LONGTERM | FOLL_FORCE | FOLL_PIN | FOLL_GET))) @@ -2754,25 +2754,25 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages, if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) && gup_fast_permitted(start,
end)) { local_irq_disable(); - gup_pgd_range(addr, end, gup_flags,
pages, &nr); + gup_pgd_range(addr, end, gup_flags, pages,
&nr_pinned); local_irq_enable(); - ret = nr; + ret = nr_pinned; }

mm/gup.c index e8aaa40..9df77b1 100644 --- renamed from mm/gup.c +0 -1
-	if (nr < nr_pages) { +	if (nr_pinned < nr_pages) { /* Try to get

the remaining pages with get_user_pages */ - start += nr <<
PAGE_SHIFT; - pages += nr; + start += nr_pinned << PAGE_SHIFT; +
pages += nr_pinned;

mm/gup.c index e8aaa40..9df77b1 100644 --- renamed from mm/gup.c +0 -1
-		ret = __gup_longterm_unlocked(start, nr_pages - nr, +		ret =

__gup_longterm_unlocked(start, nr_pages - nr_pinned, gup_flags, pages);

/* Have to be a bit careful with return values */ - if (nr > 0) { +
if (nr_pinned > 0) { if (ret < 0) - ret = nr; + ret =
nr_pinned; else - ret += nr; + ret += nr_pinned; } }

-- 2.7.5

#4 lore raw

PATCH v6 2/3 mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

In reply to Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where __gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Jason Gunthorpe <[email protected]>

To: [email protected]
Cc: [email protected]

---
 mm/gup.c | 9 +++++++++
 1 file changed, 9 insertions(+)
mm/gup.c +9 -0
index 9df77b1..78132cf 100644
@@ -89,6 +89,15 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page,
 		int orig_refs = refs;
 
 		/*
+		 * Huge page's subpages have the same migrate type due to either
+		 * allocation from a free_list[] or alloc_contig_range() with
+		 * param MIGRATE_MOVABLE. So it is enough to check on a subpage.
+		 */
+		if (unlikely(flags & FOLL_LONGTERM) &&
+			is_migrate_cma_page(page))
+			return NULL;
+
+		/*
 		 * When pinning a compound page of order > 1 (which is what
 		 * hpage_pincount_available() checks for), use an exact count to
 		 * track it, via hpage_pincount_add/_sub().

--
2.7.5

#5 lore raw

Re: [PATCHv6 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

Quoted 41 lines · Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where __gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Jason Gunthorpe <[email protected]>

To: [email protected]
Cc: [email protected]

---
 mm/gup.c | 9 +++++++++
 1 file changed, 9 insertions(+)
mm/gup.c +0 -0
index 9df77b1..78132cf 100644

mm/gup.c static __maybe_unused struct page *try_grab_compound_head(struct page *page, · line 98

Quoted 10 lines
mm/gup.c +7 -0
@@ -89,6 +89,15 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page,
 		int orig_refs = refs;
 
 		/*
+		 * Huge page's subpages have the same migrate type due to either
+		 * allocation from a free_list[] or alloc_contig_range() with
+		 * param MIGRATE_MOVABLE. So it is enough to check on a subpage.
+		 */
+		if (unlikely(flags & FOLL_LONGTERM) &&
+			is_migrate_cma_page(page))
+			return NULL;

Wrong indentation. We either align two tabs for continuation statements, or after the opening brace of the previous line. With a likely or unlikely thrown in the former IMHO looks much better. E.g.

		if (unlikely(flags & FOLL_LONGTERM) &&
				is_migrate_cma_page(page))
			return NULL;
#6 lore raw

Re: [PATCHv6 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

Quoted 1 line · Christoph Hellwig

[...]

Quoted 9 lines

Wrong indentation. We either align two tabs for continuation statements, or after the opening brace of the previous line. With a likely or unlikely thrown in the former IMHO looks much better. E.g.

                if (unlikely(flags & FOLL_LONGTERM) &&
                                is_migrate_cma_page(page))
                        return NULL;

OK, thanks. I will send out V7 to fix it.

Regards,
Pingfan

#7 lore raw

PATCH v7 2/3 mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

In reply to Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where __gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Jason Gunthorpe <[email protected]>

To: [email protected]
Cc: [email protected]
---
v6 -> v7: fix coding style issue

 mm/gup.c | 9 +++++++++
 1 file changed, 9 insertions(+)
mm/gup.c +9 -0
index 9df77b1..0a536d7 100644
@@ -89,6 +89,15 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page,
 		int orig_refs = refs;
 
 		/*
+		 * Huge page's subpages have the same migrate type due to either
+		 * allocation from a free_list[] or alloc_contig_range() with
+		 * param MIGRATE_MOVABLE. So it is enough to check on a subpage.
+		 */
+		if (unlikely(flags & FOLL_LONGTERM) &&
+				is_migrate_cma_page(page))
+			return NULL;
+
+		/*
 		 * When pinning a compound page of order > 1 (which is what
 		 * hpage_pincount_available() checks for), use an exact count to
 		 * track it, via hpage_pincount_add/_sub().

--
2.7.5

Reviewed-by on v7 2/3
#8 lore raw

Re: [PATCHv7 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

Quoted 13 lines · Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where __gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Quoted 5 lines

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Looks good,

Reviewed-by on v7 2/3
#9 lore raw

Re: [PATCHv7 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

In reply to Pingfan Liu
Quoted 30 lines · Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where __gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Quoted 6 lines

To: [email protected]
Cc: [email protected]
---
v6 -> v7: fix coding style issue

 mm/gup.c | 9 +++++++++
 1 file changed, 9 insertions(+)

Much clearer, thank you

Jason

reviewer
#10 lore raw

Re: [PATCHv7 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

In reply to Pingfan Liu
Quoted 5 lines · Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where

s/slow path, slow path/slow path/

Quoted 37 lines

__gup_longterm_locked->check_and_migrate_cma_pages() handles FOLL_LONGTERM, but in fast path, there lacks such a check, which means a possible leak of CMA page to longterm pinned.

Place a check in try_grab_compound_head() in the fast path to fix the leak, and if FOLL_LONGTERM happens on CMA, it will fall back to slow path to migrate the page.

Some note about the check:
Huge page's subpages have the same migrate type due to either allocation from a free_list[] or alloc_contig_range() with param MIGRATE_MOVABLE. So it is enough to check on a single subpage by is_migrate_cma_page(subpage)

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Jason Gunthorpe <[email protected]>

To: [email protected]
Cc: [email protected]
---
v6 -> v7: fix coding style issue

  mm/gup.c | 9 +++++++++
  1 file changed, 9 insertions(+)
mm/gup.c +0 -0
index 9df77b1..0a536d7 100644

mm/gup.c static __maybe_unused struct page *try_grab_compound_head(struct page *page, · line 95

Quoted 7 lines
mm/gup.c +4 -0
@@ -89,6 +89,15 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page,
  		int orig_refs = refs;
 
  		/*
+		 * Huge page's subpages have the same migrate type due to either
+		 * allocation from a free_list[] or alloc_contig_range() with
+		 * param MIGRATE_MOVABLE. So it is enough to check on a subpage.
+		 */

Urggh, this comment is fine in the commit description, but at this location in the code it is completely incomprehensible! Instead of an extremely far-removed tidbit about interactions between CMA and huge pages, this comment should be explaining why we bail out early in the specific case of FOLL_PIN + FOLL_LONGTERM. And we don't bail out for FOLL_GET + FOLL_LONGTERM...

I'm expect it is something like:

		/*
		 * We can't do FOLL_LONGTERM + FOLL_PIN with CMA in the gup fast
		 * path, so fail and let the caller fall back to the slow path.
		 */

...approximately. Right?

Quoted 11 lines
mm/gup.c +5 -1
+		if (unlikely(flags & FOLL_LONGTERM) &&
+				is_migrate_cma_page(page))
+			return NULL;
+
+		/*
  		 * When pinning a compound page of order > 1 (which is what
  		 * hpage_pincount_available() checks for), use an exact count to
  		 * track it, via hpage_pincount_add/_sub().
--

2.7.5

thanks,

Signature · 2 lines
John Hubbard
NVIDIA
#11 lore raw

Re: [PATCHv7 2/3] mm/gup: fix omission of check on FOLL_LONGTERM in gup fast path

Quoted 10 lines · John Hubbard
Quoted 5 lines · Pingfan Liu

FOLL_LONGTERM is a special case of FOLL_PIN. It suggests a pin which is going to be given to hardware and can't move. It would truncate CMA permanently and should be excluded.

In gup slow path, slow path, where

s/slow path, slow path/slow path/

Yeah.
[...]

Quoted 16 lines

mm/gup.c static __maybe_unused struct page *try_grab_compound_head(struct page *page, · line 95

Quoted 6 lines
              /*
mm/gup.c +4 -0
+              * Huge page's subpages have the same migrate type due to either
+              * allocation from a free_list[] or alloc_contig_range() with
+              * param MIGRATE_MOVABLE. So it is enough to check on a subpage.
+              */

Urggh, this comment is fine in the commit description, but at this location in the code it is completely incomprehensible! Instead of an extremely far-removed tidbit about interactions between CMA and huge pages, this comment should be explaining why we bail out early in the specific case of FOLL_PIN + FOLL_LONGTERM. And we don't bail out for FOLL_GET + FOLL_LONGTERM...

I'm expect it is something like:

Quoted 7 lines

/*
* We can't do FOLL_LONGTERM + FOLL_PIN with CMA in the gup fast
* path, so fail and let the caller fall back to the slow path. */

...approximately. Right?

Yes, right. And I think it is better to drop "We".

Thanks,
Pingfan

#12 lore raw

PATCH v6 3/3 mm/gup_benchemark: add LONGTERM_BENCHMARK test in gup fast path

In reply to Pingfan Liu

Introduce a PIN_FAST_LONGTERM_BENCHMARK ioctl to test longterm pin in gup fast path.

Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Alexander Duyck <[email protected]>

To: [email protected]
Cc: [email protected]

---
 mm/gup_benchmark.c                         | 7 +++++++
 tools/testing/selftests/vm/gup_benchmark.c | 6 +++++-
 2 files changed, 12 insertions(+), 1 deletion(-)
mm/gup_benchmark.c +7 -0
index be690fa..09fba20 100644
@@ -10,6 +10,7 @@
 #define GUP_BENCHMARK		_IOWR('g', 3, struct gup_benchmark)
 #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark)
 #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark)
+#define PIN_FAST_LONGTERM_BENCHMARK	_IOWR('g', 6, struct gup_benchmark)
 
 struct gup_benchmark {
 	__u64 get_delta_usec;
@@ -101,6 +102,11 @@ static int __gup_benchmark_ioctl(unsigned int cmd,
 			nr = get_user_pages_fast(addr, nr, gup->flags,
 						 pages + i);
 			break;
+		case PIN_FAST_LONGTERM_BENCHMARK:
+			nr = get_user_pages_fast(addr, nr,
+					gup->flags | FOLL_LONGTERM,
+					pages + i);
+			break;
 		case GUP_LONGTERM_BENCHMARK:
 			nr = get_user_pages(addr, nr,
 					    gup->flags | FOLL_LONGTERM,
@@ -166,6 +172,7 @@ static long gup_benchmark_ioctl(struct file *filep, unsigned int cmd,
 	case GUP_BENCHMARK:
 	case PIN_FAST_BENCHMARK:
 	case PIN_BENCHMARK:
+	case PIN_FAST_LONGTERM_BENCHMARK:
 		break;
 	default:
 		return -EINVAL;
tools/testing/selftests/vm/gup_benchmark.c +5 -1
index 43b4dfe..f024ff3 100644
@@ -21,6 +21,7 @@
 /* Similar to above, but use FOLL_PIN instead of FOLL_GET. */
 #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark)
 #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark)
+#define PIN_FAST_LONGTERM_BENCHMARK	_IOWR('g', 6, struct gup_benchmark)
 
 /* Just the flags we need, copied from mm.h: */
 #define FOLL_WRITE	0x01	/* check pte is writable */
@@ -44,7 +45,7 @@ int main(int argc, char **argv)
 	char *file = "/dev/zero";
 	char *p;
 
-	while ((opt = getopt(argc, argv, "m:r:n:f:abtTLUuwSH")) != -1) {
+	while ((opt = getopt(argc, argv, "m:r:n:f:abtTlLUuwSH")) != -1) {
 		switch (opt) {
 		case 'a':
 			cmd = PIN_FAST_BENCHMARK;
@@ -67,6 +68,9 @@ int main(int argc, char **argv)
 		case 'T':
 			thp = 0;
 			break;
+		case 'l':
+			cmd = PIN_FAST_LONGTERM_BENCHMARK;
+			break;
 		case 'L':
 			cmd = GUP_LONGTERM_BENCHMARK;
 			break;

--
2.7.5

reviewer
#13 lore raw

Re: [PATCHv6 3/3] mm/gup_benchemark: add LONGTERM_BENCHMARK test in gup fast path

Quoted 2 lines · Pingfan Liu

Introduce a PIN_FAST_LONGTERM_BENCHMARK ioctl to test longterm pin in gup fast path.

1. The subject line still has "benchemark", which should be "benchmark".

2. What do you really want to test? More about the use case to be tested would help. Just another sentence. I wouldn't normally ask, but in this case the implementation is slightly scrambled, and I can't suggest how to fix it because there's no information in the commit log as to the use case, nor the motivation.

Below...

Quoted 24 lines
Cc Ira Weiny <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Dan Williams <[email protected]>
Cc Matthew Wilcox <[email protected]>
Cc John Hubbard <[email protected]>
Cc "Aneesh Kumar K.V" <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Alexander Duyck <[email protected]>

To: [email protected]
Cc: [email protected]

---
  mm/gup_benchmark.c                         | 7 +++++++
  tools/testing/selftests/vm/gup_benchmark.c | 6 +++++-
  2 files changed, 12 insertions(+), 1 deletion(-)
mm/gup_benchmark.c +0 -0
index be690fa..09fba20 100644

mm/gup_benchmark.c line 13

Quoted 4 lines
mm/gup_benchmark.c +1 -0
@@ -10,6 +10,7 @@
  #define GUP_BENCHMARK		_IOWR('g', 3, struct gup_benchmark)
  #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark)
  #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark)
+#define PIN_FAST_LONGTERM_BENCHMARK	_IOWR('g', 6, struct gup_benchmark)

Use PIN_ prefixes for things that test pin_user_pages*(), and GUP_ prefixes for things that test get_user_pages*().

I can't really be sure which one you want to test, but these wrongly intermixed:
here you are using PIN_ and get_user_pages*().

mm/gup_benchmark.c static int __gup_benchmark_ioctl(unsigned int cmd, · line 109

Quoted 12 lines
mm/gup_benchmark.c +5 -0
  struct gup_benchmark {
  	__u64 get_delta_usec;
@@ -101,6 +102,11 @@ static int __gup_benchmark_ioctl(unsigned int cmd,
  			nr = get_user_pages_fast(addr, nr, gup->flags,
  						 pages + i);
  			break;
+		case PIN_FAST_LONGTERM_BENCHMARK:
+			nr = get_user_pages_fast(addr, nr,
+					gup->flags | FOLL_LONGTERM,
+					pages + i);
+			break;

Probably, pin_user_pages_fast() is where you want to go here, not get_user_pages_fast(). See the guidance in Documentation/core-api/pin_user_pages.rst to help decide.

thanks,

Signature · 2 lines
John Hubbard
NVIDIA
Quoted 45 lines
mm/gup_benchmark.c +1 -0
  		case GUP_LONGTERM_BENCHMARK:
  			nr = get_user_pages(addr, nr,
  					    gup->flags | FOLL_LONGTERM,
@@ -166,6 +172,7 @@ static long gup_benchmark_ioctl(struct file *filep, unsigned int cmd,
  	case GUP_BENCHMARK:
  	case PIN_FAST_BENCHMARK:
  	case PIN_BENCHMARK:
+	case PIN_FAST_LONGTERM_BENCHMARK:
  		break;
  	default:
  		return -EINVAL;
tools/testing/selftests/vm/gup_benchmark.c +5 -2
index 43b4dfe..f024ff3 100644
@@ -21,6 +21,7 @@
  /* Similar to above, but use FOLL_PIN instead of FOLL_GET. */
  #define PIN_FAST_BENCHMARK	_IOWR('g', 4, struct gup_benchmark)
  #define PIN_BENCHMARK		_IOWR('g', 5, struct gup_benchmark)
+#define PIN_FAST_LONGTERM_BENCHMARK	_IOWR('g', 6, struct gup_benchmark)
 
  /* Just the flags we need, copied from mm.h: */
  #define FOLL_WRITE	0x01	/* check pte is writable */
@@ -44,7 +45,7 @@ int main(int argc, char **argv)
  	char *file = "/dev/zero";
  	char *p;
 
-	while ((opt = getopt(argc, argv, "m:r:n:f:abtTLUuwSH")) != -1) {
+	while ((opt = getopt(argc, argv, "m:r:n:f:abtTlLUuwSH")) != -1) {
  		switch (opt) {
  		case 'a':
  			cmd = PIN_FAST_BENCHMARK;
@@ -67,6 +68,9 @@ int main(int argc, char **argv)
  		case 'T':
  			thp = 0;
  			break;
+		case 'l':
+			cmd = PIN_FAST_LONGTERM_BENCHMARK;
+			break;
  		case 'L':
  			cmd = GUP_LONGTERM_BENCHMARK;
  			break;
--

2.7.5

#14 lore raw

Re: [PATCHv6 3/3] mm/gup_benchemark: add LONGTERM_BENCHMARK test in gup fast path

Quoted 11 lines · John Hubbard
Quoted 2 lines · Pingfan Liu

Introduce a PIN_FAST_LONGTERM_BENCHMARK ioctl to test longterm pin in gup fast path.

1. The subject line still has "benchemark", which should be "benchmark".

2. What do you really want to test? More about the use case to be tested would help. Just another sentence. I wouldn't normally ask, but in this case the implementation is slightly scrambled, and I can't suggest how to fix it because there's no information in the commit log as to the use case, nor the motivation.

Oh, the history about [3/3] is to verify the implementation method of [2/3]. Please refer to
https://lore.kernel.org/linux-mm/[email protected]/
Cite "

Quoted 5 lines
Quoted 5 lines

I think the concern is: for the successful gup_fast case with no CMA

pages, this patch is adding another complete loop through all the pages. In the fast case.

Quoted 7 lines
Quoted 7 lines

If the check were instead done as part of the gup_pte_range(), then it would be a little more efficient for that case.

As for whether it's worth it, *probably* this is too small an effect to measure. But in order to attempt a measurement: running fio (https://github.com/axboe/fio)
with O_DIRECT on an NVMe drive, might shed some light. Here's an fio.conf file that Jan Kara and Tom Talpey helped me come up with, for related testing:

"
But I think now, there is no motivation for it, and can be dropped it now.

Thanks,
Pingfan