On Wed, Jun 17, 2020 at 4:43 PM Dan Carpenter <dan.carpenter@xxxxxxxxxx> wrote: > > On Wed, Jun 17, 2020 at 07:57:20AM +0530, Souptick Joarder wrote: > > There is a bug, when get_user_pages() failed but partially pinned > > pages are not unpinned. Fixed it. > > > > Also, int is more appropriate type for rv. Changed it. > > > > Signed-off-by: Souptick Joarder <jrdr.linux@xxxxxxxxx> > > Cc: John Hubbard <jhubbard@xxxxxxxxxx> > > Cc: Bharath Vedartham <linux.bhar@xxxxxxxxx> > > Cc: Dan Carpenter <dan.carpenter@xxxxxxxxxx> > > --- > > drivers/staging/kpc2000/kpc_dma/fileops.c | 6 +++++- > > 1 file changed, 5 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/staging/kpc2000/kpc_dma/fileops.c b/drivers/staging/kpc2000/kpc_dma/fileops.c > > index 8975346..b136353 100644 > > --- a/drivers/staging/kpc2000/kpc_dma/fileops.c > > +++ b/drivers/staging/kpc2000/kpc_dma/fileops.c > > @@ -35,7 +35,7 @@ static int kpc_dma_transfer(struct dev_private_data *priv, > > unsigned long iov_base, size_t iov_len) > > { > > unsigned int i = 0; > > - long rv = 0; > > + int rv = 0; > > struct kpc_dma_device *ldev; > > struct aio_cb_data *acd; > > DECLARE_COMPLETION_ONSTACK(done); > > @@ -193,6 +193,10 @@ static int kpc_dma_transfer(struct dev_private_data *priv, > > put_page(acd->user_pages[i]); > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > err_get_user_pages: > > + if (rv > 0) { > > + for (i = 0; i < rv; i++) > > + put_pages(acd->user_pages[i]) > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > + } > > This isn't a complete fix. "rv" is the negative error code but here we > are returning a positive value on this path. In case of error of get_user_pages(), it will return -errno, 0 and 3rd one is (rv > 0 && rv != acd->page_count). When rv is -errno or 0 there is no need to call put_pages() in error path. But for 3rd case partially mapped pages need to unpin. Correct me if I am missing anything. >Also it's ugly to have > same put_page() loop repeated twice. Yes, I agree, but these are intermediate steps. Patch [4/4] of this series finally did the same. > > It would be better to write it like this: > > rv = get_user_pages(iov_base, acd->page_count, FOLL_TOUCH | FOLL_WRITE | FOLL_GET, acd->user_pages, NULL); > mmap_read_unlock(current->mm); /* release the semaphore */ > if (rv < 0) > goto free_pages; > if (rv != acd->page_count) { > acd->page_count = rv; > rv = -EFAULT; > goto put_pages; > } > > ... > > put_pages: > for (i = 0 ; i < acd->page_count ; i++) > put_pages(acd->user_pages[i]); > free_pages: > kfree(acd->user_pages); > > regards, > dan carpenter > _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel