diff options
-rw-r--r-- | drivers/media/common/videobuf2/frame_vector.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index ce879f6f8f82..542dde9d2609 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -37,6 +37,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + int ret_pin_user_pages_fast = 0; int ret = 0; int err; @@ -56,6 +57,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, vec->is_pfns = false; goto out_unlocked; } + ret_pin_user_pages_fast = ret; mmap_read_lock(mm); vec->got_ref = false; @@ -71,7 +73,18 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) { err = follow_pfn(vma, start, &nums[ret]); if (err) { - if (ret == 0) + if (ret) + goto out; + // If follow_pfn() returns -EINVAL, then this + // is not an IO mapping or a raw PFN mapping. + // In that case, return the original error from + // pin_user_pages_fast(). Otherwise this + // function would return -EINVAL when + // pin_user_pages_fast() returned -ENOMEM, + // which makes debugging hard. + if (err == -EINVAL && ret_pin_user_pages_fast) + ret = ret_pin_user_pages_fast; + else ret = err; goto out; } |