diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2013-04-29 10:41:36 -0400 |
---|---|---|
committer | Alex Williamson <alex.williamson@redhat.com> | 2013-04-29 10:41:36 -0400 |
commit | 0b43c082338b857c27d2f87c886eb78812ccd236 (patch) | |
tree | 4692c09a3ba9b7efb9eff3000f17d8bdbde00630 /drivers/vfio | |
parent | 9587f44aa69a4cfb13701b31a633852684bed701 (diff) |
vfio: Use down_reads to protect iommu disconnects
If a group or device is released or a container is unset from a group
it can race against file ops on the container. Protect these with
down_reads to allow concurrent users.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Reported-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'drivers/vfio')
-rw-r--r-- | drivers/vfio/vfio.c | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 073788e50e4b..ac7423bfaa7d 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -704,9 +704,13 @@ EXPORT_SYMBOL_GPL(vfio_del_group_dev); | |||
704 | static long vfio_ioctl_check_extension(struct vfio_container *container, | 704 | static long vfio_ioctl_check_extension(struct vfio_container *container, |
705 | unsigned long arg) | 705 | unsigned long arg) |
706 | { | 706 | { |
707 | struct vfio_iommu_driver *driver = container->iommu_driver; | 707 | struct vfio_iommu_driver *driver; |
708 | long ret = 0; | 708 | long ret = 0; |
709 | 709 | ||
710 | down_read(&container->group_lock); | ||
711 | |||
712 | driver = container->iommu_driver; | ||
713 | |||
710 | switch (arg) { | 714 | switch (arg) { |
711 | /* No base extensions yet */ | 715 | /* No base extensions yet */ |
712 | default: | 716 | default: |
@@ -736,6 +740,8 @@ static long vfio_ioctl_check_extension(struct vfio_container *container, | |||
736 | VFIO_CHECK_EXTENSION, arg); | 740 | VFIO_CHECK_EXTENSION, arg); |
737 | } | 741 | } |
738 | 742 | ||
743 | up_read(&container->group_lock); | ||
744 | |||
739 | return ret; | 745 | return ret; |
740 | } | 746 | } |
741 | 747 | ||
@@ -844,9 +850,6 @@ static long vfio_fops_unl_ioctl(struct file *filep, | |||
844 | if (!container) | 850 | if (!container) |
845 | return ret; | 851 | return ret; |
846 | 852 | ||
847 | driver = container->iommu_driver; | ||
848 | data = container->iommu_data; | ||
849 | |||
850 | switch (cmd) { | 853 | switch (cmd) { |
851 | case VFIO_GET_API_VERSION: | 854 | case VFIO_GET_API_VERSION: |
852 | ret = VFIO_API_VERSION; | 855 | ret = VFIO_API_VERSION; |
@@ -858,8 +861,15 @@ static long vfio_fops_unl_ioctl(struct file *filep, | |||
858 | ret = vfio_ioctl_set_iommu(container, arg); | 861 | ret = vfio_ioctl_set_iommu(container, arg); |
859 | break; | 862 | break; |
860 | default: | 863 | default: |
864 | down_read(&container->group_lock); | ||
865 | |||
866 | driver = container->iommu_driver; | ||
867 | data = container->iommu_data; | ||
868 | |||
861 | if (driver) /* passthrough all unrecognized ioctls */ | 869 | if (driver) /* passthrough all unrecognized ioctls */ |
862 | ret = driver->ops->ioctl(data, cmd, arg); | 870 | ret = driver->ops->ioctl(data, cmd, arg); |
871 | |||
872 | up_read(&container->group_lock); | ||
863 | } | 873 | } |
864 | 874 | ||
865 | return ret; | 875 | return ret; |
@@ -910,35 +920,55 @@ static ssize_t vfio_fops_read(struct file *filep, char __user *buf, | |||
910 | size_t count, loff_t *ppos) | 920 | size_t count, loff_t *ppos) |
911 | { | 921 | { |
912 | struct vfio_container *container = filep->private_data; | 922 | struct vfio_container *container = filep->private_data; |
913 | struct vfio_iommu_driver *driver = container->iommu_driver; | 923 | struct vfio_iommu_driver *driver; |
924 | ssize_t ret = -EINVAL; | ||
914 | 925 | ||
915 | if (unlikely(!driver || !driver->ops->read)) | 926 | down_read(&container->group_lock); |
916 | return -EINVAL; | 927 | |
928 | driver = container->iommu_driver; | ||
929 | if (likely(driver && driver->ops->read)) | ||
930 | ret = driver->ops->read(container->iommu_data, | ||
931 | buf, count, ppos); | ||
917 | 932 | ||
918 | return driver->ops->read(container->iommu_data, buf, count, ppos); | 933 | up_read(&container->group_lock); |
934 | |||
935 | return ret; | ||
919 | } | 936 | } |
920 | 937 | ||
921 | static ssize_t vfio_fops_write(struct file *filep, const char __user *buf, | 938 | static ssize_t vfio_fops_write(struct file *filep, const char __user *buf, |
922 | size_t count, loff_t *ppos) | 939 | size_t count, loff_t *ppos) |
923 | { | 940 | { |
924 | struct vfio_container *container = filep->private_data; | 941 | struct vfio_container *container = filep->private_data; |
925 | struct vfio_iommu_driver *driver = container->iommu_driver; | 942 | struct vfio_iommu_driver *driver; |
943 | ssize_t ret = -EINVAL; | ||
926 | 944 | ||
927 | if (unlikely(!driver || !driver->ops->write)) | 945 | down_read(&container->group_lock); |
928 | return -EINVAL; | 946 | |
947 | driver = container->iommu_driver; | ||
948 | if (likely(driver && driver->ops->write)) | ||
949 | ret = driver->ops->write(container->iommu_data, | ||
950 | buf, count, ppos); | ||
951 | |||
952 | up_read(&container->group_lock); | ||
929 | 953 | ||
930 | return driver->ops->write(container->iommu_data, buf, count, ppos); | 954 | return ret; |
931 | } | 955 | } |
932 | 956 | ||
933 | static int vfio_fops_mmap(struct file *filep, struct vm_area_struct *vma) | 957 | static int vfio_fops_mmap(struct file *filep, struct vm_area_struct *vma) |
934 | { | 958 | { |
935 | struct vfio_container *container = filep->private_data; | 959 | struct vfio_container *container = filep->private_data; |
936 | struct vfio_iommu_driver *driver = container->iommu_driver; | 960 | struct vfio_iommu_driver *driver; |
961 | int ret = -EINVAL; | ||
937 | 962 | ||
938 | if (unlikely(!driver || !driver->ops->mmap)) | 963 | down_read(&container->group_lock); |
939 | return -EINVAL; | ||
940 | 964 | ||
941 | return driver->ops->mmap(container->iommu_data, vma); | 965 | driver = container->iommu_driver; |
966 | if (likely(driver && driver->ops->mmap)) | ||
967 | ret = driver->ops->mmap(container->iommu_data, vma); | ||
968 | |||
969 | up_read(&container->group_lock); | ||
970 | |||
971 | return ret; | ||
942 | } | 972 | } |
943 | 973 | ||
944 | static const struct file_operations vfio_fops = { | 974 | static const struct file_operations vfio_fops = { |