aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vhost
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2015-01-28 03:15:00 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2015-02-04 13:55:36 -0500
commite8de56b5e76ab7ed2a4aa3476649fe3fa85de1d7 (patch)
tree395e2c91c7cc0da292a6d484f005681d8f118127 /drivers/vhost
parentb4078b5face3c1e79ef6e2dd254af04a470ed2bc (diff)
vhost/scsi: Add ANY_LAYOUT iov -> sgl mapping prerequisites
This patch adds ANY_LAYOUT prerequisites logic for accepting a set of protection + data payloads via iov_iter. Also includes helpers for calcuating SGLs + invoking vhost_scsi_map_to_sgl() with a known number of iovecs. Required by ANY_LAYOUT processing when struct iovec may be offset into the first outgoing virtio-scsi request header. Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/vhost')
-rw-r--r--drivers/vhost/scsi.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index b9800c7a1d5d..5396b8a3028f 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -914,6 +914,99 @@ vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd,
914 return 0; 914 return 0;
915} 915}
916 916
917static int
918vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
919{
920 int sgl_count = 0;
921
922 if (!iter || !iter->iov) {
923 pr_err("%s: iter->iov is NULL, but expected bytes: %zu"
924 " present\n", __func__, bytes);
925 return -EINVAL;
926 }
927
928 sgl_count = iov_iter_npages(iter, 0xffff);
929 if (sgl_count > max_sgls) {
930 pr_err("%s: requested sgl_count: %d exceeds pre-allocated"
931 " max_sgls: %d\n", __func__, sgl_count, max_sgls);
932 return -EINVAL;
933 }
934 return sgl_count;
935}
936
937static int
938vhost_scsi_iov_to_sgl(struct tcm_vhost_cmd *cmd, bool write,
939 struct iov_iter *iter, struct scatterlist *sg,
940 int sg_count)
941{
942 size_t off = iter->iov_offset;
943 int i, ret;
944
945 for (i = 0; i < iter->nr_segs; i++) {
946 void __user *base = iter->iov[i].iov_base + off;
947 size_t len = iter->iov[i].iov_len - off;
948
949 ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write);
950 if (ret < 0) {
951 for (i = 0; i < sg_count; i++) {
952 struct page *page = sg_page(&sg[i]);
953 if (page)
954 put_page(page);
955 }
956 return ret;
957 }
958 sg += ret;
959 off = 0;
960 }
961 return 0;
962}
963
964static int
965vhost_scsi_mapal(struct tcm_vhost_cmd *cmd,
966 size_t prot_bytes, struct iov_iter *prot_iter,
967 size_t data_bytes, struct iov_iter *data_iter)
968{
969 int sgl_count, ret;
970 bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE);
971
972 if (prot_bytes) {
973 sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
974 TCM_VHOST_PREALLOC_PROT_SGLS);
975 if (sgl_count < 0)
976 return sgl_count;
977
978 sg_init_table(cmd->tvc_prot_sgl, sgl_count);
979 cmd->tvc_prot_sgl_count = sgl_count;
980 pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
981 cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
982
983 ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter,
984 cmd->tvc_prot_sgl,
985 cmd->tvc_prot_sgl_count);
986 if (ret < 0) {
987 cmd->tvc_prot_sgl_count = 0;
988 return ret;
989 }
990 }
991 sgl_count = vhost_scsi_calc_sgls(data_iter, data_bytes,
992 TCM_VHOST_PREALLOC_SGLS);
993 if (sgl_count < 0)
994 return sgl_count;
995
996 sg_init_table(cmd->tvc_sgl, sgl_count);
997 cmd->tvc_sgl_count = sgl_count;
998 pr_debug("%s data_sg %p data_sgl_count %u\n", __func__,
999 cmd->tvc_sgl, cmd->tvc_sgl_count);
1000
1001 ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter,
1002 cmd->tvc_sgl, cmd->tvc_sgl_count);
1003 if (ret < 0) {
1004 cmd->tvc_sgl_count = 0;
1005 return ret;
1006 }
1007 return 0;
1008}
1009
917static void tcm_vhost_submission_work(struct work_struct *work) 1010static void tcm_vhost_submission_work(struct work_struct *work)
918{ 1011{
919 struct tcm_vhost_cmd *cmd = 1012 struct tcm_vhost_cmd *cmd =