Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/vm: gup_test: fix test flag

In gup_test both gup_flags and test_flags use the same flags field.
This is broken.

Farther, in the actual gup_test.c all the passed gup_flags are erased
and unconditionally replaced with FOLL_WRITE.

Which means that test_flags are ignored, and code like this always
performs pin dump test:

155 if (gup->flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN)
156 nr = pin_user_pages(addr, nr, gup->flags,
157 pages + i, NULL);
158 else
159 nr = get_user_pages(addr, nr, gup->flags,
160 pages + i, NULL);
161 break;

Add a new test_flags field, to allow raw gup_flags to work. Add a new
subcommand for DUMP_USER_PAGES_TEST to specify that pin test should be
performed.

Remove unconditional overwriting of gup_flags via FOLL_WRITE. But,
preserve the previous behaviour where FOLL_WRITE was the default flag,
and add a new option "-W" to unset FOLL_WRITE.

Rename flags with gup_flags.

With the fix, dump works like this:

root@virtme:/# gup_test -c
---- page #0, starting from user virt addr: 0x7f8acb9e4000
page:00000000d3d2ee27 refcount:2 mapcount:1 mapping:0000000000000000
index:0x0 pfn:0x100bcf
anon flags: 0x300000000080016(referenced|uptodate|lru|swapbacked)
raw: 0300000000080016 ffffd0e204021608 ffffd0e208df2e88 ffff8ea04243ec61
raw: 0000000000000000 0000000000000000 0000000200000000 0000000000000000
page dumped because: gup_test: dump_pages() test
DUMP_USER_PAGES_TEST: done

root@virtme:/# gup_test -c -p
---- page #0, starting from user virt addr: 0x7fd19701b000
page:00000000baed3c7d refcount:1025 mapcount:1 mapping:0000000000000000
index:0x0 pfn:0x108008
anon flags: 0x300000000080014(uptodate|lru|swapbacked)
raw: 0300000000080014 ffffd0e204200188 ffffd0e205e09088 ffff8ea04243ee71
raw: 0000000000000000 0000000000000000 0000040100000000 0000000000000000
page dumped because: gup_test: dump_pages() test
DUMP_USER_PAGES_TEST: done

Refcount shows the difference between pin vs no-pin case.
Also change type of nr from int to long, as it counts number of pages.

Link: https://lkml.kernel.org/r/20210215161349.246722-14-pasha.tatashin@soleen.com
Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: John Hubbard <jhubbard@nvidia.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ira Weiny <ira.weiny@intel.com>
Cc: James Morris <jmorris@namei.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sashal@kernel.org>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Tyler Hicks <tyhicks@linux.microsoft.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Pavel Tatashin and committed by
Linus Torvalds
79dbf135 f68749ec

