aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAsias He <asias@redhat.com>2013-01-21 22:20:27 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-02-13 14:27:41 -0500
commit1810053e8db3fd65f039229bde9e420278994300 (patch)
tree7349d6a077501dfa8cdf66d8eb7df96b82df8d46
parentf3158f362ca8b77b24c5de86cbec347ab2bb6430 (diff)
tcm_vhost: Optimize gup in vhost_scsi_map_to_sgl
We can get all the pages in one time instead of calling gup N times. Signed-off-by: Asias He <asias@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/vhost/tcm_vhost.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
index 62058d7a562f..704e4f674776 100644
--- a/drivers/vhost/tcm_vhost.c
+++ b/drivers/vhost/tcm_vhost.c
@@ -430,40 +430,47 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
430 * Returns the number of scatterlist entries used or -errno on error. 430 * Returns the number of scatterlist entries used or -errno on error.
431 */ 431 */
432static int vhost_scsi_map_to_sgl(struct scatterlist *sgl, 432static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
433 unsigned int sgl_count, void __user *ptr, size_t len, int write) 433 unsigned int sgl_count, struct iovec *iov, int write)
434{ 434{
435 unsigned int npages = 0, pages_nr, offset, nbytes;
435 struct scatterlist *sg = sgl; 436 struct scatterlist *sg = sgl;
436 unsigned int npages = 0; 437 void __user *ptr = iov->iov_base;
437 int ret; 438 size_t len = iov->iov_len;
439 struct page **pages;
440 int ret, i;
438 441
439 while (len > 0) { 442 pages_nr = iov_num_pages(iov);
440 struct page *page; 443 if (pages_nr > sgl_count)
441 unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK; 444 return -ENOBUFS;
442 unsigned int nbytes = min_t(unsigned int,
443 PAGE_SIZE - offset, len);
444 445
445 if (npages == sgl_count) { 446 pages = kmalloc(pages_nr * sizeof(struct page *), GFP_KERNEL);
446 ret = -ENOBUFS; 447 if (!pages)
447 goto err; 448 return -ENOMEM;
448 }
449 449
450 ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page); 450 ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages);
451 BUG_ON(ret == 0); /* we should either get our page or fail */ 451 /* No pages were pinned */
452 if (ret < 0) 452 if (ret < 0)
453 goto err; 453 goto out;
454 /* Less pages pinned than wanted */
455 if (ret != pages_nr) {
456 for (i = 0; i < ret; i++)
457 put_page(pages[i]);
458 ret = -EFAULT;
459 goto out;
460 }
454 461
455 sg_set_page(sg, page, nbytes, offset); 462 while (len > 0) {
463 offset = (uintptr_t)ptr & ~PAGE_MASK;
464 nbytes = min_t(unsigned int, PAGE_SIZE - offset, len);
465 sg_set_page(sg, pages[npages], nbytes, offset);
456 ptr += nbytes; 466 ptr += nbytes;
457 len -= nbytes; 467 len -= nbytes;
458 sg++; 468 sg++;
459 npages++; 469 npages++;
460 } 470 }
461 return npages;
462 471
463err: 472out:
464 /* Put pages that we hold */ 473 kfree(pages);
465 for (sg = sgl; sg != &sgl[npages]; sg++)
466 put_page(sg_page(sg));
467 return ret; 474 return ret;
468} 475}
469 476
@@ -496,8 +503,7 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
496 503
497 pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); 504 pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
498 for (i = 0; i < niov; i++) { 505 for (i = 0; i < niov; i++) {
499 ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base, 506 ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write);
500 iov[i].iov_len, write);
501 if (ret < 0) { 507 if (ret < 0) {
502 for (i = 0; i < tv_cmd->tvc_sgl_count; i++) 508 for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
503 put_page(sg_page(&tv_cmd->tvc_sgl[i])); 509 put_page(sg_page(&tv_cmd->tvc_sgl[i]));