Commit 1810053e authored by Asias He's avatar Asias He Committed by Nicholas Bellinger

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: default avatarAsias He <asias@redhat.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent f3158f36
...@@ -430,40 +430,47 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( ...@@ -430,40 +430,47 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
* Returns the number of scatterlist entries used or -errno on error. * Returns the number of scatterlist entries used or -errno on error.
*/ */
static int vhost_scsi_map_to_sgl(struct scatterlist *sgl, static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
unsigned int sgl_count, void __user *ptr, size_t len, int write) unsigned int sgl_count, struct iovec *iov, int write)
{ {
unsigned int npages = 0, pages_nr, offset, nbytes;
struct scatterlist *sg = sgl; struct scatterlist *sg = sgl;
unsigned int npages = 0; void __user *ptr = iov->iov_base;
int ret; size_t len = iov->iov_len;
struct page **pages;
int ret, i;
while (len > 0) { pages_nr = iov_num_pages(iov);
struct page *page; if (pages_nr > sgl_count)
unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK; return -ENOBUFS;
unsigned int nbytes = min_t(unsigned int,
PAGE_SIZE - offset, len);
if (npages == sgl_count) { pages = kmalloc(pages_nr * sizeof(struct page *), GFP_KERNEL);
ret = -ENOBUFS; if (!pages)
goto err; return -ENOMEM;
}
ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page); ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages);
BUG_ON(ret == 0); /* we should either get our page or fail */ /* No pages were pinned */
if (ret < 0) if (ret < 0)
goto err; goto out;
/* Less pages pinned than wanted */
if (ret != pages_nr) {
for (i = 0; i < ret; i++)
put_page(pages[i]);
ret = -EFAULT;
goto out;
}
sg_set_page(sg, page, nbytes, offset); while (len > 0) {
offset = (uintptr_t)ptr & ~PAGE_MASK;
nbytes = min_t(unsigned int, PAGE_SIZE - offset, len);
sg_set_page(sg, pages[npages], nbytes, offset);
ptr += nbytes; ptr += nbytes;
len -= nbytes; len -= nbytes;
sg++; sg++;
npages++; npages++;
} }
return npages;
err: out:
/* Put pages that we hold */ kfree(pages);
for (sg = sgl; sg != &sgl[npages]; sg++)
put_page(sg_page(sg));
return ret; return ret;
} }
...@@ -496,8 +503,7 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd, ...@@ -496,8 +503,7 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
for (i = 0; i < niov; i++) { for (i = 0; i < niov; i++) {
ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base, ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write);
iov[i].iov_len, write);
if (ret < 0) { if (ret < 0) {
for (i = 0; i < tv_cmd->tvc_sgl_count; i++) for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
put_page(sg_page(&tv_cmd->tvc_sgl[i])); put_page(sg_page(&tv_cmd->tvc_sgl[i]));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment