diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-02-22 21:34:08 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-06-02 15:41:54 -0400 |
commit | 5a01d08217e39f3d36d3ca160361c7b019ff1598 (patch) | |
tree | 15d4b1d9b66bd8e6dce24569c93f718cac1d8bab /drivers/vhost | |
parent | 1b49dcf3d7c765ad18ca7167a0e441824eb1f7af (diff) |
vhost/scsi: Move sanity check into vhost_scsi_map_iov_to_sgl
Move the overflow check for sgl_count > TCM_VHOST_PREALLOC_SGLS into
vhost_scsi_map_iov_to_sgl() so that it's based on the total number
of SGLs for all IOVs, instead of single IOVs.
Also, rename TCM_VHOST_PREALLOC_PAGES -> TCM_VHOST_PREALLOC_UPAGES
to better describe pointers to user-space pages.
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/vhost')
-rw-r--r-- | drivers/vhost/scsi.c | 59 |
1 files changed, 25 insertions, 34 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index cf50ce93975b..ae434db2d384 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
@@ -57,7 +57,7 @@ | |||
57 | #define TCM_VHOST_MAX_CDB_SIZE 32 | 57 | #define TCM_VHOST_MAX_CDB_SIZE 32 |
58 | #define TCM_VHOST_DEFAULT_TAGS 256 | 58 | #define TCM_VHOST_DEFAULT_TAGS 256 |
59 | #define TCM_VHOST_PREALLOC_SGLS 2048 | 59 | #define TCM_VHOST_PREALLOC_SGLS 2048 |
60 | #define TCM_VHOST_PREALLOC_PAGES 2048 | 60 | #define TCM_VHOST_PREALLOC_UPAGES 2048 |
61 | 61 | ||
62 | struct vhost_scsi_inflight { | 62 | struct vhost_scsi_inflight { |
63 | /* Wait for the flush operation to finish */ | 63 | /* Wait for the flush operation to finish */ |
@@ -767,35 +767,28 @@ vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd, | |||
767 | struct scatterlist *sgl, | 767 | struct scatterlist *sgl, |
768 | unsigned int sgl_count, | 768 | unsigned int sgl_count, |
769 | struct iovec *iov, | 769 | struct iovec *iov, |
770 | int write) | 770 | struct page **pages, |
771 | bool write) | ||
771 | { | 772 | { |
772 | unsigned int npages = 0, pages_nr, offset, nbytes; | 773 | unsigned int npages = 0, pages_nr, offset, nbytes; |
773 | struct scatterlist *sg = sgl; | 774 | struct scatterlist *sg = sgl; |
774 | void __user *ptr = iov->iov_base; | 775 | void __user *ptr = iov->iov_base; |
775 | size_t len = iov->iov_len; | 776 | size_t len = iov->iov_len; |
776 | struct page **pages; | ||
777 | int ret, i; | 777 | int ret, i; |
778 | 778 | ||
779 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { | ||
780 | pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than" | ||
781 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
782 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
783 | return -ENOBUFS; | ||
784 | } | ||
785 | |||
786 | pages_nr = iov_num_pages(iov); | 779 | pages_nr = iov_num_pages(iov); |
787 | if (pages_nr > sgl_count) | 780 | if (pages_nr > sgl_count) { |
781 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | ||
782 | " sgl_count: %u\n", pages_nr, sgl_count); | ||
788 | return -ENOBUFS; | 783 | return -ENOBUFS; |
789 | 784 | } | |
790 | if (pages_nr > TCM_VHOST_PREALLOC_PAGES) { | 785 | if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) { |
791 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | 786 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" |
792 | " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n", | 787 | " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n", |
793 | pages_nr, TCM_VHOST_PREALLOC_PAGES); | 788 | pages_nr, TCM_VHOST_PREALLOC_UPAGES); |
794 | return -ENOBUFS; | 789 | return -ENOBUFS; |
795 | } | 790 | } |
796 | 791 | ||
797 | pages = tv_cmd->tvc_upages; | ||
798 | |||
799 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); | 792 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); |
800 | /* No pages were pinned */ | 793 | /* No pages were pinned */ |
801 | if (ret < 0) | 794 | if (ret < 0) |
@@ -825,33 +818,32 @@ out: | |||
825 | static int | 818 | static int |
826 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | 819 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, |
827 | struct iovec *iov, | 820 | struct iovec *iov, |
828 | unsigned int niov, | 821 | int niov, |
829 | int write) | 822 | bool write) |
830 | { | 823 | { |
831 | int ret; | 824 | struct scatterlist *sg = cmd->tvc_sgl; |
832 | unsigned int i; | 825 | unsigned int sgl_count = 0; |
833 | u32 sgl_count; | 826 | int ret, i; |
834 | struct scatterlist *sg; | ||
835 | 827 | ||
836 | /* | ||
837 | * Find out how long sglist needs to be | ||
838 | */ | ||
839 | sgl_count = 0; | ||
840 | for (i = 0; i < niov; i++) | 828 | for (i = 0; i < niov; i++) |
841 | sgl_count += iov_num_pages(&iov[i]); | 829 | sgl_count += iov_num_pages(&iov[i]); |
842 | 830 | ||
843 | /* TODO overflow checking */ | 831 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { |
832 | pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than" | ||
833 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
834 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
835 | return -ENOBUFS; | ||
836 | } | ||
844 | 837 | ||
845 | sg = cmd->tvc_sgl; | ||
846 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); | 838 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); |
847 | sg_init_table(sg, sgl_count); | 839 | sg_init_table(sg, sgl_count); |
848 | |||
849 | cmd->tvc_sgl_count = sgl_count; | 840 | cmd->tvc_sgl_count = sgl_count; |
850 | 841 | ||
851 | pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); | 842 | pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count); |
843 | |||
852 | for (i = 0; i < niov; i++) { | 844 | for (i = 0; i < niov; i++) { |
853 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], | 845 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], |
854 | write); | 846 | cmd->tvc_upages, write); |
855 | if (ret < 0) { | 847 | if (ret < 0) { |
856 | for (i = 0; i < cmd->tvc_sgl_count; i++) | 848 | for (i = 0; i < cmd->tvc_sgl_count; i++) |
857 | put_page(sg_page(&cmd->tvc_sgl[i])); | 849 | put_page(sg_page(&cmd->tvc_sgl[i])); |
@@ -859,7 +851,6 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | |||
859 | cmd->tvc_sgl_count = 0; | 851 | cmd->tvc_sgl_count = 0; |
860 | return ret; | 852 | return ret; |
861 | } | 853 | } |
862 | |||
863 | sg += ret; | 854 | sg += ret; |
864 | sgl_count -= ret; | 855 | sgl_count -= ret; |
865 | } | 856 | } |
@@ -1765,7 +1756,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, | |||
1765 | } | 1756 | } |
1766 | 1757 | ||
1767 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * | 1758 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * |
1768 | TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL); | 1759 | TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL); |
1769 | if (!tv_cmd->tvc_upages) { | 1760 | if (!tv_cmd->tvc_upages) { |
1770 | mutex_unlock(&tpg->tv_tpg_mutex); | 1761 | mutex_unlock(&tpg->tv_tpg_mutex); |
1771 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); | 1762 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); |