diff options
author | Hans Verkuil <hverkuil-cisco@xs4all.nl> | 2021-11-11 11:56:29 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-11-30 12:07:36 +0100 |
commit | 89ab2d39643e5ce2b122baa1e76176d1bd984cec (patch) | |
tree | 87c7a55e7d9a965ba12a67b332963f2cf74d7168 /drivers/media/common | |
parent | fadecf79cf8ef9bd3b8dcd0a82455b2c94c4d5c7 (diff) | |
download | linux-89ab2d39643e5ce2b122baa1e76176d1bd984cec.tar.bz2 |
media: vb2: frame_vector.c: don't overwrite error code
get_vaddr_frames() first calls pin_user_pages_fast() and if
that fails tries follow_pfn(). But if that also fails, then
the error code from pin_user_pages_fast() is overwritten with
the error code from follow_pfn().
Specifically if pin_user_pages_fast() returns -ENOMEM, then
follow_pfn() will overwrite that with -EINVAL, which is very
confusing.
So store the error code from pin_user_pages_fast() and return
that if follow_pfn() returns -EINVAL. -EINVAL indicates that
the page is unsuitable for follow_pfn, so pin_user_pages_fast()
was the correct call to make, and that error code should be
returned instead.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/common')
-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; } |