+23 -18
+10 -13
mm/gup_test.c
··· 94 94 { 95 95 ktime_t start_time, end_time; 96 96 unsigned long i, nr_pages, addr, next; 97 - int nr; 97 + long nr; 98 98 struct page **pages; 99 99 int ret = 0; 100 100 bool needs_mmap_lock = ··· 126 126 nr = (next - addr) / PAGE_SIZE; 127 127 } 128 128 129 - /* Filter out most gup flags: only allow a tiny subset here: */ 130 - gup->flags &= FOLL_WRITE; 131 - 132 129 switch (cmd) { 133 130 case GUP_FAST_BENCHMARK: 134 - nr = get_user_pages_fast(addr, nr, gup->flags, 131 + nr = get_user_pages_fast(addr, nr, gup->gup_flags, 135 132 pages + i); 136 133 break; 137 134 case GUP_BASIC_TEST: 138 - nr = get_user_pages(addr, nr, gup->flags, pages + i, 135 + nr = get_user_pages(addr, nr, gup->gup_flags, pages + i, 139 136 NULL); 140 137 break; 141 138 case PIN_FAST_BENCHMARK: 142 - nr = pin_user_pages_fast(addr, nr, gup->flags, 139 + nr = pin_user_pages_fast(addr, nr, gup->gup_flags, 143 140 pages + i); 144 141 break; 145 142 case PIN_BASIC_TEST: 146 - nr = pin_user_pages(addr, nr, gup->flags, pages + i, 143 + nr = pin_user_pages(addr, nr, gup->gup_flags, pages + i, 147 144 NULL); 148 145 break; 149 146 case PIN_LONGTERM_BENCHMARK: 150 147 nr = pin_user_pages(addr, nr, 151 - gup->flags | FOLL_LONGTERM, 148 + gup->gup_flags | FOLL_LONGTERM, 152 149 pages + i, NULL); 153 150 break; 154 151 case DUMP_USER_PAGES_TEST: 155 - if (gup->flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) 156 - nr = pin_user_pages(addr, nr, gup->flags, 152 + if (gup->test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) 153 + nr = pin_user_pages(addr, nr, gup->gup_flags, 157 154 pages + i, NULL); 158 155 else 159 - nr = get_user_pages(addr, nr, gup->flags, 156 + nr = get_user_pages(addr, nr, gup->gup_flags, 160 157 pages + i, NULL); 161 158 break; 162 159 default: ··· 184 187 185 188 start_time = ktime_get(); 186 189 187 - put_back_pages(cmd, pages, nr_pages, gup->flags); 190 + put_back_pages(cmd, pages, nr_pages, gup->test_flags); 188 191 189 192 end_time = ktime_get(); 190 193 gup->put_delta_usec = ktime_us_delta(end_time, start_time);
+2 -1
mm/gup_test.h
··· 21 21 __u64 addr; 22 22 __u64 size; 23 23 __u32 nr_pages_per_call; 24 - __u32 flags; 24 + __u32 gup_flags; 25 + __u32 test_flags; 25 26 /* 26 27 * Each non-zero entry is the number of the page (1-based: first page is 27 28 * page 1, so that zero entries mean "do nothing") from the .addr base.
+11 -4
tools/testing/selftests/vm/gup_test.c
··· 37 37 { 38 38 struct gup_test gup = { 0 }; 39 39 unsigned long size = 128 * MB; 40 - int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0; 40 + int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 1; 41 41 unsigned long cmd = GUP_FAST_BENCHMARK; 42 42 int flags = MAP_PRIVATE; 43 43 char *file = "/dev/zero"; 44 44 char *p; 45 45 46 - while ((opt = getopt(argc, argv, "m:r:n:F:f:abctTLUuwSH")) != -1) { 46 + while ((opt = getopt(argc, argv, "m:r:n:F:f:abctTLUuwWSHp")) != -1) { 47 47 switch (opt) { 48 48 case 'a': 49 49 cmd = PIN_FAST_BENCHMARK; ··· 65 65 */ 66 66 gup.which_pages[0] = 1; 67 67 break; 68 + case 'p': 69 + /* works only with DUMP_USER_PAGES_TEST */ 70 + gup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN; 71 + break; 68 72 case 'F': 69 73 /* strtol, so you can pass flags in hex form */ 70 - gup.flags = strtol(optarg, 0, 0); 74 + gup.gup_flags = strtol(optarg, 0, 0); 71 75 break; 72 76 case 'm': 73 77 size = atoi(optarg) * MB; ··· 96 92 break; 97 93 case 'w': 98 94 write = 1; 95 + break; 96 + case 'W': 97 + write = 0; 99 98 break; 100 99 case 'f': 101 100 file = optarg; ··· 147 140 148 141 gup.nr_pages_per_call = nr_pages; 149 142 if (write) 150 - gup.flags |= FOLL_WRITE; 143 + gup.gup_flags |= FOLL_WRITE; 151 144 152 145 fd = open("/sys/kernel/debug/gup_test", O_RDWR); 153 146 if (fd == -1) {