hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/mm/gup_benchmark.c
....@@ -6,14 +6,63 @@
66 #include <linux/debugfs.h>
77
88 #define GUP_FAST_BENCHMARK _IOWR('g', 1, struct gup_benchmark)
9
+#define GUP_BENCHMARK _IOWR('g', 2, struct gup_benchmark)
10
+#define PIN_FAST_BENCHMARK _IOWR('g', 3, struct gup_benchmark)
11
+#define PIN_BENCHMARK _IOWR('g', 4, struct gup_benchmark)
12
+#define PIN_LONGTERM_BENCHMARK _IOWR('g', 5, struct gup_benchmark)
913
1014 struct gup_benchmark {
11
- __u64 delta_usec;
15
+ __u64 get_delta_usec;
16
+ __u64 put_delta_usec;
1217 __u64 addr;
1318 __u64 size;
1419 __u32 nr_pages_per_call;
1520 __u32 flags;
21
+ __u64 expansion[10]; /* For future use */
1622 };
23
+
24
+static void put_back_pages(unsigned int cmd, struct page **pages,
25
+ unsigned long nr_pages)
26
+{
27
+ unsigned long i;
28
+
29
+ switch (cmd) {
30
+ case GUP_FAST_BENCHMARK:
31
+ case GUP_BENCHMARK:
32
+ for (i = 0; i < nr_pages; i++)
33
+ put_page(pages[i]);
34
+ break;
35
+
36
+ case PIN_FAST_BENCHMARK:
37
+ case PIN_BENCHMARK:
38
+ case PIN_LONGTERM_BENCHMARK:
39
+ unpin_user_pages(pages, nr_pages);
40
+ break;
41
+ }
42
+}
43
+
44
+static void verify_dma_pinned(unsigned int cmd, struct page **pages,
45
+ unsigned long nr_pages)
46
+{
47
+ unsigned long i;
48
+ struct page *page;
49
+
50
+ switch (cmd) {
51
+ case PIN_FAST_BENCHMARK:
52
+ case PIN_BENCHMARK:
53
+ case PIN_LONGTERM_BENCHMARK:
54
+ for (i = 0; i < nr_pages; i++) {
55
+ page = pages[i];
56
+ if (WARN(!page_maybe_dma_pinned(page),
57
+ "pages[%lu] is NOT dma-pinned\n", i)) {
58
+
59
+ dump_page(page, "gup_benchmark failure");
60
+ break;
61
+ }
62
+ }
63
+ break;
64
+ }
65
+}
1766
1867 static int __gup_benchmark_ioctl(unsigned int cmd,
1968 struct gup_benchmark *gup)
....@@ -22,6 +71,9 @@
2271 unsigned long i, nr_pages, addr, next;
2372 int nr;
2473 struct page **pages;
74
+ int ret = 0;
75
+ bool needs_mmap_lock =
76
+ cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
2577
2678 if (gup->size > ULONG_MAX)
2779 return -EINVAL;
....@@ -30,6 +82,11 @@
3082 pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
3183 if (!pages)
3284 return -ENOMEM;
85
+
86
+ if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) {
87
+ ret = -EINTR;
88
+ goto free_pages;
89
+ }
3390
3491 i = 0;
3592 nr = gup->nr_pages_per_call;
....@@ -44,24 +101,67 @@
44101 nr = (next - addr) / PAGE_SIZE;
45102 }
46103
47
- nr = get_user_pages_fast(addr, nr, gup->flags & 1, pages + i);
104
+ /* Filter out most gup flags: only allow a tiny subset here: */
105
+ gup->flags &= FOLL_WRITE;
106
+
107
+ switch (cmd) {
108
+ case GUP_FAST_BENCHMARK:
109
+ nr = get_user_pages_fast(addr, nr, gup->flags,
110
+ pages + i);
111
+ break;
112
+ case GUP_BENCHMARK:
113
+ nr = get_user_pages(addr, nr, gup->flags, pages + i,
114
+ NULL);
115
+ break;
116
+ case PIN_FAST_BENCHMARK:
117
+ nr = pin_user_pages_fast(addr, nr, gup->flags,
118
+ pages + i);
119
+ break;
120
+ case PIN_BENCHMARK:
121
+ nr = pin_user_pages(addr, nr, gup->flags, pages + i,
122
+ NULL);
123
+ break;
124
+ case PIN_LONGTERM_BENCHMARK:
125
+ nr = pin_user_pages(addr, nr,
126
+ gup->flags | FOLL_LONGTERM,
127
+ pages + i, NULL);
128
+ break;
129
+ default:
130
+ ret = -EINVAL;
131
+ goto unlock;
132
+ }
133
+
48134 if (nr <= 0)
49135 break;
50136 i += nr;
51137 }
52138 end_time = ktime_get();
53139
54
- gup->delta_usec = ktime_us_delta(end_time, start_time);
140
+ /* Shifting the meaning of nr_pages: now it is actual number pinned: */
141
+ nr_pages = i;
142
+
143
+ gup->get_delta_usec = ktime_us_delta(end_time, start_time);
55144 gup->size = addr - gup->addr;
56145
57
- for (i = 0; i < nr_pages; i++) {
58
- if (!pages[i])
59
- break;
60
- put_page(pages[i]);
61
- }
146
+ /*
147
+ * Take an un-benchmark-timed moment to verify DMA pinned
148
+ * state: print a warning if any non-dma-pinned pages are found:
149
+ */
150
+ verify_dma_pinned(cmd, pages, nr_pages);
62151
152
+ start_time = ktime_get();
153
+
154
+ put_back_pages(cmd, pages, nr_pages);
155
+
156
+ end_time = ktime_get();
157
+ gup->put_delta_usec = ktime_us_delta(end_time, start_time);
158
+
159
+unlock:
160
+ if (needs_mmap_lock)
161
+ mmap_read_unlock(current->mm);
162
+free_pages:
63163 kvfree(pages);
64
- return 0;
164
+ return ret;
65165 }
66166
67167 static long gup_benchmark_ioctl(struct file *filep, unsigned int cmd,
....@@ -70,8 +170,16 @@
70170 struct gup_benchmark gup;
71171 int ret;
72172
73
- if (cmd != GUP_FAST_BENCHMARK)
173
+ switch (cmd) {
174
+ case GUP_FAST_BENCHMARK:
175
+ case GUP_BENCHMARK:
176
+ case PIN_FAST_BENCHMARK:
177
+ case PIN_BENCHMARK:
178
+ case PIN_LONGTERM_BENCHMARK:
179
+ break;
180
+ default:
74181 return -EINVAL;
182
+ }
75183
76184 if (copy_from_user(&gup, (void __user *)arg, sizeof(gup)))
77185 return -EFAULT;
....@@ -93,12 +201,8 @@
93201
94202 static int gup_benchmark_init(void)
95203 {
96
- void *ret;
97
-
98
- ret = debugfs_create_file_unsafe("gup_benchmark", 0600, NULL, NULL,
99
- &gup_benchmark_fops);
100
- if (!ret)
101
- pr_warn("Failed to create gup_benchmark in debugfs");
204
+ debugfs_create_file_unsafe("gup_benchmark", 0600, NULL, NULL,
205
+ &gup_benchmark_fops);
102206
103207 return 0;
104208 }