diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-09-24 22:07:59 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-10-11 22:36:55 -0400 |
commit | 2f240c4ae8869907d4c8161ee015bedb366512e2 (patch) | |
tree | c5d4a0f96711386df3da29beca154b553cbb4ca8 | |
parent | 11d49e9d089ccec81be87c2386dfdd010d7f7f6e (diff) |
vhost/scsi: switch to iov_iter_get_pages()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | drivers/vhost/scsi.c | 68 |
1 files changed, 20 insertions, 48 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e47c5bc3ddca..e5b18320f1a3 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
@@ -210,12 +210,6 @@ static struct workqueue_struct *vhost_scsi_workqueue; | |||
210 | static DEFINE_MUTEX(vhost_scsi_mutex); | 210 | static DEFINE_MUTEX(vhost_scsi_mutex); |
211 | static LIST_HEAD(vhost_scsi_list); | 211 | static LIST_HEAD(vhost_scsi_list); |
212 | 212 | ||
213 | static int iov_num_pages(void __user *iov_base, size_t iov_len) | ||
214 | { | ||
215 | return (PAGE_ALIGN((unsigned long)iov_base + iov_len) - | ||
216 | ((unsigned long)iov_base & PAGE_MASK)) >> PAGE_SHIFT; | ||
217 | } | ||
218 | |||
219 | static void vhost_scsi_done_inflight(struct kref *kref) | 213 | static void vhost_scsi_done_inflight(struct kref *kref) |
220 | { | 214 | { |
221 | struct vhost_scsi_inflight *inflight; | 215 | struct vhost_scsi_inflight *inflight; |
@@ -618,48 +612,31 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, | |||
618 | */ | 612 | */ |
619 | static int | 613 | static int |
620 | vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd, | 614 | vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd, |
621 | void __user *ptr, | 615 | struct iov_iter *iter, |
622 | size_t len, | ||
623 | struct scatterlist *sgl, | 616 | struct scatterlist *sgl, |
624 | bool write) | 617 | bool write) |
625 | { | 618 | { |
626 | unsigned int npages = 0, offset, nbytes; | ||
627 | unsigned int pages_nr = iov_num_pages(ptr, len); | ||
628 | struct scatterlist *sg = sgl; | ||
629 | struct page **pages = cmd->tvc_upages; | 619 | struct page **pages = cmd->tvc_upages; |
630 | int ret, i; | 620 | struct scatterlist *sg = sgl; |
631 | 621 | ssize_t bytes; | |
632 | if (pages_nr > VHOST_SCSI_PREALLOC_UPAGES) { | 622 | size_t offset; |
633 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | 623 | unsigned int npages = 0; |
634 | " preallocated VHOST_SCSI_PREALLOC_UPAGES: %u\n", | ||
635 | pages_nr, VHOST_SCSI_PREALLOC_UPAGES); | ||
636 | return -ENOBUFS; | ||
637 | } | ||
638 | 624 | ||
639 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); | 625 | bytes = iov_iter_get_pages(iter, pages, LONG_MAX, |
626 | VHOST_SCSI_PREALLOC_UPAGES, &offset); | ||
640 | /* No pages were pinned */ | 627 | /* No pages were pinned */ |
641 | if (ret < 0) | 628 | if (bytes <= 0) |
642 | goto out; | 629 | return bytes < 0 ? bytes : -EFAULT; |
643 | /* Less pages pinned than wanted */ | ||
644 | if (ret != pages_nr) { | ||
645 | for (i = 0; i < ret; i++) | ||
646 | put_page(pages[i]); | ||
647 | ret = -EFAULT; | ||
648 | goto out; | ||
649 | } | ||
650 | 630 | ||
651 | while (len > 0) { | 631 | iov_iter_advance(iter, bytes); |
652 | offset = (uintptr_t)ptr & ~PAGE_MASK; | ||
653 | nbytes = min_t(unsigned int, PAGE_SIZE - offset, len); | ||
654 | sg_set_page(sg, pages[npages], nbytes, offset); | ||
655 | ptr += nbytes; | ||
656 | len -= nbytes; | ||
657 | sg++; | ||
658 | npages++; | ||
659 | } | ||
660 | 632 | ||
661 | out: | 633 | while (bytes) { |
662 | return ret; | 634 | unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes); |
635 | sg_set_page(sg++, pages[npages++], n, offset); | ||
636 | bytes -= n; | ||
637 | offset = 0; | ||
638 | } | ||
639 | return npages; | ||
663 | } | 640 | } |
664 | 641 | ||
665 | static int | 642 | static int |
@@ -687,15 +664,11 @@ vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, | |||
687 | struct iov_iter *iter, | 664 | struct iov_iter *iter, |
688 | struct scatterlist *sg, int sg_count) | 665 | struct scatterlist *sg, int sg_count) |
689 | { | 666 | { |
690 | size_t off = iter->iov_offset; | ||
691 | struct scatterlist *p = sg; | 667 | struct scatterlist *p = sg; |
692 | int i, ret; | 668 | int ret; |
693 | |||
694 | for (i = 0; i < iter->nr_segs; i++) { | ||
695 | void __user *base = iter->iov[i].iov_base + off; | ||
696 | size_t len = iter->iov[i].iov_len - off; | ||
697 | 669 | ||
698 | ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write); | 670 | while (iov_iter_count(iter)) { |
671 | ret = vhost_scsi_map_to_sgl(cmd, iter, sg, write); | ||
699 | if (ret < 0) { | 672 | if (ret < 0) { |
700 | while (p < sg) { | 673 | while (p < sg) { |
701 | struct page *page = sg_page(p++); | 674 | struct page *page = sg_page(p++); |
@@ -705,7 +678,6 @@ vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, | |||
705 | return ret; | 678 | return ret; |
706 | } | 679 | } |
707 | sg += ret; | 680 | sg += ret; |
708 | off = 0; | ||
709 | } | 681 | } |
710 | return 0; | 682 | return 0; |
711 | } | 683 | } |