diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-30 16:30:00 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-08-16 20:33:40 -0400 |
commit | 101998f6fcd680ed12d85633b81504feb1cb0667 (patch) | |
tree | e2d323c4e7a2f09cadd675d59e003330130c6563 /drivers/vhost | |
parent | f0e0e9bba5eed2086f6001be14f21566a49bed10 (diff) |
tcm_vhost: Post-merge review changes requested by MST
This patch contains the post RFC-v5 (post-merge) changes, this includes:
- Add locking comment
- Move vhost_scsi_complete_cmd ahead of TFO callbacks in order to
drop forward declarations
- Drop extra '!= NULL' usage in vhost_scsi_complete_cmd_work()
- Change vhost_scsi_*_handle_kick() to use pr_debug
- Fix possible race in vhost_scsi_set_endpoint() for vs->vs_tpg checking
+ assignment.
- Convert tv_tpg->tpg_vhost_count + ->tv_tpg_port_count from atomic_t ->
int, and make sure reference is protected by ->tv_tpg_mutex.
- Drop unnecessary vhost_scsi->vhost_ref_cnt
- Add 'err:' label for exception path in vhost_scsi_clear_endpoint()
- Add enum for VQ numbers, add usage in vhost_scsi_open()
- Add vhost_scsi_flush() + vhost_scsi_flush_vq() following
drivers/vhost/net.c
- Add smp_wmb() + vhost_scsi_flush() call during vhost_scsi_set_features()
- Drop unnecessary copy_from_user() usage with GET_ABI_VERSION ioctl
- Add missing vhost_scsi_compat_ioctl() caller for vhost_scsi_fops
- Fix function parameter definition first line to follow existing
vhost code style
- Change 'vHost' usage -> 'vhost' in handful of locations
- Change -EPERM -> -EBUSY usage for two failures in tcm_vhost_drop_nexus()
- Add comment for tcm_vhost_workqueue in tcm_vhost_init()
- Make GET_ABI_VERSION return 'int' + add comment in tcm_vhost.h
Reported-by: Michael S. Tsirkin <mst@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Zhi Yong Wu <wuzhy@cn.ibm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/vhost')
-rw-r--r-- | drivers/vhost/tcm_vhost.c | 195 | ||||
-rw-r--r-- | drivers/vhost/tcm_vhost.h | 9 |
2 files changed, 111 insertions, 93 deletions
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index 481af88a5ff5..74b2edaaf1f6 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c | |||
@@ -53,9 +53,14 @@ | |||
53 | #include "vhost.h" | 53 | #include "vhost.h" |
54 | #include "tcm_vhost.h" | 54 | #include "tcm_vhost.h" |
55 | 55 | ||
56 | enum { | ||
57 | VHOST_SCSI_VQ_CTL = 0, | ||
58 | VHOST_SCSI_VQ_EVT = 1, | ||
59 | VHOST_SCSI_VQ_IO = 2, | ||
60 | }; | ||
61 | |||
56 | struct vhost_scsi { | 62 | struct vhost_scsi { |
57 | atomic_t vhost_ref_cnt; | 63 | struct tcm_vhost_tpg *vs_tpg; /* Protected by vhost_scsi->dev.mutex */ |
58 | struct tcm_vhost_tpg *vs_tpg; | ||
59 | struct vhost_dev dev; | 64 | struct vhost_dev dev; |
60 | struct vhost_virtqueue vqs[3]; | 65 | struct vhost_virtqueue vqs[3]; |
61 | 66 | ||
@@ -131,8 +136,7 @@ static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg) | |||
131 | return 1; | 136 | return 1; |
132 | } | 137 | } |
133 | 138 | ||
134 | static u32 tcm_vhost_get_pr_transport_id( | 139 | static u32 tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg, |
135 | struct se_portal_group *se_tpg, | ||
136 | struct se_node_acl *se_nacl, | 140 | struct se_node_acl *se_nacl, |
137 | struct t10_pr_registration *pr_reg, | 141 | struct t10_pr_registration *pr_reg, |
138 | int *format_code, | 142 | int *format_code, |
@@ -162,8 +166,7 @@ static u32 tcm_vhost_get_pr_transport_id( | |||
162 | format_code, buf); | 166 | format_code, buf); |
163 | } | 167 | } |
164 | 168 | ||
165 | static u32 tcm_vhost_get_pr_transport_id_len( | 169 | static u32 tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg, |
166 | struct se_portal_group *se_tpg, | ||
167 | struct se_node_acl *se_nacl, | 170 | struct se_node_acl *se_nacl, |
168 | struct t10_pr_registration *pr_reg, | 171 | struct t10_pr_registration *pr_reg, |
169 | int *format_code) | 172 | int *format_code) |
@@ -192,8 +195,7 @@ static u32 tcm_vhost_get_pr_transport_id_len( | |||
192 | format_code); | 195 | format_code); |
193 | } | 196 | } |
194 | 197 | ||
195 | static char *tcm_vhost_parse_pr_out_transport_id( | 198 | static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg, |
196 | struct se_portal_group *se_tpg, | ||
197 | const char *buf, | 199 | const char *buf, |
198 | u32 *out_tid_len, | 200 | u32 *out_tid_len, |
199 | char **port_nexus_ptr) | 201 | char **port_nexus_ptr) |
@@ -236,8 +238,7 @@ static struct se_node_acl *tcm_vhost_alloc_fabric_acl( | |||
236 | return &nacl->se_node_acl; | 238 | return &nacl->se_node_acl; |
237 | } | 239 | } |
238 | 240 | ||
239 | static void tcm_vhost_release_fabric_acl( | 241 | static void tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg, |
240 | struct se_portal_group *se_tpg, | ||
241 | struct se_node_acl *se_nacl) | 242 | struct se_node_acl *se_nacl) |
242 | { | 243 | { |
243 | struct tcm_vhost_nacl *nacl = container_of(se_nacl, | 244 | struct tcm_vhost_nacl *nacl = container_of(se_nacl, |
@@ -297,7 +298,16 @@ static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd) | |||
297 | return 0; | 298 | return 0; |
298 | } | 299 | } |
299 | 300 | ||
300 | static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *); | 301 | static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd) |
302 | { | ||
303 | struct vhost_scsi *vs = tv_cmd->tvc_vhost; | ||
304 | |||
305 | spin_lock_bh(&vs->vs_completion_lock); | ||
306 | list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); | ||
307 | spin_unlock_bh(&vs->vs_completion_lock); | ||
308 | |||
309 | vhost_work_queue(&vs->dev, &vs->vs_completion_work); | ||
310 | } | ||
301 | 311 | ||
302 | static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd) | 312 | static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd) |
303 | { | 313 | { |
@@ -381,7 +391,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) | |||
381 | vs_completion_work); | 391 | vs_completion_work); |
382 | struct tcm_vhost_cmd *tv_cmd; | 392 | struct tcm_vhost_cmd *tv_cmd; |
383 | 393 | ||
384 | while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs)) != NULL) { | 394 | while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs))) { |
385 | struct virtio_scsi_cmd_resp v_rsp; | 395 | struct virtio_scsi_cmd_resp v_rsp; |
386 | struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; | 396 | struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; |
387 | int ret; | 397 | int ret; |
@@ -408,19 +418,6 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) | |||
408 | vhost_signal(&vs->dev, &vs->vqs[2]); | 418 | vhost_signal(&vs->dev, &vs->vqs[2]); |
409 | } | 419 | } |
410 | 420 | ||
411 | static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd) | ||
412 | { | ||
413 | struct vhost_scsi *vs = tv_cmd->tvc_vhost; | ||
414 | |||
415 | pr_debug("%s tv_cmd %p\n", __func__, tv_cmd); | ||
416 | |||
417 | spin_lock_bh(&vs->vs_completion_lock); | ||
418 | list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); | ||
419 | spin_unlock_bh(&vs->vs_completion_lock); | ||
420 | |||
421 | vhost_work_queue(&vs->dev, &vs->vs_completion_work); | ||
422 | } | ||
423 | |||
424 | static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( | 421 | static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( |
425 | struct tcm_vhost_tpg *tv_tpg, | 422 | struct tcm_vhost_tpg *tv_tpg, |
426 | struct virtio_scsi_cmd_req *v_req, | 423 | struct virtio_scsi_cmd_req *v_req, |
@@ -787,12 +784,12 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | |||
787 | 784 | ||
788 | static void vhost_scsi_ctl_handle_kick(struct vhost_work *work) | 785 | static void vhost_scsi_ctl_handle_kick(struct vhost_work *work) |
789 | { | 786 | { |
790 | pr_err("%s: The handling func for control queue.\n", __func__); | 787 | pr_debug("%s: The handling func for control queue.\n", __func__); |
791 | } | 788 | } |
792 | 789 | ||
793 | static void vhost_scsi_evt_handle_kick(struct vhost_work *work) | 790 | static void vhost_scsi_evt_handle_kick(struct vhost_work *work) |
794 | { | 791 | { |
795 | pr_err("%s: The handling func for event queue.\n", __func__); | 792 | pr_debug("%s: The handling func for event queue.\n", __func__); |
796 | } | 793 | } |
797 | 794 | ||
798 | static void vhost_scsi_handle_kick(struct vhost_work *work) | 795 | static void vhost_scsi_handle_kick(struct vhost_work *work) |
@@ -825,11 +822,6 @@ static int vhost_scsi_set_endpoint( | |||
825 | return -EFAULT; | 822 | return -EFAULT; |
826 | } | 823 | } |
827 | } | 824 | } |
828 | |||
829 | if (vs->vs_tpg) { | ||
830 | mutex_unlock(&vs->dev.mutex); | ||
831 | return -EEXIST; | ||
832 | } | ||
833 | mutex_unlock(&vs->dev.mutex); | 825 | mutex_unlock(&vs->dev.mutex); |
834 | 826 | ||
835 | mutex_lock(&tcm_vhost_mutex); | 827 | mutex_lock(&tcm_vhost_mutex); |
@@ -839,7 +831,7 @@ static int vhost_scsi_set_endpoint( | |||
839 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 831 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
840 | continue; | 832 | continue; |
841 | } | 833 | } |
842 | if (atomic_read(&tv_tpg->tv_tpg_vhost_count)) { | 834 | if (tv_tpg->tv_tpg_vhost_count != 0) { |
843 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 835 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
844 | continue; | 836 | continue; |
845 | } | 837 | } |
@@ -847,14 +839,20 @@ static int vhost_scsi_set_endpoint( | |||
847 | 839 | ||
848 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) && | 840 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) && |
849 | (tv_tpg->tport_tpgt == t->vhost_tpgt)) { | 841 | (tv_tpg->tport_tpgt == t->vhost_tpgt)) { |
850 | atomic_inc(&tv_tpg->tv_tpg_vhost_count); | 842 | tv_tpg->tv_tpg_vhost_count++; |
851 | smp_mb__after_atomic_inc(); | ||
852 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 843 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
853 | mutex_unlock(&tcm_vhost_mutex); | 844 | mutex_unlock(&tcm_vhost_mutex); |
854 | 845 | ||
855 | mutex_lock(&vs->dev.mutex); | 846 | mutex_lock(&vs->dev.mutex); |
847 | if (vs->vs_tpg) { | ||
848 | mutex_unlock(&vs->dev.mutex); | ||
849 | mutex_lock(&tv_tpg->tv_tpg_mutex); | ||
850 | tv_tpg->tv_tpg_vhost_count--; | ||
851 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | ||
852 | return -EEXIST; | ||
853 | } | ||
854 | |||
856 | vs->vs_tpg = tv_tpg; | 855 | vs->vs_tpg = tv_tpg; |
857 | atomic_inc(&vs->vhost_ref_cnt); | ||
858 | smp_mb__after_atomic_inc(); | 856 | smp_mb__after_atomic_inc(); |
859 | mutex_unlock(&vs->dev.mutex); | 857 | mutex_unlock(&vs->dev.mutex); |
860 | return 0; | 858 | return 0; |
@@ -871,38 +869,42 @@ static int vhost_scsi_clear_endpoint( | |||
871 | { | 869 | { |
872 | struct tcm_vhost_tport *tv_tport; | 870 | struct tcm_vhost_tport *tv_tport; |
873 | struct tcm_vhost_tpg *tv_tpg; | 871 | struct tcm_vhost_tpg *tv_tpg; |
874 | int index; | 872 | int index, ret; |
875 | 873 | ||
876 | mutex_lock(&vs->dev.mutex); | 874 | mutex_lock(&vs->dev.mutex); |
877 | /* Verify that ring has been setup correctly. */ | 875 | /* Verify that ring has been setup correctly. */ |
878 | for (index = 0; index < vs->dev.nvqs; ++index) { | 876 | for (index = 0; index < vs->dev.nvqs; ++index) { |
879 | if (!vhost_vq_access_ok(&vs->vqs[index])) { | 877 | if (!vhost_vq_access_ok(&vs->vqs[index])) { |
880 | mutex_unlock(&vs->dev.mutex); | 878 | ret = -EFAULT; |
881 | return -EFAULT; | 879 | goto err; |
882 | } | 880 | } |
883 | } | 881 | } |
884 | 882 | ||
885 | if (!vs->vs_tpg) { | 883 | if (!vs->vs_tpg) { |
886 | mutex_unlock(&vs->dev.mutex); | 884 | ret = -ENODEV; |
887 | return -ENODEV; | 885 | goto err; |
888 | } | 886 | } |
889 | tv_tpg = vs->vs_tpg; | 887 | tv_tpg = vs->vs_tpg; |
890 | tv_tport = tv_tpg->tport; | 888 | tv_tport = tv_tpg->tport; |
891 | 889 | ||
892 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn) || | 890 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn) || |
893 | (tv_tpg->tport_tpgt != t->vhost_tpgt)) { | 891 | (tv_tpg->tport_tpgt != t->vhost_tpgt)) { |
894 | mutex_unlock(&vs->dev.mutex); | ||
895 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" | 892 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" |
896 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", | 893 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", |
897 | tv_tport->tport_name, tv_tpg->tport_tpgt, | 894 | tv_tport->tport_name, tv_tpg->tport_tpgt, |
898 | t->vhost_wwpn, t->vhost_tpgt); | 895 | t->vhost_wwpn, t->vhost_tpgt); |
899 | return -EINVAL; | 896 | ret = -EINVAL; |
897 | goto err; | ||
900 | } | 898 | } |
901 | atomic_dec(&tv_tpg->tv_tpg_vhost_count); | 899 | tv_tpg->tv_tpg_vhost_count--; |
902 | vs->vs_tpg = NULL; | 900 | vs->vs_tpg = NULL; |
903 | mutex_unlock(&vs->dev.mutex); | 901 | mutex_unlock(&vs->dev.mutex); |
904 | 902 | ||
905 | return 0; | 903 | return 0; |
904 | |||
905 | err: | ||
906 | mutex_unlock(&vs->dev.mutex); | ||
907 | return ret; | ||
906 | } | 908 | } |
907 | 909 | ||
908 | static int vhost_scsi_open(struct inode *inode, struct file *f) | 910 | static int vhost_scsi_open(struct inode *inode, struct file *f) |
@@ -918,9 +920,9 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | |||
918 | INIT_LIST_HEAD(&s->vs_completion_list); | 920 | INIT_LIST_HEAD(&s->vs_completion_list); |
919 | spin_lock_init(&s->vs_completion_lock); | 921 | spin_lock_init(&s->vs_completion_lock); |
920 | 922 | ||
921 | s->vqs[0].handle_kick = vhost_scsi_ctl_handle_kick; | 923 | s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick; |
922 | s->vqs[1].handle_kick = vhost_scsi_evt_handle_kick; | 924 | s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick; |
923 | s->vqs[2].handle_kick = vhost_scsi_handle_kick; | 925 | s->vqs[VHOST_SCSI_VQ_IO].handle_kick = vhost_scsi_handle_kick; |
924 | r = vhost_dev_init(&s->dev, s->vqs, 3); | 926 | r = vhost_dev_init(&s->dev, s->vqs, 3); |
925 | if (r < 0) { | 927 | if (r < 0) { |
926 | kfree(s); | 928 | kfree(s); |
@@ -949,6 +951,18 @@ static int vhost_scsi_release(struct inode *inode, struct file *f) | |||
949 | return 0; | 951 | return 0; |
950 | } | 952 | } |
951 | 953 | ||
954 | static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index) | ||
955 | { | ||
956 | vhost_poll_flush(&vs->dev.vqs[index].poll); | ||
957 | } | ||
958 | |||
959 | static void vhost_scsi_flush(struct vhost_scsi *vs) | ||
960 | { | ||
961 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_CTL); | ||
962 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_EVT); | ||
963 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_IO); | ||
964 | } | ||
965 | |||
952 | static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) | 966 | static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) |
953 | { | 967 | { |
954 | if (features & ~VHOST_FEATURES) | 968 | if (features & ~VHOST_FEATURES) |
@@ -961,7 +975,8 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) | |||
961 | return -EFAULT; | 975 | return -EFAULT; |
962 | } | 976 | } |
963 | vs->dev.acked_features = features; | 977 | vs->dev.acked_features = features; |
964 | /* TODO possibly smp_wmb() and flush vqs */ | 978 | smp_wmb(); |
979 | vhost_scsi_flush(vs); | ||
965 | mutex_unlock(&vs->dev.mutex); | 980 | mutex_unlock(&vs->dev.mutex); |
966 | return 0; | 981 | return 0; |
967 | } | 982 | } |
@@ -974,7 +989,7 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, | |||
974 | void __user *argp = (void __user *)arg; | 989 | void __user *argp = (void __user *)arg; |
975 | u64 __user *featurep = argp; | 990 | u64 __user *featurep = argp; |
976 | u64 features; | 991 | u64 features; |
977 | int r; | 992 | int r, abi_version = VHOST_SCSI_ABI_VERSION; |
978 | 993 | ||
979 | switch (ioctl) { | 994 | switch (ioctl) { |
980 | case VHOST_SCSI_SET_ENDPOINT: | 995 | case VHOST_SCSI_SET_ENDPOINT: |
@@ -988,12 +1003,7 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, | |||
988 | 1003 | ||
989 | return vhost_scsi_clear_endpoint(vs, &backend); | 1004 | return vhost_scsi_clear_endpoint(vs, &backend); |
990 | case VHOST_SCSI_GET_ABI_VERSION: | 1005 | case VHOST_SCSI_GET_ABI_VERSION: |
991 | if (copy_from_user(&backend, argp, sizeof backend)) | 1006 | if (copy_to_user(argp, &abi_version, sizeof abi_version)) |
992 | return -EFAULT; | ||
993 | |||
994 | backend.abi_version = VHOST_SCSI_ABI_VERSION; | ||
995 | |||
996 | if (copy_to_user(argp, &backend, sizeof backend)) | ||
997 | return -EFAULT; | 1007 | return -EFAULT; |
998 | return 0; | 1008 | return 0; |
999 | case VHOST_GET_FEATURES: | 1009 | case VHOST_GET_FEATURES: |
@@ -1013,11 +1023,21 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, | |||
1013 | } | 1023 | } |
1014 | } | 1024 | } |
1015 | 1025 | ||
1026 | #ifdef CONFIG_COMPAT | ||
1027 | static long vhost_scsi_compat_ioctl(struct file *f, unsigned int ioctl, | ||
1028 | unsigned long arg) | ||
1029 | { | ||
1030 | return vhost_scsi_ioctl(f, ioctl, (unsigned long)compat_ptr(arg)); | ||
1031 | } | ||
1032 | #endif | ||
1033 | |||
1016 | static const struct file_operations vhost_scsi_fops = { | 1034 | static const struct file_operations vhost_scsi_fops = { |
1017 | .owner = THIS_MODULE, | 1035 | .owner = THIS_MODULE, |
1018 | .release = vhost_scsi_release, | 1036 | .release = vhost_scsi_release, |
1019 | .unlocked_ioctl = vhost_scsi_ioctl, | 1037 | .unlocked_ioctl = vhost_scsi_ioctl, |
1020 | /* TODO compat ioctl? */ | 1038 | #ifdef CONFIG_COMPAT |
1039 | .compat_ioctl = vhost_scsi_compat_ioctl, | ||
1040 | #endif | ||
1021 | .open = vhost_scsi_open, | 1041 | .open = vhost_scsi_open, |
1022 | .llseek = noop_llseek, | 1042 | .llseek = noop_llseek, |
1023 | }; | 1043 | }; |
@@ -1054,28 +1074,28 @@ static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport) | |||
1054 | return "Unknown"; | 1074 | return "Unknown"; |
1055 | } | 1075 | } |
1056 | 1076 | ||
1057 | static int tcm_vhost_port_link( | 1077 | static int tcm_vhost_port_link(struct se_portal_group *se_tpg, |
1058 | struct se_portal_group *se_tpg, | ||
1059 | struct se_lun *lun) | 1078 | struct se_lun *lun) |
1060 | { | 1079 | { |
1061 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, | 1080 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, |
1062 | struct tcm_vhost_tpg, se_tpg); | 1081 | struct tcm_vhost_tpg, se_tpg); |
1063 | 1082 | ||
1064 | atomic_inc(&tv_tpg->tv_tpg_port_count); | 1083 | mutex_lock(&tv_tpg->tv_tpg_mutex); |
1065 | smp_mb__after_atomic_inc(); | 1084 | tv_tpg->tv_tpg_port_count++; |
1085 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | ||
1066 | 1086 | ||
1067 | return 0; | 1087 | return 0; |
1068 | } | 1088 | } |
1069 | 1089 | ||
1070 | static void tcm_vhost_port_unlink( | 1090 | static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg, |
1071 | struct se_portal_group *se_tpg, | ||
1072 | struct se_lun *se_lun) | 1091 | struct se_lun *se_lun) |
1073 | { | 1092 | { |
1074 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, | 1093 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, |
1075 | struct tcm_vhost_tpg, se_tpg); | 1094 | struct tcm_vhost_tpg, se_tpg); |
1076 | 1095 | ||
1077 | atomic_dec(&tv_tpg->tv_tpg_port_count); | 1096 | mutex_lock(&tv_tpg->tv_tpg_mutex); |
1078 | smp_mb__after_atomic_dec(); | 1097 | tv_tpg->tv_tpg_port_count--; |
1098 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | ||
1079 | } | 1099 | } |
1080 | 1100 | ||
1081 | static struct se_node_acl *tcm_vhost_make_nodeacl( | 1101 | static struct se_node_acl *tcm_vhost_make_nodeacl( |
@@ -1122,8 +1142,7 @@ static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl) | |||
1122 | kfree(nacl); | 1142 | kfree(nacl); |
1123 | } | 1143 | } |
1124 | 1144 | ||
1125 | static int tcm_vhost_make_nexus( | 1145 | static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg, |
1126 | struct tcm_vhost_tpg *tv_tpg, | ||
1127 | const char *name) | 1146 | const char *name) |
1128 | { | 1147 | { |
1129 | struct se_portal_group *se_tpg; | 1148 | struct se_portal_group *se_tpg; |
@@ -1168,7 +1187,7 @@ static int tcm_vhost_make_nexus( | |||
1168 | return -ENOMEM; | 1187 | return -ENOMEM; |
1169 | } | 1188 | } |
1170 | /* | 1189 | /* |
1171 | * Now register the TCM vHost virtual I_T Nexus as active with the | 1190 | * Now register the TCM vhost virtual I_T Nexus as active with the |
1172 | * call to __transport_register_session() | 1191 | * call to __transport_register_session() |
1173 | */ | 1192 | */ |
1174 | __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, | 1193 | __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, |
@@ -1179,8 +1198,7 @@ static int tcm_vhost_make_nexus( | |||
1179 | return 0; | 1198 | return 0; |
1180 | } | 1199 | } |
1181 | 1200 | ||
1182 | static int tcm_vhost_drop_nexus( | 1201 | static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg) |
1183 | struct tcm_vhost_tpg *tpg) | ||
1184 | { | 1202 | { |
1185 | struct se_session *se_sess; | 1203 | struct se_session *se_sess; |
1186 | struct tcm_vhost_nexus *tv_nexus; | 1204 | struct tcm_vhost_nexus *tv_nexus; |
@@ -1198,27 +1216,27 @@ static int tcm_vhost_drop_nexus( | |||
1198 | return -ENODEV; | 1216 | return -ENODEV; |
1199 | } | 1217 | } |
1200 | 1218 | ||
1201 | if (atomic_read(&tpg->tv_tpg_port_count)) { | 1219 | if (tpg->tv_tpg_port_count != 0) { |
1202 | mutex_unlock(&tpg->tv_tpg_mutex); | 1220 | mutex_unlock(&tpg->tv_tpg_mutex); |
1203 | pr_err("Unable to remove TCM_vHost I_T Nexus with" | 1221 | pr_err("Unable to remove TCM_vhost I_T Nexus with" |
1204 | " active TPG port count: %d\n", | 1222 | " active TPG port count: %d\n", |
1205 | atomic_read(&tpg->tv_tpg_port_count)); | 1223 | tpg->tv_tpg_port_count); |
1206 | return -EPERM; | 1224 | return -EBUSY; |
1207 | } | 1225 | } |
1208 | 1226 | ||
1209 | if (atomic_read(&tpg->tv_tpg_vhost_count)) { | 1227 | if (tpg->tv_tpg_vhost_count != 0) { |
1210 | mutex_unlock(&tpg->tv_tpg_mutex); | 1228 | mutex_unlock(&tpg->tv_tpg_mutex); |
1211 | pr_err("Unable to remove TCM_vHost I_T Nexus with" | 1229 | pr_err("Unable to remove TCM_vhost I_T Nexus with" |
1212 | " active TPG vhost count: %d\n", | 1230 | " active TPG vhost count: %d\n", |
1213 | atomic_read(&tpg->tv_tpg_vhost_count)); | 1231 | tpg->tv_tpg_vhost_count); |
1214 | return -EPERM; | 1232 | return -EBUSY; |
1215 | } | 1233 | } |
1216 | 1234 | ||
1217 | pr_debug("TCM_vHost_ConfigFS: Removing I_T Nexus to emulated" | 1235 | pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated" |
1218 | " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport), | 1236 | " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport), |
1219 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); | 1237 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); |
1220 | /* | 1238 | /* |
1221 | * Release the SCSI I_T Nexus to the emulated vHost Target Port | 1239 | * Release the SCSI I_T Nexus to the emulated vhost Target Port |
1222 | */ | 1240 | */ |
1223 | transport_deregister_session(tv_nexus->tvn_se_sess); | 1241 | transport_deregister_session(tv_nexus->tvn_se_sess); |
1224 | tpg->tpg_nexus = NULL; | 1242 | tpg->tpg_nexus = NULL; |
@@ -1228,8 +1246,7 @@ static int tcm_vhost_drop_nexus( | |||
1228 | return 0; | 1246 | return 0; |
1229 | } | 1247 | } |
1230 | 1248 | ||
1231 | static ssize_t tcm_vhost_tpg_show_nexus( | 1249 | static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg, |
1232 | struct se_portal_group *se_tpg, | ||
1233 | char *page) | 1250 | char *page) |
1234 | { | 1251 | { |
1235 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, | 1252 | struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, |
@@ -1250,8 +1267,7 @@ static ssize_t tcm_vhost_tpg_show_nexus( | |||
1250 | return ret; | 1267 | return ret; |
1251 | } | 1268 | } |
1252 | 1269 | ||
1253 | static ssize_t tcm_vhost_tpg_store_nexus( | 1270 | static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg, |
1254 | struct se_portal_group *se_tpg, | ||
1255 | const char *page, | 1271 | const char *page, |
1256 | size_t count) | 1272 | size_t count) |
1257 | { | 1273 | { |
@@ -1336,8 +1352,7 @@ static struct configfs_attribute *tcm_vhost_tpg_attrs[] = { | |||
1336 | NULL, | 1352 | NULL, |
1337 | }; | 1353 | }; |
1338 | 1354 | ||
1339 | static struct se_portal_group *tcm_vhost_make_tpg( | 1355 | static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn, |
1340 | struct se_wwn *wwn, | ||
1341 | struct config_group *group, | 1356 | struct config_group *group, |
1342 | const char *name) | 1357 | const char *name) |
1343 | { | 1358 | { |
@@ -1385,7 +1400,7 @@ static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg) | |||
1385 | list_del(&tpg->tv_tpg_list); | 1400 | list_del(&tpg->tv_tpg_list); |
1386 | mutex_unlock(&tcm_vhost_mutex); | 1401 | mutex_unlock(&tcm_vhost_mutex); |
1387 | /* | 1402 | /* |
1388 | * Release the virtual I_T Nexus for this vHost TPG | 1403 | * Release the virtual I_T Nexus for this vhost TPG |
1389 | */ | 1404 | */ |
1390 | tcm_vhost_drop_nexus(tpg); | 1405 | tcm_vhost_drop_nexus(tpg); |
1391 | /* | 1406 | /* |
@@ -1395,8 +1410,7 @@ static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg) | |||
1395 | kfree(tpg); | 1410 | kfree(tpg); |
1396 | } | 1411 | } |
1397 | 1412 | ||
1398 | static struct se_wwn *tcm_vhost_make_tport( | 1413 | static struct se_wwn *tcm_vhost_make_tport(struct target_fabric_configfs *tf, |
1399 | struct target_fabric_configfs *tf, | ||
1400 | struct config_group *group, | 1414 | struct config_group *group, |
1401 | const char *name) | 1415 | const char *name) |
1402 | { | 1416 | { |
@@ -1592,7 +1606,10 @@ static void tcm_vhost_deregister_configfs(void) | |||
1592 | static int __init tcm_vhost_init(void) | 1606 | static int __init tcm_vhost_init(void) |
1593 | { | 1607 | { |
1594 | int ret = -ENOMEM; | 1608 | int ret = -ENOMEM; |
1595 | 1609 | /* | |
1610 | * Use our own dedicated workqueue for submitting I/O into | ||
1611 | * target core to avoid contention within system_wq. | ||
1612 | */ | ||
1596 | tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0); | 1613 | tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0); |
1597 | if (!tcm_vhost_workqueue) | 1614 | if (!tcm_vhost_workqueue) |
1598 | goto out; | 1615 | goto out; |
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h index c983ed21e413..eff42df14de9 100644 --- a/drivers/vhost/tcm_vhost.h +++ b/drivers/vhost/tcm_vhost.h | |||
@@ -47,9 +47,9 @@ struct tcm_vhost_tpg { | |||
47 | /* Vhost port target portal group tag for TCM */ | 47 | /* Vhost port target portal group tag for TCM */ |
48 | u16 tport_tpgt; | 48 | u16 tport_tpgt; |
49 | /* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */ | 49 | /* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */ |
50 | atomic_t tv_tpg_port_count; | 50 | int tv_tpg_port_count; |
51 | /* Used for vhost_scsi device reference to tpg_nexus */ | 51 | /* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */ |
52 | atomic_t tv_tpg_vhost_count; | 52 | int tv_tpg_vhost_count; |
53 | /* list for tcm_vhost_list */ | 53 | /* list for tcm_vhost_list */ |
54 | struct list_head tv_tpg_list; | 54 | struct list_head tv_tpg_list; |
55 | /* Used to protect access for tpg_nexus */ | 55 | /* Used to protect access for tpg_nexus */ |
@@ -98,4 +98,5 @@ struct vhost_scsi_target { | |||
98 | /* VHOST_SCSI specific defines */ | 98 | /* VHOST_SCSI specific defines */ |
99 | #define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) | 99 | #define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) |
100 | #define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) | 100 | #define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) |
101 | #define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, struct vhost_scsi_target) | 101 | /* Changing this breaks userspace. */ |
102 | #define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) | ||