Skip to content

Commit c0562d5

Browse files
Souptick Joardergregkh
authored andcommitted
drivers/virt/fsl_hypervisor: Fix error handling path
[ Upstream commit 7f360bec37857bfd5a48cef21d86f58a09a3df63 ] First, when memory allocation for sg_list_unaligned failed, there is a bug of calling put_pages() as we haven't pinned any pages. Second, if get_user_pages_fast() failed we should unpin num_pinned pages. This will address both. As part of these changes, minor update in documentation. Fixes: 6db7199 ("drivers/virt: introduce Freescale hypervisor management driver") Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com> Reviewed-by: John Hubbard <jhubbard@nvidia.com> Link: https://lore.kernel.org/r/1598995271-6755-1-git-send-email-jrdr.linux@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 8908ffa commit c0562d5

File tree

1 file changed

+8
-9
lines changed

1 file changed

+8
-9
lines changed

drivers/virt/fsl_hypervisor.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
157157

158158
unsigned int i;
159159
long ret = 0;
160-
int num_pinned; /* return value from get_user_pages() */
160+
int num_pinned = 0; /* return value from get_user_pages_fast() */
161161
phys_addr_t remote_paddr; /* The next address in the remote buffer */
162162
uint32_t count; /* The number of bytes left to copy */
163163

@@ -174,7 +174,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
174174
return -EINVAL;
175175

176176
/*
177-
* The array of pages returned by get_user_pages() covers only
177+
* The array of pages returned by get_user_pages_fast() covers only
178178
* page-aligned memory. Since the user buffer is probably not
179179
* page-aligned, we need to handle the discrepancy.
180180
*
@@ -224,7 +224,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
224224

225225
/*
226226
* 'pages' is an array of struct page pointers that's initialized by
227-
* get_user_pages().
227+
* get_user_pages_fast().
228228
*/
229229
pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL);
230230
if (!pages) {
@@ -241,7 +241,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
241241
if (!sg_list_unaligned) {
242242
pr_debug("fsl-hv: could not allocate S/G list\n");
243243
ret = -ENOMEM;
244-
goto exit;
244+
goto free_pages;
245245
}
246246
sg_list = PTR_ALIGN(sg_list_unaligned, sizeof(struct fh_sg_list));
247247

@@ -254,7 +254,6 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
254254
up_read(&current->mm->mmap_sem);
255255

256256
if (num_pinned != num_pages) {
257-
/* get_user_pages() failed */
258257
pr_debug("fsl-hv: could not lock source buffer\n");
259258
ret = (num_pinned < 0) ? num_pinned : -EFAULT;
260259
goto exit;
@@ -296,13 +295,13 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
296295
virt_to_phys(sg_list), num_pages);
297296

298297
exit:
299-
if (pages) {
300-
for (i = 0; i < num_pages; i++)
301-
if (pages[i])
302-
put_page(pages[i]);
298+
if (pages && (num_pinned > 0)) {
299+
for (i = 0; i < num_pinned; i++)
300+
put_page(pages[i]);
303301
}
304302

305303
kfree(sg_list_unaligned);
304+
free_pages:
306305
kfree(pages);
307306

308307
if (!ret)

0 commit comments

Comments
 (0)