On Tue, Jun 30, 2020 at 01:22:19PM +0530, Souptick Joarder wrote: > As 3 goto level referring to same common code, those can be > accomodated with a single goto level and renameing it to > unpin_pages. Set the -ERRNO when returning partial mapped > pages in more appropriate place. > > 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 | 24 ++++++++++++------------ > 1 file changed, 12 insertions(+), 12 deletions(-) > > diff --git a/drivers/staging/kpc2000/kpc_dma/fileops.c b/drivers/staging/kpc2000/kpc_dma/fileops.c > index 8cd20ad..d21a4fd 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; > - int rv = 0; > + int rv = 0, nr_pages = 0; > struct kpc_dma_device *ldev; > struct aio_cb_data *acd; > DECLARE_COMPLETION_ONSTACK(done); > @@ -79,22 +79,27 @@ static int kpc_dma_transfer(struct dev_private_data *priv, > rv = pin_user_pages(iov_base, acd->page_count, FOLL_TOUCH | FOLL_WRITE, acd->user_pages, NULL); > mmap_read_unlock(current->mm); /* release the semaphore */ > if (rv != acd->page_count) { > + nr_pages = rv; > + if (rv > 0) > + rv = -EFAULT; > + > dev_err(&priv->ldev->pldev->dev, "Couldn't pin_user_pages (%d)\n", rv); > - goto err_get_user_pages; > + goto unpin_pages; > } > + nr_pages = acd->page_count; > > // Allocate and setup the sg_table (scatterlist entries) > rv = sg_alloc_table_from_pages(&acd->sgt, acd->user_pages, acd->page_count, iov_base & (PAGE_SIZE - 1), iov_len, GFP_KERNEL); > if (rv) { > dev_err(&priv->ldev->pldev->dev, "Couldn't alloc sg_table (%d)\n", rv); > - goto err_alloc_sg_table; > + goto unpin_pages; > } > > // Setup the DMA mapping for all the sg entries > acd->mapped_entry_count = dma_map_sg(&ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, ldev->dir); > if (acd->mapped_entry_count <= 0) { > dev_err(&priv->ldev->pldev->dev, "Couldn't dma_map_sg (%d)\n", acd->mapped_entry_count); > - goto err_dma_map_sg; > + goto unpin_pages; This wasn't introduced by your patch but the most recent successful allocation is sg_alloc_table_from_pages() so this should be goto free_table: free_table: sg_free_table(&acd->sgt); unpin_pages: if (nr_pages > 0) unpin_user_pages(acd->user_pages, nr_pages); Always just keep track of the most recent allocation and check that the "goto free_foo" matches what you would expect to release the most recent thing. > } > > // Calculate how many descriptors are actually needed for this transfer. > @@ -187,15 +192,10 @@ static int kpc_dma_transfer(struct dev_private_data *priv, > unlock_engine(ldev); > dma_unmap_sg(&ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, ldev->dir); > sg_free_table(&acd->sgt); ^^^^^^^^^^^^^^^^^^^^^^^^ > - err_dma_map_sg: > - err_alloc_sg_table: > - unpin_user_pages(acd->user_pages, acd->page_count); > > - err_get_user_pages: > - if (rv > 0) { > - unpin_user_pages(acd->user_pages, rv); > - rv = -EFAULT; > - } > + unpin_pages: > + if (nr_pages > 0) > + unpin_user_pages(acd->user_pages, nr_pages); > kfree(acd->user_pages); > err_alloc_userpages: > kfree(acd); regards, dan carpenter _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel