diff options
| author | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-01-28 03:15:00 -0500 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-02-04 13:55:36 -0500 |
| commit | e8de56b5e76ab7ed2a4aa3476649fe3fa85de1d7 (patch) | |
| tree | 395e2c91c7cc0da292a6d484f005681d8f118127 /drivers/vhost | |
| parent | b4078b5face3c1e79ef6e2dd254af04a470ed2bc (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.c | 93 |
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 | ||
| 917 | static int | ||
| 918 | vhost_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 | |||
| 937 | static int | ||
| 938 | vhost_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 | |||
| 964 | static int | ||
| 965 | vhost_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 | |||
| 917 | static void tcm_vhost_submission_work(struct work_struct *work) | 1010 | static void tcm_vhost_submission_work(struct work_struct *work) |
| 918 | { | 1011 | { |
| 919 | struct tcm_vhost_cmd *cmd = | 1012 | struct tcm_vhost_cmd *cmd = |
