diff options
Diffstat (limited to 'drivers/vhost/vhost.c')
| -rw-r--r-- | drivers/vhost/vhost.c | 97 |
1 files changed, 83 insertions, 14 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index bac939af8dbb..15a216cdd507 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c | |||
| @@ -1737,13 +1737,87 @@ static int log_write(void __user *log_base, | |||
| 1737 | return r; | 1737 | return r; |
| 1738 | } | 1738 | } |
| 1739 | 1739 | ||
| 1740 | static int log_write_hva(struct vhost_virtqueue *vq, u64 hva, u64 len) | ||
| 1741 | { | ||
| 1742 | struct vhost_umem *umem = vq->umem; | ||
| 1743 | struct vhost_umem_node *u; | ||
| 1744 | u64 start, end, l, min; | ||
| 1745 | int r; | ||
| 1746 | bool hit = false; | ||
| 1747 | |||
| 1748 | while (len) { | ||
| 1749 | min = len; | ||
| 1750 | /* More than one GPAs can be mapped into a single HVA. So | ||
| 1751 | * iterate all possible umems here to be safe. | ||
| 1752 | */ | ||
| 1753 | list_for_each_entry(u, &umem->umem_list, link) { | ||
| 1754 | if (u->userspace_addr > hva - 1 + len || | ||
| 1755 | u->userspace_addr - 1 + u->size < hva) | ||
| 1756 | continue; | ||
| 1757 | start = max(u->userspace_addr, hva); | ||
| 1758 | end = min(u->userspace_addr - 1 + u->size, | ||
| 1759 | hva - 1 + len); | ||
| 1760 | l = end - start + 1; | ||
| 1761 | r = log_write(vq->log_base, | ||
| 1762 | u->start + start - u->userspace_addr, | ||
| 1763 | l); | ||
| 1764 | if (r < 0) | ||
| 1765 | return r; | ||
| 1766 | hit = true; | ||
| 1767 | min = min(l, min); | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | if (!hit) | ||
| 1771 | return -EFAULT; | ||
| 1772 | |||
| 1773 | len -= min; | ||
| 1774 | hva += min; | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | return 0; | ||
| 1778 | } | ||
| 1779 | |||
| 1780 | static int log_used(struct vhost_virtqueue *vq, u64 used_offset, u64 len) | ||
| 1781 | { | ||
| 1782 | struct iovec iov[64]; | ||
| 1783 | int i, ret; | ||
| 1784 | |||
| 1785 | if (!vq->iotlb) | ||
| 1786 | return log_write(vq->log_base, vq->log_addr + used_offset, len); | ||
| 1787 | |||
| 1788 | ret = translate_desc(vq, (uintptr_t)vq->used + used_offset, | ||
| 1789 | len, iov, 64, VHOST_ACCESS_WO); | ||
| 1790 | if (ret) | ||
| 1791 | return ret; | ||
| 1792 | |||
| 1793 | for (i = 0; i < ret; i++) { | ||
| 1794 | ret = log_write_hva(vq, (uintptr_t)iov[i].iov_base, | ||
| 1795 | iov[i].iov_len); | ||
| 1796 | if (ret) | ||
| 1797 | return ret; | ||
| 1798 | } | ||
| 1799 | |||
| 1800 | return 0; | ||
| 1801 | } | ||
| 1802 | |||
| 1740 | int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, | 1803 | int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, |
| 1741 | unsigned int log_num, u64 len) | 1804 | unsigned int log_num, u64 len, struct iovec *iov, int count) |
| 1742 | { | 1805 | { |
| 1743 | int i, r; | 1806 | int i, r; |
| 1744 | 1807 | ||
| 1745 | /* Make sure data written is seen before log. */ | 1808 | /* Make sure data written is seen before log. */ |
| 1746 | smp_wmb(); | 1809 | smp_wmb(); |
| 1810 | |||
| 1811 | if (vq->iotlb) { | ||
| 1812 | for (i = 0; i < count; i++) { | ||
| 1813 | r = log_write_hva(vq, (uintptr_t)iov[i].iov_base, | ||
| 1814 | iov[i].iov_len); | ||
| 1815 | if (r < 0) | ||
| 1816 | return r; | ||
| 1817 | } | ||
| 1818 | return 0; | ||
| 1819 | } | ||
| 1820 | |||
| 1747 | for (i = 0; i < log_num; ++i) { | 1821 | for (i = 0; i < log_num; ++i) { |
| 1748 | u64 l = min(log[i].len, len); | 1822 | u64 l = min(log[i].len, len); |
| 1749 | r = log_write(vq->log_base, log[i].addr, l); | 1823 | r = log_write(vq->log_base, log[i].addr, l); |
| @@ -1773,9 +1847,8 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq) | |||
| 1773 | smp_wmb(); | 1847 | smp_wmb(); |
| 1774 | /* Log used flag write. */ | 1848 | /* Log used flag write. */ |
| 1775 | used = &vq->used->flags; | 1849 | used = &vq->used->flags; |
| 1776 | log_write(vq->log_base, vq->log_addr + | 1850 | log_used(vq, (used - (void __user *)vq->used), |
| 1777 | (used - (void __user *)vq->used), | 1851 | sizeof vq->used->flags); |
| 1778 | sizeof vq->used->flags); | ||
| 1779 | if (vq->log_ctx) | 1852 | if (vq->log_ctx) |
| 1780 | eventfd_signal(vq->log_ctx, 1); | 1853 | eventfd_signal(vq->log_ctx, 1); |
| 1781 | } | 1854 | } |
| @@ -1793,9 +1866,8 @@ static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event) | |||
| 1793 | smp_wmb(); | 1866 | smp_wmb(); |
| 1794 | /* Log avail event write */ | 1867 | /* Log avail event write */ |
| 1795 | used = vhost_avail_event(vq); | 1868 | used = vhost_avail_event(vq); |
| 1796 | log_write(vq->log_base, vq->log_addr + | 1869 | log_used(vq, (used - (void __user *)vq->used), |
| 1797 | (used - (void __user *)vq->used), | 1870 | sizeof *vhost_avail_event(vq)); |
| 1798 | sizeof *vhost_avail_event(vq)); | ||
| 1799 | if (vq->log_ctx) | 1871 | if (vq->log_ctx) |
| 1800 | eventfd_signal(vq->log_ctx, 1); | 1872 | eventfd_signal(vq->log_ctx, 1); |
| 1801 | } | 1873 | } |
| @@ -2195,10 +2267,8 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, | |||
| 2195 | /* Make sure data is seen before log. */ | 2267 | /* Make sure data is seen before log. */ |
| 2196 | smp_wmb(); | 2268 | smp_wmb(); |
| 2197 | /* Log used ring entry write. */ | 2269 | /* Log used ring entry write. */ |
| 2198 | log_write(vq->log_base, | 2270 | log_used(vq, ((void __user *)used - (void __user *)vq->used), |
| 2199 | vq->log_addr + | 2271 | count * sizeof *used); |
| 2200 | ((void __user *)used - (void __user *)vq->used), | ||
| 2201 | count * sizeof *used); | ||
| 2202 | } | 2272 | } |
| 2203 | old = vq->last_used_idx; | 2273 | old = vq->last_used_idx; |
| 2204 | new = (vq->last_used_idx += count); | 2274 | new = (vq->last_used_idx += count); |
| @@ -2240,9 +2310,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, | |||
| 2240 | /* Make sure used idx is seen before log. */ | 2310 | /* Make sure used idx is seen before log. */ |
| 2241 | smp_wmb(); | 2311 | smp_wmb(); |
| 2242 | /* Log used index update. */ | 2312 | /* Log used index update. */ |
| 2243 | log_write(vq->log_base, | 2313 | log_used(vq, offsetof(struct vring_used, idx), |
| 2244 | vq->log_addr + offsetof(struct vring_used, idx), | 2314 | sizeof vq->used->idx); |
| 2245 | sizeof vq->used->idx); | ||
| 2246 | if (vq->log_ctx) | 2315 | if (vq->log_ctx) |
| 2247 | eventfd_signal(vq->log_ctx, 1); | 2316 | eventfd_signal(vq->log_ctx, 1); |
| 2248 | } | 2317 | } |
