aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vhost/vhost.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/vhost/vhost.c')
-rw-r--r--drivers/vhost/vhost.c97
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
1740static 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
1780static 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
1740int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, 1803int 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 }