diff options
| -rw-r--r-- | drivers/vhost/tcm_vhost.c | 131 | ||||
| -rw-r--r-- | drivers/vhost/tcm_vhost.h | 4 |
2 files changed, 85 insertions, 50 deletions
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index 704e4f674776..81ecda54b923 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c | |||
| @@ -59,8 +59,14 @@ enum { | |||
| 59 | VHOST_SCSI_VQ_IO = 2, | 59 | VHOST_SCSI_VQ_IO = 2, |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | #define VHOST_SCSI_MAX_TARGET 256 | ||
| 63 | |||
| 62 | struct vhost_scsi { | 64 | struct vhost_scsi { |
| 63 | struct tcm_vhost_tpg *vs_tpg; /* Protected by vhost_scsi->dev.mutex */ | 65 | /* Protected by vhost_scsi->dev.mutex */ |
| 66 | struct tcm_vhost_tpg *vs_tpg[VHOST_SCSI_MAX_TARGET]; | ||
| 67 | char vs_vhost_wwpn[TRANSPORT_IQN_LEN]; | ||
| 68 | bool vs_endpoint; | ||
| 69 | |||
| 64 | struct vhost_dev dev; | 70 | struct vhost_dev dev; |
| 65 | struct vhost_virtqueue vqs[3]; | 71 | struct vhost_virtqueue vqs[3]; |
| 66 | 72 | ||
| @@ -564,10 +570,10 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | |||
| 564 | u32 exp_data_len, data_first, data_num, data_direction; | 570 | u32 exp_data_len, data_first, data_num, data_direction; |
| 565 | unsigned out, in, i; | 571 | unsigned out, in, i; |
| 566 | int head, ret; | 572 | int head, ret; |
| 573 | u8 target; | ||
| 567 | 574 | ||
| 568 | /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ | 575 | /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ |
| 569 | tv_tpg = vs->vs_tpg; | 576 | if (unlikely(!vs->vs_endpoint)) |
| 570 | if (unlikely(!tv_tpg)) | ||
| 571 | return; | 577 | return; |
| 572 | 578 | ||
| 573 | mutex_lock(&vq->mutex); | 579 | mutex_lock(&vq->mutex); |
| @@ -635,6 +641,28 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | |||
| 635 | break; | 641 | break; |
| 636 | } | 642 | } |
| 637 | 643 | ||
| 644 | /* Extract the tpgt */ | ||
| 645 | target = v_req.lun[1]; | ||
| 646 | tv_tpg = vs->vs_tpg[target]; | ||
| 647 | |||
| 648 | /* Target does not exist, fail the request */ | ||
| 649 | if (unlikely(!tv_tpg)) { | ||
| 650 | struct virtio_scsi_cmd_resp __user *resp; | ||
| 651 | struct virtio_scsi_cmd_resp rsp; | ||
| 652 | |||
| 653 | memset(&rsp, 0, sizeof(rsp)); | ||
| 654 | rsp.response = VIRTIO_SCSI_S_BAD_TARGET; | ||
| 655 | resp = vq->iov[out].iov_base; | ||
| 656 | ret = __copy_to_user(resp, &rsp, sizeof(rsp)); | ||
| 657 | if (!ret) | ||
| 658 | vhost_add_used_and_signal(&vs->dev, | ||
| 659 | &vs->vqs[2], head, 0); | ||
| 660 | else | ||
| 661 | pr_err("Faulted on virtio_scsi_cmd_resp\n"); | ||
| 662 | |||
| 663 | continue; | ||
| 664 | } | ||
| 665 | |||
| 638 | exp_data_len = 0; | 666 | exp_data_len = 0; |
| 639 | for (i = 0; i < data_num; i++) | 667 | for (i = 0; i < data_num; i++) |
| 640 | exp_data_len += vq->iov[data_first + i].iov_len; | 668 | exp_data_len += vq->iov[data_first + i].iov_len; |
| @@ -743,7 +771,8 @@ static int vhost_scsi_set_endpoint( | |||
| 743 | { | 771 | { |
| 744 | struct tcm_vhost_tport *tv_tport; | 772 | struct tcm_vhost_tport *tv_tport; |
| 745 | struct tcm_vhost_tpg *tv_tpg; | 773 | struct tcm_vhost_tpg *tv_tpg; |
| 746 | int index; | 774 | bool match = false; |
| 775 | int index, ret; | ||
| 747 | 776 | ||
| 748 | mutex_lock(&vs->dev.mutex); | 777 | mutex_lock(&vs->dev.mutex); |
| 749 | /* Verify that ring has been setup correctly. */ | 778 | /* Verify that ring has been setup correctly. */ |
| @@ -754,7 +783,6 @@ static int vhost_scsi_set_endpoint( | |||
| 754 | return -EFAULT; | 783 | return -EFAULT; |
| 755 | } | 784 | } |
| 756 | } | 785 | } |
| 757 | mutex_unlock(&vs->dev.mutex); | ||
| 758 | 786 | ||
| 759 | mutex_lock(&tcm_vhost_mutex); | 787 | mutex_lock(&tcm_vhost_mutex); |
| 760 | list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) { | 788 | list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) { |
| @@ -769,30 +797,33 @@ static int vhost_scsi_set_endpoint( | |||
| 769 | } | 797 | } |
| 770 | tv_tport = tv_tpg->tport; | 798 | tv_tport = tv_tpg->tport; |
| 771 | 799 | ||
| 772 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) && | 800 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) { |
| 773 | (tv_tpg->tport_tpgt == t->vhost_tpgt)) { | 801 | if (vs->vs_tpg[tv_tpg->tport_tpgt]) { |
| 774 | tv_tpg->tv_tpg_vhost_count++; | ||
| 775 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | ||
| 776 | mutex_unlock(&tcm_vhost_mutex); | ||
| 777 | |||
| 778 | mutex_lock(&vs->dev.mutex); | ||
| 779 | if (vs->vs_tpg) { | ||
| 780 | mutex_unlock(&vs->dev.mutex); | ||
| 781 | mutex_lock(&tv_tpg->tv_tpg_mutex); | ||
| 782 | tv_tpg->tv_tpg_vhost_count--; | ||
| 783 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 802 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
| 803 | mutex_unlock(&tcm_vhost_mutex); | ||
| 804 | mutex_unlock(&vs->dev.mutex); | ||
| 784 | return -EEXIST; | 805 | return -EEXIST; |
| 785 | } | 806 | } |
| 786 | 807 | tv_tpg->tv_tpg_vhost_count++; | |
| 787 | vs->vs_tpg = tv_tpg; | 808 | vs->vs_tpg[tv_tpg->tport_tpgt] = tv_tpg; |
| 788 | smp_mb__after_atomic_inc(); | 809 | smp_mb__after_atomic_inc(); |
| 789 | mutex_unlock(&vs->dev.mutex); | 810 | match = true; |
| 790 | return 0; | ||
| 791 | } | 811 | } |
| 792 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 812 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
| 793 | } | 813 | } |
| 794 | mutex_unlock(&tcm_vhost_mutex); | 814 | mutex_unlock(&tcm_vhost_mutex); |
| 795 | return -EINVAL; | 815 | |
| 816 | if (match) { | ||
| 817 | memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn, | ||
| 818 | sizeof(vs->vs_vhost_wwpn)); | ||
| 819 | vs->vs_endpoint = true; | ||
| 820 | ret = 0; | ||
| 821 | } else { | ||
| 822 | ret = -EEXIST; | ||
| 823 | } | ||
| 824 | |||
| 825 | mutex_unlock(&vs->dev.mutex); | ||
| 826 | return ret; | ||
| 796 | } | 827 | } |
| 797 | 828 | ||
| 798 | static int vhost_scsi_clear_endpoint( | 829 | static int vhost_scsi_clear_endpoint( |
| @@ -801,7 +832,8 @@ static int vhost_scsi_clear_endpoint( | |||
| 801 | { | 832 | { |
| 802 | struct tcm_vhost_tport *tv_tport; | 833 | struct tcm_vhost_tport *tv_tport; |
| 803 | struct tcm_vhost_tpg *tv_tpg; | 834 | struct tcm_vhost_tpg *tv_tpg; |
| 804 | int index, ret; | 835 | int index, ret, i; |
| 836 | u8 target; | ||
| 805 | 837 | ||
| 806 | mutex_lock(&vs->dev.mutex); | 838 | mutex_lock(&vs->dev.mutex); |
| 807 | /* Verify that ring has been setup correctly. */ | 839 | /* Verify that ring has been setup correctly. */ |
| @@ -811,27 +843,32 @@ static int vhost_scsi_clear_endpoint( | |||
| 811 | goto err; | 843 | goto err; |
| 812 | } | 844 | } |
| 813 | } | 845 | } |
| 846 | for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) { | ||
| 847 | target = i; | ||
| 814 | 848 | ||
| 815 | if (!vs->vs_tpg) { | 849 | tv_tpg = vs->vs_tpg[target]; |
| 816 | ret = -ENODEV; | 850 | if (!tv_tpg) |
| 817 | goto err; | 851 | continue; |
| 818 | } | 852 | |
| 819 | tv_tpg = vs->vs_tpg; | 853 | tv_tport = tv_tpg->tport; |
| 820 | tv_tport = tv_tpg->tport; | 854 | if (!tv_tport) { |
| 821 | 855 | ret = -ENODEV; | |
| 822 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn) || | 856 | goto err; |
| 823 | (tv_tpg->tport_tpgt != t->vhost_tpgt)) { | 857 | } |
| 824 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" | 858 | |
| 825 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", | 859 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) { |
| 826 | tv_tport->tport_name, tv_tpg->tport_tpgt, | 860 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" |
| 827 | t->vhost_wwpn, t->vhost_tpgt); | 861 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", |
| 828 | ret = -EINVAL; | 862 | tv_tport->tport_name, tv_tpg->tport_tpgt, |
| 829 | goto err; | 863 | t->vhost_wwpn, t->vhost_tpgt); |
| 864 | ret = -EINVAL; | ||
| 865 | goto err; | ||
| 866 | } | ||
| 867 | tv_tpg->tv_tpg_vhost_count--; | ||
| 868 | vs->vs_tpg[target] = NULL; | ||
| 869 | vs->vs_endpoint = false; | ||
| 830 | } | 870 | } |
| 831 | tv_tpg->tv_tpg_vhost_count--; | ||
| 832 | vs->vs_tpg = NULL; | ||
| 833 | mutex_unlock(&vs->dev.mutex); | 871 | mutex_unlock(&vs->dev.mutex); |
| 834 | |||
| 835 | return 0; | 872 | return 0; |
| 836 | 873 | ||
| 837 | err: | 874 | err: |
| @@ -866,16 +903,12 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | |||
| 866 | static int vhost_scsi_release(struct inode *inode, struct file *f) | 903 | static int vhost_scsi_release(struct inode *inode, struct file *f) |
| 867 | { | 904 | { |
| 868 | struct vhost_scsi *s = f->private_data; | 905 | struct vhost_scsi *s = f->private_data; |
| 906 | struct vhost_scsi_target t; | ||
| 869 | 907 | ||
| 870 | if (s->vs_tpg && s->vs_tpg->tport) { | 908 | mutex_lock(&s->dev.mutex); |
| 871 | struct vhost_scsi_target backend; | 909 | memcpy(t.vhost_wwpn, s->vs_vhost_wwpn, sizeof(t.vhost_wwpn)); |
| 872 | 910 | mutex_unlock(&s->dev.mutex); | |
| 873 | memcpy(backend.vhost_wwpn, s->vs_tpg->tport->tport_name, | 911 | vhost_scsi_clear_endpoint(s, &t); |
| 874 | sizeof(backend.vhost_wwpn)); | ||
| 875 | backend.vhost_tpgt = s->vs_tpg->tport_tpgt; | ||
| 876 | vhost_scsi_clear_endpoint(s, &backend); | ||
| 877 | } | ||
| 878 | |||
| 879 | vhost_dev_stop(&s->dev); | 912 | vhost_dev_stop(&s->dev); |
| 880 | vhost_dev_cleanup(&s->dev, false); | 913 | vhost_dev_cleanup(&s->dev, false); |
| 881 | kfree(s); | 914 | kfree(s); |
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h index 47ee80b3adee..519a5504d347 100644 --- a/drivers/vhost/tcm_vhost.h +++ b/drivers/vhost/tcm_vhost.h | |||
| @@ -93,9 +93,11 @@ struct tcm_vhost_tport { | |||
| 93 | * | 93 | * |
| 94 | * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + | 94 | * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + |
| 95 | * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage | 95 | * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage |
| 96 | * ABI Rev 1: January 2013. Ignore vhost_tpgt filed in struct vhost_scsi_target. | ||
| 97 | * All the targets under vhost_wwpn can be seen and used by guset. | ||
| 96 | */ | 98 | */ |
| 97 | 99 | ||
| 98 | #define VHOST_SCSI_ABI_VERSION 0 | 100 | #define VHOST_SCSI_ABI_VERSION 1 |
| 99 | 101 | ||
| 100 | struct vhost_scsi_target { | 102 | struct vhost_scsi_target { |
| 101 | int abi_version; | 103 | int abi_version; |
