1 From a8b9fa3504163bfe29fc9faa2aac201ace66e4da Mon Sep 17 00:00:00 2001
2 From: Paolo Pisati <paolo.pisati@canonical.com>
3 Date: Thu, 13 Jul 2023 13:35:33 +0000
4 Subject: [PATCH 2/2] Linux 6.5: handle get_user_pages() vmas argument removal
6 commit b2cac248191b7466c5819e0da617b0705a26e197 "mm/gup: removed vmas
7 array from internal GUP functions" removed vmas arg from
8 __get_user_pages_locked()[*], and to handle that we do two things:
10 1) when caller vmas arg was NULL, blindly substitute the call with the new API.
12 2) when caller vmas was a real array (and the caller expected it to be
13 populated upon return), reimplement the internal "for(;;) vma = vma_find(); vmas[i] = vma;"
14 loop that was partially removed.
16 *: get_user_pages() is a wrapper around __get_user_pages_locked()
18 Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
20 common/inc/nv-mm.h | 56 +++++++++++++------
21 conftest.sh | 26 ++++++++-
22 nvidia-drm/nvidia-drm-linux.c | 5 ++
23 nvidia-uvm/uvm8_tools.c | 24 ++++++++
24 nvidia/kernel/os-mlock.c | 5 ++
25 5 files changed, 97 insertions(+), 19 deletions(-)
27 diff --git a/kernel/common/inc/nv-mm.h b/kernel/common/inc/nv-mm.h
28 index 51d0df4a..86bf6036 100644
29 --- a/kernel/common/inc/nv-mm.h
30 +++ b/kernel/common/inc/nv-mm.h
31 @@ -77,24 +77,44 @@ typedef int vm_fault_t;
32 #if defined(NV_GET_USER_PAGES_HAS_WRITE_AND_FORCE_ARGS)
33 #define NV_GET_USER_PAGES get_user_pages
35 - #include <linux/mm.h>
37 - static inline long NV_GET_USER_PAGES(unsigned long start,
38 - unsigned long nr_pages,
41 - struct page **pages,
42 - struct vm_area_struct **vmas)
44 - unsigned int flags = 0;
47 - flags |= FOLL_WRITE;
49 - flags |= FOLL_FORCE;
51 - return get_user_pages(start, nr_pages, flags, pages, vmas);
53 + #if defined(NV_GET_USER_PAGES_DROPPED_VMA)
54 + #include <linux/mm.h>
56 + static inline long NV_GET_USER_PAGES(unsigned long start,
57 + unsigned long nr_pages,
60 + struct page **pages)
62 + unsigned int flags = 0;
65 + flags |= FOLL_WRITE;
67 + flags |= FOLL_FORCE;
69 + return get_user_pages(start, nr_pages, flags, pages);
72 + #include <linux/mm.h>
74 + static inline long NV_GET_USER_PAGES(unsigned long start,
75 + unsigned long nr_pages,
78 + struct page **pages,
79 + struct vm_area_struct **vmas)
81 + unsigned int flags = 0;
84 + flags |= FOLL_WRITE;
86 + flags |= FOLL_FORCE;
88 + return get_user_pages(start, nr_pages, flags, pages, vmas);
94 diff --git a/kernel/conftest.sh b/kernel/conftest.sh
95 index abe435ff..0131fab5 100755
96 --- a/kernel/conftest.sh
97 +++ b/kernel/conftest.sh
98 @@ -3051,7 +3051,6 @@ compile_test() {
99 # write and force parameters AND that gup has task_struct and
100 # mm_struct as its first arguments.
101 # Return if available.
102 - # Fall through to default case if absent.
104 echo "$CONFTEST_PREAMBLE
105 #include <linux/mm.h>
106 @@ -3075,6 +3074,31 @@ compile_test() {
110 + # Conftest #4: check if vma arg was dropped
111 + # Return if available.
112 + # Fall through to default case if absent.
114 + echo "$CONFTEST_PREAMBLE
115 + #include <linux/mm.h>
116 + long get_user_pages(unsigned long start,
117 + unsigned long nr_pages,
118 + unsigned int gup_flags,
119 + struct page **pages) {
123 + $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1
126 + if [ -f conftest$$.o ]; then
127 + echo "#define NV_GET_USER_PAGES_DROPPED_VMA" | append_conftest "functions"
128 + echo "#undef NV_GET_USER_PAGES_HAS_WRITE_AND_FORCE_ARGS" | append_conftest "functions"
129 + echo "#undef NV_GET_USER_PAGES_HAS_TASK_STRUCT" | append_conftest "functions"
135 echo "#define NV_GET_USER_PAGES_HAS_WRITE_AND_FORCE_ARGS" | append_conftest "functions"
136 echo "#define NV_GET_USER_PAGES_HAS_TASK_STRUCT" | append_conftest "functions"
138 diff --git a/kernel/nvidia-drm/nvidia-drm-linux.c b/kernel/nvidia-drm/nvidia-drm-linux.c
139 index be405f29..dd4a2a6d 100644
140 --- a/kernel/nvidia-drm/nvidia-drm-linux.c
141 +++ b/kernel/nvidia-drm/nvidia-drm-linux.c
142 @@ -115,8 +115,13 @@ int nv_drm_lock_user_pages(unsigned long address,
144 nv_mmap_read_lock(mm);
146 +#if defined(NV_GET_USER_PAGES_DROPPED_VMA)
147 + pages_pinned = NV_GET_USER_PAGES(address, pages_count, write, force,
150 pages_pinned = NV_GET_USER_PAGES(address, pages_count, write, force,
153 nv_mmap_read_unlock(mm);
155 if (pages_pinned < 0 || (unsigned)pages_pinned < pages_count) {
156 diff --git a/kernel/nvidia-uvm/uvm8_tools.c b/kernel/nvidia-uvm/uvm8_tools.c
157 index 1dc7c97d..ea521945 100644
158 --- a/kernel/nvidia-uvm/uvm8_tools.c
159 +++ b/kernel/nvidia-uvm/uvm8_tools.c
160 @@ -251,13 +251,37 @@ static NV_STATUS map_user_pages(NvU64 user_va, NvU64 size, void **addr, struct p
163 nv_mmap_read_lock(current->mm);
164 +#if defined(NV_GET_USER_PAGES_DROPPED_VMA)
165 + ret = NV_GET_USER_PAGES(user_va, num_pages, 1, 0, *pages);
167 ret = NV_GET_USER_PAGES(user_va, num_pages, 1, 0, *pages, vmas);
169 nv_mmap_read_unlock(current->mm);
170 if (ret != num_pages) {
171 status = NV_ERR_INVALID_ARGUMENT;
175 +#if defined(NV_GET_USER_PAGES_DROPPED_VMA)
176 + struct vm_area_struct *vma;
177 + unsigned long start;
179 + nv_mmap_read_lock(current->mm);
181 + for (i = 0; i < num_pages; i++) {
182 + vma = find_vma(current->mm, start);
184 + nv_mmap_read_unlock(current->mm);
185 + status = NV_ERR_INVALID_ARGUMENT;
190 + start = (start + PAGE_SIZE) & PAGE_MASK;
192 + nv_mmap_read_unlock(current->mm);
195 for (i = 0; i < num_pages; i++) {
196 if (page_count((*pages)[i]) > MAX_PAGE_COUNT || uvm_file_is_nvidia_uvm(vmas[i]->vm_file)) {
197 status = NV_ERR_INVALID_ARGUMENT;
198 diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
199 index f88daed4..ad5cb9a1 100644
200 --- a/kernel/nvidia/os-mlock.c
201 +++ b/kernel/nvidia/kernel/os-mlock.c
202 @@ -127,8 +127,13 @@ NV_STATUS NV_API_CALL os_lock_user_pages(
205 nv_mmap_read_lock(mm);
206 +#if defined(NV_GET_USER_PAGES_DROPPED_VMA)
207 + ret = NV_GET_USER_PAGES((unsigned long)address,
208 + page_count, write, force, user_pages);
210 ret = NV_GET_USER_PAGES((unsigned long)address,
211 page_count, write, force, user_pages, NULL);
213 nv_mmap_read_unlock(mm);