aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-06-21 17:32:04 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-09-09 17:29:19 -0400
commit3aee26b4ae91048c933dc622f00b7bb01f7f0ff1 (patch)
treec20fcf58cf50fc2803601872aecb866de860c28e /drivers
parent4824d3bfb9097ac59cf7633c0bc4fb7c5b549a80 (diff)
vhost/scsi: Add pre-allocation for tv_cmd SGL + upages memory
This patch adds support for pre-allocation of per tv_cmd descriptor scatterlist + user-space page pointer memory using se_sess->sess_cmd_map within tcm_vhost_make_nexus() code. This includes sanity checks within vhost_scsi_map_to_sgl() to reject I/O that exceeds these initial hardcoded values, and the necessary cleanup in tcm_vhost_make_nexus() failure path + tcm_vhost_drop_nexus(). v3 changes: - Rebase to v3.11-rc5 code Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Asias He <asias@redhat.com> Cc: Kent Overstreet <kmo@daterainc.com> Reviewed-by: Asias He <asias@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/vhost/scsi.c99
1 files changed, 80 insertions, 19 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 8cd545ad3f51..d52a3a063be0 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -56,6 +56,8 @@
56#define TCM_VHOST_NAMELEN 256 56#define TCM_VHOST_NAMELEN 256
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
60#define TCM_VHOST_PREALLOC_PAGES 2048
59 61
60struct vhost_scsi_inflight { 62struct vhost_scsi_inflight {
61 /* Wait for the flush operation to finish */ 63 /* Wait for the flush operation to finish */
@@ -81,6 +83,7 @@ struct tcm_vhost_cmd {
81 u32 tvc_lun; 83 u32 tvc_lun;
82 /* Pointer to the SGL formatted memory from virtio-scsi */ 84 /* Pointer to the SGL formatted memory from virtio-scsi */
83 struct scatterlist *tvc_sgl; 85 struct scatterlist *tvc_sgl;
86 struct page **tvc_upages;
84 /* Pointer to response */ 87 /* Pointer to response */
85 struct virtio_scsi_cmd_resp __user *tvc_resp; 88 struct virtio_scsi_cmd_resp __user *tvc_resp;
86 /* Pointer to vhost_scsi for our device */ 89 /* Pointer to vhost_scsi for our device */
@@ -458,8 +461,6 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
458 u32 i; 461 u32 i;
459 for (i = 0; i < tv_cmd->tvc_sgl_count; i++) 462 for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
460 put_page(sg_page(&tv_cmd->tvc_sgl[i])); 463 put_page(sg_page(&tv_cmd->tvc_sgl[i]));
461
462 kfree(tv_cmd->tvc_sgl);
463 } 464 }
464 465
465 tcm_vhost_put_inflight(tv_cmd->inflight); 466 tcm_vhost_put_inflight(tv_cmd->inflight);
@@ -716,6 +717,8 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
716 struct tcm_vhost_cmd *cmd; 717 struct tcm_vhost_cmd *cmd;
717 struct tcm_vhost_nexus *tv_nexus; 718 struct tcm_vhost_nexus *tv_nexus;
718 struct se_session *se_sess; 719 struct se_session *se_sess;
720 struct scatterlist *sg;
721 struct page **pages;
719 int tag; 722 int tag;
720 723
721 tv_nexus = tpg->tpg_nexus; 724 tv_nexus = tpg->tpg_nexus;
@@ -727,8 +730,12 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
727 730
728 tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL); 731 tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL);
729 cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; 732 cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
733 sg = cmd->tvc_sgl;
734 pages = cmd->tvc_upages;
730 memset(cmd, 0, sizeof(struct tcm_vhost_cmd)); 735 memset(cmd, 0, sizeof(struct tcm_vhost_cmd));
731 736
737 cmd->tvc_sgl = sg;
738 cmd->tvc_upages = pages;
732 cmd->tvc_se_cmd.map_tag = tag; 739 cmd->tvc_se_cmd.map_tag = tag;
733 cmd->tvc_tag = v_req->tag; 740 cmd->tvc_tag = v_req->tag;
734 cmd->tvc_task_attr = v_req->task_attr; 741 cmd->tvc_task_attr = v_req->task_attr;
@@ -746,7 +753,8 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
746 * Returns the number of scatterlist entries used or -errno on error. 753 * Returns the number of scatterlist entries used or -errno on error.
747 */ 754 */
748static int 755static int
749vhost_scsi_map_to_sgl(struct scatterlist *sgl, 756vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd,
757 struct scatterlist *sgl,
750 unsigned int sgl_count, 758 unsigned int sgl_count,
751 struct iovec *iov, 759 struct iovec *iov,
752 int write) 760 int write)
@@ -758,13 +766,25 @@ vhost_scsi_map_to_sgl(struct scatterlist *sgl,
758 struct page **pages; 766 struct page **pages;
759 int ret, i; 767 int ret, i;
760 768
769 if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
770 pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than"
771 " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
772 sgl_count, TCM_VHOST_PREALLOC_SGLS);
773 return -ENOBUFS;
774 }
775
761 pages_nr = iov_num_pages(iov); 776 pages_nr = iov_num_pages(iov);
762 if (pages_nr > sgl_count) 777 if (pages_nr > sgl_count)
763 return -ENOBUFS; 778 return -ENOBUFS;
764 779
765 pages = kmalloc(pages_nr * sizeof(struct page *), GFP_KERNEL); 780 if (pages_nr > TCM_VHOST_PREALLOC_PAGES) {
766 if (!pages) 781 pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
767 return -ENOMEM; 782 " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n",
783 pages_nr, TCM_VHOST_PREALLOC_PAGES);
784 return -ENOBUFS;
785 }
786
787 pages = tv_cmd->tvc_upages;
768 788
769 ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); 789 ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages);
770 /* No pages were pinned */ 790 /* No pages were pinned */
@@ -789,7 +809,6 @@ vhost_scsi_map_to_sgl(struct scatterlist *sgl,
789 } 809 }
790 810
791out: 811out:
792 kfree(pages);
793 return ret; 812 return ret;
794} 813}
795 814
@@ -813,24 +832,20 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
813 832
814 /* TODO overflow checking */ 833 /* TODO overflow checking */
815 834
816 sg = kmalloc(sizeof(cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC); 835 sg = cmd->tvc_sgl;
817 if (!sg) 836 pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count);
818 return -ENOMEM;
819 pr_debug("%s sg %p sgl_count %u is_err %d\n", __func__,
820 sg, sgl_count, !sg);
821 sg_init_table(sg, sgl_count); 837 sg_init_table(sg, sgl_count);
822 838
823 cmd->tvc_sgl = sg;
824 cmd->tvc_sgl_count = sgl_count; 839 cmd->tvc_sgl_count = sgl_count;
825 840
826 pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); 841 pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
827 for (i = 0; i < niov; i++) { 842 for (i = 0; i < niov; i++) {
828 ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write); 843 ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i],
844 write);
829 if (ret < 0) { 845 if (ret < 0) {
830 for (i = 0; i < cmd->tvc_sgl_count; i++) 846 for (i = 0; i < cmd->tvc_sgl_count; i++)
831 put_page(sg_page(&cmd->tvc_sgl[i])); 847 put_page(sg_page(&cmd->tvc_sgl[i]));
832 kfree(cmd->tvc_sgl); 848
833 cmd->tvc_sgl = NULL;
834 cmd->tvc_sgl_count = 0; 849 cmd->tvc_sgl_count = 0;
835 return ret; 850 return ret;
836 } 851 }
@@ -1660,11 +1675,31 @@ static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
1660 kfree(nacl); 1675 kfree(nacl);
1661} 1676}
1662 1677
1678static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
1679 struct se_session *se_sess)
1680{
1681 struct tcm_vhost_cmd *tv_cmd;
1682 unsigned int i;
1683
1684 if (!se_sess->sess_cmd_map)
1685 return;
1686
1687 for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
1688 tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
1689
1690 kfree(tv_cmd->tvc_sgl);
1691 kfree(tv_cmd->tvc_upages);
1692 }
1693}
1694
1663static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, 1695static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
1664 const char *name) 1696 const char *name)
1665{ 1697{
1666 struct se_portal_group *se_tpg; 1698 struct se_portal_group *se_tpg;
1699 struct se_session *se_sess;
1667 struct tcm_vhost_nexus *tv_nexus; 1700 struct tcm_vhost_nexus *tv_nexus;
1701 struct tcm_vhost_cmd *tv_cmd;
1702 unsigned int i;
1668 1703
1669 mutex_lock(&tpg->tv_tpg_mutex); 1704 mutex_lock(&tpg->tv_tpg_mutex);
1670 if (tpg->tpg_nexus) { 1705 if (tpg->tpg_nexus) {
@@ -1692,6 +1727,26 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
1692 kfree(tv_nexus); 1727 kfree(tv_nexus);
1693 return -ENOMEM; 1728 return -ENOMEM;
1694 } 1729 }
1730 se_sess = tv_nexus->tvn_se_sess;
1731 for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
1732 tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
1733
1734 tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) *
1735 TCM_VHOST_PREALLOC_SGLS, GFP_KERNEL);
1736 if (!tv_cmd->tvc_sgl) {
1737 mutex_unlock(&tpg->tv_tpg_mutex);
1738 pr_err("Unable to allocate tv_cmd->tvc_sgl\n");
1739 goto out;
1740 }
1741
1742 tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) *
1743 TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL);
1744 if (!tv_cmd->tvc_upages) {
1745 mutex_unlock(&tpg->tv_tpg_mutex);
1746 pr_err("Unable to allocate tv_cmd->tvc_upages\n");
1747 goto out;
1748 }
1749 }
1695 /* 1750 /*
1696 * Since we are running in 'demo mode' this call with generate a 1751 * Since we are running in 'demo mode' this call with generate a
1697 * struct se_node_acl for the tcm_vhost struct se_portal_group with 1752 * struct se_node_acl for the tcm_vhost struct se_portal_group with
@@ -1703,9 +1758,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
1703 mutex_unlock(&tpg->tv_tpg_mutex); 1758 mutex_unlock(&tpg->tv_tpg_mutex);
1704 pr_debug("core_tpg_check_initiator_node_acl() failed" 1759 pr_debug("core_tpg_check_initiator_node_acl() failed"
1705 " for %s\n", name); 1760 " for %s\n", name);
1706 transport_free_session(tv_nexus->tvn_se_sess); 1761 goto out;
1707 kfree(tv_nexus);
1708 return -ENOMEM;
1709 } 1762 }
1710 /* 1763 /*
1711 * Now register the TCM vhost virtual I_T Nexus as active with the 1764 * Now register the TCM vhost virtual I_T Nexus as active with the
@@ -1717,6 +1770,12 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
1717 1770
1718 mutex_unlock(&tpg->tv_tpg_mutex); 1771 mutex_unlock(&tpg->tv_tpg_mutex);
1719 return 0; 1772 return 0;
1773
1774out:
1775 tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
1776 transport_free_session(se_sess);
1777 kfree(tv_nexus);
1778 return -ENOMEM;
1720} 1779}
1721 1780
1722static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg) 1781static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
@@ -1756,6 +1815,8 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
1756 pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated" 1815 pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
1757 " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport), 1816 " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
1758 tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 1817 tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
1818
1819 tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
1759 /* 1820 /*
1760 * Release the SCSI I_T Nexus to the emulated vhost Target Port 1821 * Release the SCSI I_T Nexus to the emulated vhost Target Port
1761 */ 1822 */