mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-17 12:34:01 +00:00
mm/frame-vector: Use FOLL_LONGTERM
This is used by media/videbuf2 for persistent dma mappings, not just for a single dma operation and then freed again, so needs FOLL_LONGTERM. Unfortunately current pup_locked doesn't support FOLL_LONGTERM due to locking issues. Rework the code to pull the pup path out from the mmap_sem critical section as suggested by Jason. By relying entirely on the vma checks in pin_user_pages and follow_pfn (for vm_flags and vma_is_fsdax) we can also streamline the code a lot. Note that pin_user_pages_fast is a safe replacement despite the seeming lack of checking for vma->vm_flasg & (VM_IO | VM_PFNMAP). Such ptes are marked with pte_mkspecial (which pup_fast rejects in the fastpath), and only architectures supporting that support the pin_user_pages_fast fastpath. Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Pawel Osciak <pawel@osciak.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Tomasz Figa <tfiga@chromium.org> Cc: Mauro Carvalho Chehab <mchehab@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: John Hubbard <jhubbard@nvidia.com> Cc: Jérôme Glisse <jglisse@redhat.com> Cc: Jan Kara <jack@suse.cz> Cc: Dan Williams <dan.j.williams@intel.com> Cc: linux-mm@kvack.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-media@vger.kernel.org Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20201127164131.2244124-6-daniel.vetter@ffwll.ch
This commit is contained in:
parent
d88a0c169b
commit
04769cb1c4
3 changed files with 19 additions and 39 deletions
|
@ -40,7 +40,6 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
|
|||
unsigned long first, last;
|
||||
unsigned long nr;
|
||||
struct frame_vector *vec;
|
||||
unsigned int flags = FOLL_FORCE | FOLL_WRITE;
|
||||
|
||||
first = start >> PAGE_SHIFT;
|
||||
last = (start + length - 1) >> PAGE_SHIFT;
|
||||
|
@ -48,7 +47,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
|
|||
vec = frame_vector_create(nr);
|
||||
if (!vec)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
|
||||
ret = get_vaddr_frames(start & PAGE_MASK, nr, vec);
|
||||
if (ret < 0)
|
||||
goto out_destroy;
|
||||
/* We accept only complete set of PFNs */
|
||||
|
|
|
@ -1768,7 +1768,7 @@ struct frame_vector {
|
|||
struct frame_vector *frame_vector_create(unsigned int nr_frames);
|
||||
void frame_vector_destroy(struct frame_vector *vec);
|
||||
int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
|
||||
unsigned int gup_flags, struct frame_vector *vec);
|
||||
struct frame_vector *vec);
|
||||
void put_vaddr_frames(struct frame_vector *vec);
|
||||
int frame_vector_to_pages(struct frame_vector *vec);
|
||||
void frame_vector_to_pfns(struct frame_vector *vec);
|
||||
|
|
|
@ -32,13 +32,12 @@
|
|||
* This function takes care of grabbing mmap_lock as necessary.
|
||||
*/
|
||||
int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
|
||||
unsigned int gup_flags, struct frame_vector *vec)
|
||||
struct frame_vector *vec)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
int ret = 0;
|
||||
int err;
|
||||
int locked;
|
||||
|
||||
if (nr_frames == 0)
|
||||
return 0;
|
||||
|
@ -48,40 +47,26 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
|
|||
|
||||
start = untagged_addr(start);
|
||||
|
||||
mmap_read_lock(mm);
|
||||
locked = 1;
|
||||
vma = find_vma_intersection(mm, start, start + 1);
|
||||
if (!vma) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* While get_vaddr_frames() could be used for transient (kernel
|
||||
* controlled lifetime) pinning of memory pages all current
|
||||
* users establish long term (userspace controlled lifetime)
|
||||
* page pinning. Treat get_vaddr_frames() like
|
||||
* get_user_pages_longterm() and disallow it for filesystem-dax
|
||||
* mappings.
|
||||
*/
|
||||
if (vma_is_fsdax(vma)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
|
||||
ret = pin_user_pages_fast(start, nr_frames,
|
||||
FOLL_FORCE | FOLL_WRITE | FOLL_LONGTERM,
|
||||
(struct page **)(vec->ptrs));
|
||||
if (ret > 0) {
|
||||
vec->got_ref = true;
|
||||
vec->is_pfns = false;
|
||||
ret = pin_user_pages_locked(start, nr_frames,
|
||||
gup_flags, (struct page **)(vec->ptrs), &locked);
|
||||
goto out;
|
||||
goto out_unlocked;
|
||||
}
|
||||
|
||||
mmap_read_lock(mm);
|
||||
vec->got_ref = false;
|
||||
vec->is_pfns = true;
|
||||
ret = 0;
|
||||
do {
|
||||
unsigned long *nums = frame_vector_pfns(vec);
|
||||
|
||||
vma = find_vma_intersection(mm, start, start + 1);
|
||||
if (!vma)
|
||||
break;
|
||||
|
||||
while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) {
|
||||
err = follow_pfn(vma, start, &nums[ret]);
|
||||
if (err) {
|
||||
|
@ -92,17 +77,13 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
|
|||
start += PAGE_SIZE;
|
||||
ret++;
|
||||
}
|
||||
/*
|
||||
* We stop if we have enough pages or if VMA doesn't completely
|
||||
* cover the tail page.
|
||||
*/
|
||||
if (ret >= nr_frames || start < vma->vm_end)
|
||||
/* Bail out if VMA doesn't completely cover the tail page. */
|
||||
if (start < vma->vm_end)
|
||||
break;
|
||||
vma = find_vma_intersection(mm, start, start + 1);
|
||||
} while (vma && vma->vm_flags & (VM_IO | VM_PFNMAP));
|
||||
} while (ret < nr_frames);
|
||||
out:
|
||||
if (locked)
|
||||
mmap_read_unlock(mm);
|
||||
mmap_read_unlock(mm);
|
||||
out_unlocked:
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
if (ret > 0)
|
||||
|
|
Loading…
Add table
Reference in a new issue