diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-17 11:49:00 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-17 11:49:00 -0700 |
| commit | d44ade05aa21468bd30652bc4492891b854a400a (patch) | |
| tree | e146ae0c13621fc867f739bc84f98f8ce0875915 /drivers/vhost | |
| parent | 3dc0df03396a3329c644b29b421892a32ecb9387 (diff) | |
| parent | 8cb2c9285e4ce9154f45fb15633ebd45dfd8d9cf (diff) | |
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
Pull virtio updates from Michael Tsirkin:
- new virtio CAN driver
- support for LoongArch architecture in fw_cfg
- support for firmware notifications in vdpa/octeon_ep
- support for VFs in virtio core
- fixes, cleanups all over the place, notably:
- vhost: fix vhost_get_avail_idx for a non empty ring
fixing an significant old perf regression
- READ_ONCE() annotations mean virtio ring is now
free of KCSAN warnings
* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (37 commits)
can: virtio: Fix comment in UAPI header
can: virtio: Add virtio CAN driver
virtio: add num_vf callback to virtio_bus
fw_cfg: Add support for LoongArch architecture
vdpa/octeon_ep: fix IRQ-to-ring mapping in interrupt handler
vdpa/octeon_ep: Add vDPA device event handling for firmware notifications
vdpa/octeon_ep: Use 4 bytes for mailbox signature
vdpa/octeon_ep: Fix PF->VF mailbox data address calculation
vhost_task_create: kill unnecessary .exit_signal initialization
vhost: remove unnecessary module_init/exit functions
vdpa/mlx5: Use kvzalloc_flex() for MTT command memory
vdpa_sim_net: switch to dynamic root device
vdpa_sim_blk: switch to dynamic root device
virtio-mem: Destroy mutex before freeing virtio_mem
virtio-balloon: Destroy mutex before freeing virtio_balloon
tools/virtio: fix build for kmalloc_obj API and missing stubs
virtio_ring: Add READ_ONCE annotations for device-writable fields
vduse: fix compat handling for VDUSE_IOTLB_GET_FD/VDUSE_VQ_GET_INFO
tools/virtio: check mmap return value in vringh_test
vhost/net: complete zerocopy ubufs only once
...
Diffstat (limited to 'drivers/vhost')
| -rw-r--r-- | drivers/vhost/net.c | 15 | ||||
| -rw-r--r-- | drivers/vhost/vdpa.c | 29 | ||||
| -rw-r--r-- | drivers/vhost/vhost.c | 23 | ||||
| -rw-r--r-- | drivers/vhost/vsock.c | 16 |
4 files changed, 56 insertions, 27 deletions
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index db341c922673..77b59f49bddb 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -399,13 +399,20 @@ static void vhost_zerocopy_signal_used(struct vhost_net *net, static void vhost_zerocopy_complete(struct sk_buff *skb, struct ubuf_info *ubuf_base, bool success) { - struct ubuf_info_msgzc *ubuf = uarg_to_msgzc(ubuf_base); - struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; - struct vhost_virtqueue *vq = ubufs->vq; + struct ubuf_info_msgzc *ubuf; + struct vhost_net_ubuf_ref *ubufs; + struct vhost_virtqueue *vq; int cnt; - rcu_read_lock_bh(); + /* Only the final cloned skb reference completes the vhost descriptor. */ + if (!refcount_dec_and_test(&ubuf_base->refcnt)) + return; + + ubuf = uarg_to_msgzc(ubuf_base); + ubufs = ubuf->ctx; + vq = ubufs->vq; + rcu_read_lock_bh(); /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 692564b1bcbb..ac55275fa0d0 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -1482,16 +1482,32 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) } #ifdef CONFIG_MMU -static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +static int +vhost_vdpa_get_vq_notification(struct vhost_vdpa *v, unsigned long index, + struct vdpa_notification_area *notify) { - struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_device *vdpa = v->vdpa; const struct vdpa_config_ops *ops = vdpa->config; + + if (index > 65535 || index >= v->nvqs) + return -EINVAL; + + index = array_index_nospec(index, v->nvqs); + + *notify = ops->get_vq_notification(vdpa, index); + + return 0; +} + +static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +{ + struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_notification_area notify; struct vm_area_struct *vma = vmf->vma; - u16 index = vma->vm_pgoff; + unsigned long index = vma->vm_pgoff; - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) + return VM_FAULT_SIGBUS; return vmf_insert_pfn(vma, vmf->address & PAGE_MASK, PFN_DOWN(notify.addr)); } @@ -1514,8 +1530,6 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; if (vma->vm_flags & VM_READ) return -EINVAL; - if (index > 65535) - return -EINVAL; if (!ops->get_vq_notification) return -ENOTSUPP; @@ -1523,7 +1537,8 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) * support the doorbell which sits on the page boundary and * does not share the page with other registers. */ - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) + return -EINVAL; if (notify.addr & (PAGE_SIZE - 1)) return -EINVAL; if (vma->vm_end - vma->vm_start != notify.size) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2f2c45d20883..4c525b3e16ea 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1522,6 +1522,7 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d) static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) { __virtio16 idx; + u16 avail_idx; int r; r = vhost_get_avail(vq, idx, &vq->avail->idx); @@ -1532,17 +1533,19 @@ static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) } /* Check it isn't doing very strange thing with available indexes */ - vq->avail_idx = vhost16_to_cpu(vq, idx); - if (unlikely((u16)(vq->avail_idx - vq->last_avail_idx) > vq->num)) { + avail_idx = vhost16_to_cpu(vq, idx); + if (unlikely((u16)(avail_idx - vq->last_avail_idx) > vq->num)) { vq_err(vq, "Invalid available index change from %u to %u", - vq->last_avail_idx, vq->avail_idx); + vq->last_avail_idx, avail_idx); return -EINVAL; } /* We're done if there is nothing new */ - if (vq->avail_idx == vq->last_avail_idx) + if (avail_idx == vq->avail_idx) return 0; + vq->avail_idx = avail_idx; + /* * We updated vq->avail_idx so we need a memory barrier between * the index read above and the caller reading avail ring entries. @@ -3321,18 +3324,6 @@ void vhost_set_backend_features(struct vhost_dev *dev, u64 features) } EXPORT_SYMBOL_GPL(vhost_set_backend_features); -static int __init vhost_init(void) -{ - return 0; -} - -static void __exit vhost_exit(void) -{ -} - -module_init(vhost_init); -module_exit(vhost_exit); - MODULE_VERSION("0.0.1"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Michael S. Tsirkin"); diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 1d8ec6bed53e..9aaab6bb8061 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -302,6 +302,22 @@ vhost_transport_send_pkt(struct sk_buff *skb, struct net *net) return -ENODEV; } + /* Fast-fail if the guest hasn't enabled the RX vq yet. Queuing the packet + * and making the caller wait is pointless: even if the guest manages to init + * within the timeout, it'll immediately reply with RST, because there's no + * listener on the port yet. + * + * vhost_vq_get_backend() without vq->mutex is acceptable here: locking + * the mutex would be too expensive in this hot path, and we already have + * all the outcomes covered: if the backend becomes NULL right after the check, + * vhost_transport_do_send_pkt() will check it under the mutex anyway. + */ + if (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])))) { + rcu_read_unlock(); + kfree_skb(skb); + return -EHOSTUNREACH; + } + if (virtio_vsock_skb_reply(skb)) atomic_inc(&vsock->queued_replies); |
