1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/kernel.h>
3*4882a593Smuzhiyun #include <linux/errno.h>
4*4882a593Smuzhiyun #include <linux/err.h>
5*4882a593Smuzhiyun #include <linux/mm.h>
6*4882a593Smuzhiyun #include <linux/slab.h>
7*4882a593Smuzhiyun #include <linux/vmalloc.h>
8*4882a593Smuzhiyun #include <linux/pagemap.h>
9*4882a593Smuzhiyun #include <linux/sched.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /**
12*4882a593Smuzhiyun * get_vaddr_frames() - map virtual addresses to pfns
13*4882a593Smuzhiyun * @start: starting user address
14*4882a593Smuzhiyun * @nr_frames: number of pages / pfns from start to map
15*4882a593Smuzhiyun * @gup_flags: flags modifying lookup behaviour
16*4882a593Smuzhiyun * @vec: structure which receives pages / pfns of the addresses mapped.
17*4882a593Smuzhiyun * It should have space for at least nr_frames entries.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * This function maps virtual addresses from @start and fills @vec structure
20*4882a593Smuzhiyun * with page frame numbers or page pointers to corresponding pages (choice
21*4882a593Smuzhiyun * depends on the type of the vma underlying the virtual address). If @start
22*4882a593Smuzhiyun * belongs to a normal vma, the function grabs reference to each of the pages
23*4882a593Smuzhiyun * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
24*4882a593Smuzhiyun * touch page structures and the caller must make sure pfns aren't reused for
25*4882a593Smuzhiyun * anything else while he is using them.
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * The function returns number of pages mapped which may be less than
28*4882a593Smuzhiyun * @nr_frames. In particular we stop mapping if there are more vmas of
29*4882a593Smuzhiyun * different type underlying the specified range of virtual addresses.
30*4882a593Smuzhiyun * When the function isn't able to map a single page, it returns error.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * This function takes care of grabbing mmap_lock as necessary.
33*4882a593Smuzhiyun */
get_vaddr_frames(unsigned long start,unsigned int nr_frames,unsigned int gup_flags,struct frame_vector * vec)34*4882a593Smuzhiyun int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
35*4882a593Smuzhiyun unsigned int gup_flags, struct frame_vector *vec)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun struct mm_struct *mm = current->mm;
38*4882a593Smuzhiyun struct vm_area_struct *vma;
39*4882a593Smuzhiyun int ret = 0;
40*4882a593Smuzhiyun int locked;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (nr_frames == 0)
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
46*4882a593Smuzhiyun nr_frames = vec->nr_allocated;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun start = untagged_addr(start);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun mmap_read_lock(mm);
51*4882a593Smuzhiyun locked = 1;
52*4882a593Smuzhiyun vma = find_vma_intersection(mm, start, start + 1);
53*4882a593Smuzhiyun if (!vma) {
54*4882a593Smuzhiyun ret = -EFAULT;
55*4882a593Smuzhiyun goto out;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun * While get_vaddr_frames() could be used for transient (kernel
60*4882a593Smuzhiyun * controlled lifetime) pinning of memory pages all current
61*4882a593Smuzhiyun * users establish long term (userspace controlled lifetime)
62*4882a593Smuzhiyun * page pinning. Treat get_vaddr_frames() like
63*4882a593Smuzhiyun * get_user_pages_longterm() and disallow it for filesystem-dax
64*4882a593Smuzhiyun * mappings.
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun if (vma_is_fsdax(vma)) {
67*4882a593Smuzhiyun ret = -EOPNOTSUPP;
68*4882a593Smuzhiyun goto out;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
72*4882a593Smuzhiyun vec->got_ref = true;
73*4882a593Smuzhiyun vec->is_pfns = false;
74*4882a593Smuzhiyun ret = pin_user_pages_locked(start, nr_frames,
75*4882a593Smuzhiyun gup_flags, (struct page **)(vec->ptrs), &locked);
76*4882a593Smuzhiyun if (likely(ret > 0))
77*4882a593Smuzhiyun goto out;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* This used to (racily) return non-refcounted pfns. Let people know */
81*4882a593Smuzhiyun WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping");
82*4882a593Smuzhiyun vec->nr_frames = 0;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun out:
85*4882a593Smuzhiyun if (locked)
86*4882a593Smuzhiyun mmap_read_unlock(mm);
87*4882a593Smuzhiyun if (!ret)
88*4882a593Smuzhiyun ret = -EFAULT;
89*4882a593Smuzhiyun if (ret > 0)
90*4882a593Smuzhiyun vec->nr_frames = ret;
91*4882a593Smuzhiyun return ret;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun EXPORT_SYMBOL(get_vaddr_frames);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /**
96*4882a593Smuzhiyun * put_vaddr_frames() - drop references to pages if get_vaddr_frames() acquired
97*4882a593Smuzhiyun * them
98*4882a593Smuzhiyun * @vec: frame vector to put
99*4882a593Smuzhiyun *
100*4882a593Smuzhiyun * Drop references to pages if get_vaddr_frames() acquired them. We also
101*4882a593Smuzhiyun * invalidate the frame vector so that it is prepared for the next call into
102*4882a593Smuzhiyun * get_vaddr_frames().
103*4882a593Smuzhiyun */
put_vaddr_frames(struct frame_vector * vec)104*4882a593Smuzhiyun void put_vaddr_frames(struct frame_vector *vec)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct page **pages;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (!vec->got_ref)
109*4882a593Smuzhiyun goto out;
110*4882a593Smuzhiyun pages = frame_vector_pages(vec);
111*4882a593Smuzhiyun /*
112*4882a593Smuzhiyun * frame_vector_pages() might needed to do a conversion when
113*4882a593Smuzhiyun * get_vaddr_frames() got pages but vec was later converted to pfns.
114*4882a593Smuzhiyun * But it shouldn't really fail to convert pfns back...
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun if (WARN_ON(IS_ERR(pages)))
117*4882a593Smuzhiyun goto out;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun unpin_user_pages(pages, vec->nr_frames);
120*4882a593Smuzhiyun vec->got_ref = false;
121*4882a593Smuzhiyun out:
122*4882a593Smuzhiyun vec->nr_frames = 0;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun EXPORT_SYMBOL(put_vaddr_frames);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /**
127*4882a593Smuzhiyun * frame_vector_to_pages - convert frame vector to contain page pointers
128*4882a593Smuzhiyun * @vec: frame vector to convert
129*4882a593Smuzhiyun *
130*4882a593Smuzhiyun * Convert @vec to contain array of page pointers. If the conversion is
131*4882a593Smuzhiyun * successful, return 0. Otherwise return an error. Note that we do not grab
132*4882a593Smuzhiyun * page references for the page structures.
133*4882a593Smuzhiyun */
frame_vector_to_pages(struct frame_vector * vec)134*4882a593Smuzhiyun int frame_vector_to_pages(struct frame_vector *vec)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun int i;
137*4882a593Smuzhiyun unsigned long *nums;
138*4882a593Smuzhiyun struct page **pages;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (!vec->is_pfns)
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun nums = frame_vector_pfns(vec);
143*4882a593Smuzhiyun for (i = 0; i < vec->nr_frames; i++)
144*4882a593Smuzhiyun if (!pfn_valid(nums[i]))
145*4882a593Smuzhiyun return -EINVAL;
146*4882a593Smuzhiyun pages = (struct page **)nums;
147*4882a593Smuzhiyun for (i = 0; i < vec->nr_frames; i++)
148*4882a593Smuzhiyun pages[i] = pfn_to_page(nums[i]);
149*4882a593Smuzhiyun vec->is_pfns = false;
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun EXPORT_SYMBOL(frame_vector_to_pages);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /**
155*4882a593Smuzhiyun * frame_vector_to_pfns - convert frame vector to contain pfns
156*4882a593Smuzhiyun * @vec: frame vector to convert
157*4882a593Smuzhiyun *
158*4882a593Smuzhiyun * Convert @vec to contain array of pfns.
159*4882a593Smuzhiyun */
frame_vector_to_pfns(struct frame_vector * vec)160*4882a593Smuzhiyun void frame_vector_to_pfns(struct frame_vector *vec)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun int i;
163*4882a593Smuzhiyun unsigned long *nums;
164*4882a593Smuzhiyun struct page **pages;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (vec->is_pfns)
167*4882a593Smuzhiyun return;
168*4882a593Smuzhiyun pages = (struct page **)(vec->ptrs);
169*4882a593Smuzhiyun nums = (unsigned long *)pages;
170*4882a593Smuzhiyun for (i = 0; i < vec->nr_frames; i++)
171*4882a593Smuzhiyun nums[i] = page_to_pfn(pages[i]);
172*4882a593Smuzhiyun vec->is_pfns = true;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun EXPORT_SYMBOL(frame_vector_to_pfns);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /**
177*4882a593Smuzhiyun * frame_vector_create() - allocate & initialize structure for pinned pfns
178*4882a593Smuzhiyun * @nr_frames: number of pfns slots we should reserve
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * Allocate and initialize struct pinned_pfns to be able to hold @nr_pfns
181*4882a593Smuzhiyun * pfns.
182*4882a593Smuzhiyun */
frame_vector_create(unsigned int nr_frames)183*4882a593Smuzhiyun struct frame_vector *frame_vector_create(unsigned int nr_frames)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct frame_vector *vec;
186*4882a593Smuzhiyun int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (WARN_ON_ONCE(nr_frames == 0))
189*4882a593Smuzhiyun return NULL;
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * This is absurdly high. It's here just to avoid strange effects when
192*4882a593Smuzhiyun * arithmetics overflows.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun if (WARN_ON_ONCE(nr_frames > INT_MAX / sizeof(void *) / 2))
195*4882a593Smuzhiyun return NULL;
196*4882a593Smuzhiyun /*
197*4882a593Smuzhiyun * Avoid higher order allocations, use vmalloc instead. It should
198*4882a593Smuzhiyun * be rare anyway.
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun vec = kvmalloc(size, GFP_KERNEL);
201*4882a593Smuzhiyun if (!vec)
202*4882a593Smuzhiyun return NULL;
203*4882a593Smuzhiyun vec->nr_allocated = nr_frames;
204*4882a593Smuzhiyun vec->nr_frames = 0;
205*4882a593Smuzhiyun return vec;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun EXPORT_SYMBOL(frame_vector_create);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /**
210*4882a593Smuzhiyun * frame_vector_destroy() - free memory allocated to carry frame vector
211*4882a593Smuzhiyun * @vec: Frame vector to free
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun * Free structure allocated by frame_vector_create() to carry frames.
214*4882a593Smuzhiyun */
frame_vector_destroy(struct frame_vector * vec)215*4882a593Smuzhiyun void frame_vector_destroy(struct frame_vector *vec)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun /* Make sure put_vaddr_frames() got called properly... */
218*4882a593Smuzhiyun VM_BUG_ON(vec->nr_frames > 0);
219*4882a593Smuzhiyun kvfree(vec);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun EXPORT_SYMBOL(frame_vector_destroy);
222