vhost,vdpa,virtio: fixes

Just a ton of small fixes all over the place.
 
 Also includes virtio and virtio-rng MAINTAINERS updates.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCgAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmqhKYcPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRppBUIAK/QswxhFU0fUQPFQ4YU5xB8/ANGBBpaE1D0
 D6g7LYJsB9SguzdiSWOK8BV9/2h8A485yoU98kQBHLCM/Qraclr/t8sNel0Vq3V/
 FZmCW21EQZnbcsEbct5WlBlU2veUP2mAhBlRruHEFdMil/W2k4ifF26jFnKAgS8y
 ixirBte0LRCo/Ho42D2mZrY40Z1viRKL03Uhl4jiJz+16bx8uRWGd0UELjr7fMT0
 095HUYvOdCFLLedhFe9LFN5VFb+gy/iQjv/wOBAcwjjwHNIIAF40gedu8bRh8ovu
 ZA17syGe5DjLnp/C1nnEwZhGSDngVEC/aBogKXKJ1MHtVbVZn+A=
 =3WXI
 -----END PGP SIGNATURE-----

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull virtio fixes from Michael Tsirkin:
 "Just a ton of small fixes all over the place.

  Also includes virtio and virtio-rng MAINTAINERS updates"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (27 commits)
  vduse: return compat ioctl results directly
  virtio_input: stop callbacks before unregistering input device
  virtio_input: reset device if input_register_device() fails
  vhost: invalidate vring access on IOTLB transitions
  vduse: validate virtqueue alignment
  vduse: do not take dev->rwsem in the virtqueue kick path
  vhost-scsi: clamp max_io_vqs module parameter
  vhost-scsi: use kvzalloc for vq array allocation
  virtio-pci: return IRQ_HANDLED after non-zero ISR
  virtio: add Eugenio Pérez as Maintainer
  vhost: limit outstanding IOTLB misses per virtqueue
  MAINTAINERS: Add a section for virtio-rng
  vdpa_sim_net: check TX pull result before RX copy
  vdpa_sim_blk: reject out-of-range sector starts
  virtio-vdpa: Use queue id when setting vq affinity
  vdpa: octeon_ep: Check dev_set_name() in dev add
  vdpa: ifcvf: Put device on unsupported feature error
  vdpa: solidrun: Free IRQs after request failure
  vdpa: alibaba: Keep DRIVER_OK clear if IRQ setup fails
  vdpa/pds: check virtqueue notify mapping
  ...
This commit is contained in:
Linus Torvalds 2026-09-09 08:50:05 -07:00
commit 4f3989d75d
22 changed files with 342 additions and 74 deletions

View File

@ -28869,8 +28869,8 @@ F: include/uapi/linux/virtio_console.h
VIRTIO CORE
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
M: Eugenio Pérez <eperezma@redhat.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: virtualization@lists.linux.dev
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-vdpa
@ -28947,7 +28947,7 @@ F: include/uapi/linux/virtio_gpu.h
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
R: Eugenio Pérez <eperezma@redhat.com>
M: Eugenio Pérez <eperezma@redhat.com>
L: kvm@vger.kernel.org
L: virtualization@lists.linux.dev
L: netdev@vger.kernel.org
@ -29002,8 +29002,8 @@ F: include/uapi/linux/virtio_mem.h
VIRTIO NET DRIVER
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
M: Eugenio Pérez <eperezma@redhat.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: netdev@vger.kernel.org
L: virtualization@lists.linux.dev
S: Maintained
@ -29019,6 +29019,13 @@ S: Maintained
F: drivers/nvdimm/nd_virtio.c
F: drivers/nvdimm/virtio_pmem.c
VIRTIO RNG DRIVER
M: Laurent Vivier <lvivier@redhat.com>
L: virtualization@lists.linux.dev
S: Maintained
F: drivers/char/hw_random/virtio-rng.c
F: include/uapi/linux/virtio_rng.h
VIRTIO RTC DRIVER
M: Peter Hilber <peter.hilber@oss.qualcomm.com>
L: virtualization@lists.linux.dev

View File

@ -1964,13 +1964,28 @@ static const struct file_operations portdev_fops = {
static void remove_vqs(struct ports_device *portdev)
{
struct virtqueue *vq;
bool multiport = use_multiport(portdev);
virtio_device_for_each_vq(portdev->vdev, vq) {
struct port_buffer *buf;
unsigned int len;
flush_bufs(vq, true);
while ((buf = virtqueue_detach_unused_buf(vq)))
free_buf(buf, true);
/*
* c_ovq cookies are &portdev->cpkt, not port_buffer.
* Detach them but do not free_buf().
*/
if (multiport && vq == portdev->c_ovq) {
spin_lock(&portdev->c_ovq_lock);
while (virtqueue_get_buf(vq, &len))
;
while (virtqueue_detach_unused_buf(vq))
;
spin_unlock(&portdev->c_ovq_lock);
} else {
flush_bufs(vq, true);
while ((buf = virtqueue_detach_unused_buf(vq)))
free_buf(buf, true);
}
cond_resched();
}
portdev->vdev->config->del_vqs(portdev->vdev);

View File

@ -216,7 +216,10 @@ static void eni_vdpa_set_status(struct vdpa_device *vdpa, u8 status)
if (status & VIRTIO_CONFIG_S_DRIVER_OK &&
!(s & VIRTIO_CONFIG_S_DRIVER_OK)) {
eni_vdpa_request_irq(eni_vdpa);
if (eni_vdpa_request_irq(eni_vdpa)) {
WARN_ON(1);
return;
}
}
vp_legacy_set_status(ldev, status);

View File

@ -724,7 +724,8 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
if (config->device_features & ~device_features) {
IFCVF_ERR(pdev, "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n",
config->device_features, device_features);
return -EINVAL;
ret = -EINVAL;
goto err;
}
device_features &= config->device_features;
}

View File

@ -600,6 +600,8 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
ret = dev_set_name(&vdpa_dev->dev, "%s", name);
else
ret = dev_set_name(&vdpa_dev->dev, "vdpa%u", vdpa_dev->index);
if (ret)
goto vdpa_dev_put;
ret = _vdpa_register_device(&oct_vdpa->vdpa, oct_hw->nr_vring);
if (ret) {

View File

@ -731,6 +731,12 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
notify = vp_modern_map_vq_notify(&pdsv->vdpa_aux->vd_mdev,
i, &pdsv->vqs[i].notify_pa);
if (!notify) {
err = -EINVAL;
dev_err(dev, "Fail to map vq notify %d\n", i);
goto err_unmap;
}
pds_vdpa_init_vqs_entry(pdsv, i, notify);
}

View File

@ -418,11 +418,15 @@ static int snet_request_irqs(struct pci_dev *pdev, struct snet *snet)
snet->vqs[i]->irq_name, snet->vqs[i]);
if (ret) {
SNET_ERR(pdev, "Failed to request IRQ\n");
return ret;
goto err_free_irqs;
}
snet->vqs[i]->irq = irq;
}
return 0;
err_free_irqs:
snet_free_irqs(snet);
return ret;
}
static void snet_set_status(struct vdpa_device *vdev, u8 status)

View File

@ -79,10 +79,11 @@ static void vdpasim_blk_buffer_unlock(struct vdpasim_blk *blk)
static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector,
u64 num_sectors, u64 max_sectors)
{
if (start_sector > VDPASIM_BLK_CAPACITY) {
if (start_sector >= VDPASIM_BLK_CAPACITY) {
dev_dbg(&vdpasim->vdpa.dev,
"starting sector exceeds the capacity - start: 0x%llx capacity: 0x%x\n",
start_sector, VDPASIM_BLK_CAPACITY);
return false;
}
if (num_sectors > max_sectors) {

View File

@ -225,10 +225,15 @@ static void vdpasim_net_work(struct vdpasim *vdpasim)
break;
}
++tx_pkts;
read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov,
net->buffer, PAGE_SIZE);
if (read <= 0) {
++tx_errors;
vdpasim_net_complete(txq, 0);
continue;
}
++tx_pkts;
tx_bytes += read;
if (!receive_filter(vdpasim, read)) {

View File

@ -506,7 +506,7 @@ static void vduse_dev_reset(struct vduse_dev *dev)
}
scoped_guard(rwsem_write, &dev->rwsem) {
dev->suspended = false;
WRITE_ONCE(dev->suspended, false);
dev->status = 0;
dev->driver_features = 0;
dev->generation++;
@ -567,11 +567,17 @@ static int vduse_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 idx,
static void vduse_vq_kick(struct vduse_virtqueue *vq)
{
guard(rwsem_read)(&vq->dev->rwsem);
if (vq->dev->suspended)
/*
* This runs in the context of the vdpa kick_vq op, which may be
* atomic (e.g. virtio-blk kicks from blk-mq dispatch under
* rcu_read_lock()), so dev->rwsem must not be taken here.
* dev->suspended is checked under kick_lock instead and
* vduse_vdpa_suspend() cycles every kick_lock after setting it.
*/
guard(spinlock)(&vq->kick_lock);
if (READ_ONCE(vq->dev->suspended))
return;
guard(spinlock)(&vq->kick_lock);
scoped_guard(spinlock_bh, &vq->ready_lock)
if (!vq->ready)
return;
@ -946,7 +952,17 @@ static int vduse_vdpa_suspend(struct vdpa_device *vdpa)
ret = vduse_dev_msg_sync(dev, &msg);
if (ret == 0) {
scoped_guard(rwsem_write, &dev->rwsem)
dev->suspended = true;
WRITE_ONCE(dev->suspended, true);
/*
* Kicks check dev->suspended under kick_lock without taking
* the rwsem: cycle each kick_lock so that no kick that has
* already passed the check is still in flight after this.
*/
for (u32 i = 0; i < dev->vq_num; i++) {
spin_lock(&dev->vqs[i]->kick_lock);
spin_unlock(&dev->vqs[i]->kick_lock);
}
cancel_work_sync(&dev->inject);
for (u32 i = 0; i < dev->vq_num; i++)
@ -1866,11 +1882,11 @@ static long vduse_dev_compat_ioctl(struct file *file, unsigned int cmd,
break;
}
default:
ret = -ENOIOCTLCMD;
break;
return vduse_dev_ioctl(file, cmd,
(unsigned long)compat_ptr(arg));
}
return vduse_dev_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
return ret;
}
#else
#define vduse_dev_compat_ioctl compat_ptr_ioctl
@ -2211,7 +2227,9 @@ static bool vduse_validate_config(struct vduse_dev_config *config,
return false;
}
if (config->vq_align > PAGE_SIZE)
if (config->vq_align < VRING_USED_ALIGN_SIZE ||
!is_power_of_2(config->vq_align) ||
config->vq_align > PAGE_SIZE)
return false;
if (config->config_size > PAGE_SIZE)

View File

@ -1705,6 +1705,8 @@ static int vhost_net_set_features(struct vhost_net *n, const u64 *features)
if (virtio_features_test_bit(features, VIRTIO_F_ACCESS_PLATFORM)) {
if (vhost_init_device_iotlb(&n->dev))
goto out_unlock;
} else {
vhost_clear_device_iotlb(&n->dev);
}
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {

View File

@ -210,7 +210,37 @@ static const int vhost_scsi_bits[] = {
#define VHOST_SCSI_MAX_EVENT 128
static unsigned vhost_scsi_max_io_vqs = 128;
module_param_named(max_io_vqs, vhost_scsi_max_io_vqs, uint, 0644);
static int vhost_scsi_set_max_io_vqs(const char *val,
const struct kernel_param *kp)
{
unsigned int max_io_vqs;
int ret;
ret = kstrtouint(val, 0, &max_io_vqs);
if (ret)
return ret;
if (max_io_vqs > VHOST_SCSI_MAX_IO_VQ) {
pr_err("Invalid max_io_vqs of %u. Using %u.\n",
max_io_vqs, VHOST_SCSI_MAX_IO_VQ);
max_io_vqs = VHOST_SCSI_MAX_IO_VQ;
} else if (!max_io_vqs) {
pr_err("Invalid max_io_vqs of 0. Using 1.\n");
max_io_vqs = 1;
}
WRITE_ONCE(vhost_scsi_max_io_vqs, max_io_vqs);
return 0;
}
static const struct kernel_param_ops vhost_scsi_max_io_vqs_op = {
.set = vhost_scsi_set_max_io_vqs,
.get = param_get_uint,
};
module_param_cb(max_io_vqs, &vhost_scsi_max_io_vqs_op,
&vhost_scsi_max_io_vqs, 0644);
MODULE_PARM_DESC(max_io_vqs, "Set the max number of IO virtqueues a vhost scsi device can support. The default is 128. The max is 1024.");
struct vhost_scsi_virtqueue {
@ -2290,21 +2320,14 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
struct vhost_scsi_virtqueue *svq;
struct vhost_scsi *vs;
struct vhost_virtqueue **vqs;
int r = -ENOMEM, i, nvqs = vhost_scsi_max_io_vqs;
int r = -ENOMEM, i, nvqs;
vs = kvzalloc_obj(*vs);
if (!vs)
goto err_vs;
vs->inline_sg_cnt = vhost_scsi_inline_sg_cnt;
if (nvqs > VHOST_SCSI_MAX_IO_VQ) {
pr_err("Invalid max_io_vqs of %d. Using %d.\n", nvqs,
VHOST_SCSI_MAX_IO_VQ);
nvqs = VHOST_SCSI_MAX_IO_VQ;
} else if (nvqs == 0) {
pr_err("Invalid max_io_vqs of %d. Using 1.\n", nvqs);
nvqs = 1;
}
nvqs = READ_ONCE(vhost_scsi_max_io_vqs);
nvqs += VHOST_SCSI_VQ_IO;
vs->old_inflight = kmalloc_objs(*vs->old_inflight, nvqs,
@ -2312,7 +2335,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
if (!vs->old_inflight)
goto err_inflight;
vs->vqs = kmalloc_objs(*vs->vqs, nvqs, GFP_KERNEL | __GFP_ZERO);
vs->vqs = kvzalloc_objs(*vs->vqs, nvqs);
if (!vs->vqs)
goto err_vqs;
@ -2348,7 +2371,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
return 0;
err_local_vqs:
kfree(vs->vqs);
kvfree(vs->vqs);
err_vqs:
kfree(vs->old_inflight);
err_inflight:
@ -2369,7 +2392,7 @@ static int vhost_scsi_release(struct inode *inode, struct file *f)
vhost_dev_stop(&vs->dev);
vhost_dev_cleanup(&vs->dev);
kfree(vs->dev.vqs);
kfree(vs->vqs);
kvfree(vs->vqs);
kfree(vs->old_inflight);
kvfree(vs);
return 0;

View File

@ -58,9 +58,12 @@ struct vhost_vdpa {
struct cdev cdev;
atomic_t opened;
u32 nvqs;
u16 vq_num_max;
int virtio_id;
int minor;
struct eventfd_ctx *config_ctx;
/* Serialises vhost_vdpa_config_cb() against config_ctx being replaced. */
spinlock_t config_lock;
int in_batch;
struct vdpa_iova_range range;
u32 batch_asid;
@ -194,10 +197,12 @@ static irqreturn_t vhost_vdpa_virtqueue_cb(void *private)
static irqreturn_t vhost_vdpa_config_cb(void *private)
{
struct vhost_vdpa *v = private;
struct eventfd_ctx *config_ctx = v->config_ctx;
unsigned long flags;
if (config_ctx)
eventfd_signal(config_ctx);
spin_lock_irqsave(&v->config_lock, flags);
if (v->config_ctx)
eventfd_signal(v->config_ctx);
spin_unlock_irqrestore(&v->config_lock, flags);
return IRQ_HANDLED;
}
@ -236,7 +241,9 @@ static void vhost_vdpa_unsetup_vq_irq(struct vhost_vdpa *v, u16 qid)
static int _compat_vdpa_reset(struct vhost_vdpa *v)
{
struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config;
u32 flags = 0;
int ret;
v->suspended = false;
@ -246,7 +253,14 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v)
VDPA_RESET_F_CLEAN_MAP : 0;
}
return vdpa_reset(vdpa, flags);
v->vq_num_max = 0;
ret = vdpa_reset(vdpa, flags);
if (!ret) {
/* Some backends derive the max from mutable queue state. */
v->vq_num_max = ops->get_vq_num_max(vdpa);
}
return ret;
}
static int vhost_vdpa_reset(struct vhost_vdpa *v)
@ -518,15 +532,22 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)
static void vhost_vdpa_config_put(struct vhost_vdpa *v)
{
if (v->config_ctx) {
eventfd_ctx_put(v->config_ctx);
v->config_ctx = NULL;
}
struct eventfd_ctx *ctx;
unsigned long flags;
spin_lock_irqsave(&v->config_lock, flags);
ctx = v->config_ctx;
v->config_ctx = NULL;
spin_unlock_irqrestore(&v->config_lock, flags);
if (ctx)
eventfd_ctx_put(ctx);
}
static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
{
struct vdpa_callback cb;
unsigned long flags;
int fd;
struct eventfd_ctx *ctx;
@ -536,18 +557,20 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
return -EFAULT;
ctx = fd == VHOST_FILE_UNBIND ? NULL : eventfd_ctx_fdget(fd);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
spin_lock_irqsave(&v->config_lock, flags);
swap(ctx, v->config_ctx);
spin_unlock_irqrestore(&v->config_lock, flags);
if (!IS_ERR_OR_NULL(ctx))
/*
* The callback can no longer reach the old context, so this is the
* last reference to it.
*/
if (ctx)
eventfd_ctx_put(ctx);
if (IS_ERR(v->config_ctx)) {
long ret = PTR_ERR(v->config_ctx);
v->config_ctx = NULL;
return ret;
}
v->vdpa->config->set_config_cb(v->vdpa, &cb);
return 0;
@ -648,9 +671,15 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
u32 idx;
long r;
r = get_user(idx, (u32 __user *)argp);
if (r < 0)
return r;
if (cmd == VHOST_SET_VRING_NUM) {
if (copy_from_user(&s, argp, sizeof(s)))
return -EFAULT;
idx = s.index;
} else {
r = get_user(idx, (u32 __user *)argp);
if (r < 0)
return r;
}
if (idx >= v->nvqs)
return -ENOBUFS;
@ -659,6 +688,23 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
vq = &v->vqs[idx];
switch (cmd) {
case VHOST_SET_VRING_NUM:
mutex_lock(&vq->mutex);
if (vq->private_data) {
r = -EBUSY;
} else if (!s.num || s.num > 0xffff ||
s.num > v->vq_num_max ||
(s.num & (s.num - 1))) {
r = -EINVAL;
} else {
vq->num = s.num;
r = 0;
}
mutex_unlock(&vq->mutex);
if (r)
return r;
ops->set_vq_num(vdpa, idx, s.num);
return 0;
case VHOST_VDPA_SET_VRING_ENABLE:
if (copy_from_user(&s, argp, sizeof(s)))
return -EFAULT;
@ -772,9 +818,6 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
ops->set_vq_cb(vdpa, idx, &cb);
break;
case VHOST_SET_VRING_NUM:
ops->set_vq_num(vdpa, idx, vq->num);
break;
}
return r;
@ -1613,6 +1656,7 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa)
}
atomic_set(&v->opened, 0);
spin_lock_init(&v->config_lock);
v->minor = minor;
v->vdpa = vdpa;
v->nvqs = vdpa->nvqs;

View File

@ -344,6 +344,17 @@ static void __vhost_vq_meta_reset(struct vhost_virtqueue *vq)
vq->meta_iotlb[j] = NULL;
}
/* Caller must hold the virtqueue mutex. */
static void vhost_vq_invalidate_access(struct vhost_virtqueue *vq)
{
vq->desc = NULL;
vq->avail = NULL;
vq->used = NULL;
vq->log_used = false;
vq->log_addr = -1ull;
__vhost_vq_meta_reset(vq);
}
static void vhost_vq_meta_reset(struct vhost_dev *d)
{
int i;
@ -392,6 +403,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->busyloop_timeout = 0;
vq->umem = NULL;
vq->iotlb = NULL;
vq->iotlb_miss = NULL;
rcu_assign_pointer(vq->worker, NULL);
vhost_vring_call_reset(&vq->call_ctx);
__vhost_vq_meta_reset(vq);
@ -1180,6 +1192,21 @@ void vhost_dev_stop(struct vhost_dev *dev)
}
EXPORT_SYMBOL_GPL(vhost_dev_stop);
static void vhost_free_msg_locked(struct vhost_msg_node *node)
{
if (node->vq->iotlb_miss == node)
node->vq->iotlb_miss = NULL;
kfree(node);
}
static void vhost_free_msg(struct vhost_dev *dev,
struct vhost_msg_node *node)
{
spin_lock(&dev->iotlb_lock);
vhost_free_msg_locked(node);
spin_unlock(&dev->iotlb_lock);
}
void vhost_clear_msg(struct vhost_dev *dev)
{
struct vhost_msg_node *node, *n;
@ -1188,12 +1215,12 @@ void vhost_clear_msg(struct vhost_dev *dev)
list_for_each_entry_safe(node, n, &dev->read_list, node) {
list_del(&node->node);
kfree(node);
vhost_free_msg_locked(node);
}
list_for_each_entry_safe(node, n, &dev->pending_list, node) {
list_del(&node->node);
kfree(node);
vhost_free_msg_locked(node);
}
spin_unlock(&dev->iotlb_lock);
@ -1602,7 +1629,7 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d,
vq_msg->type == VHOST_IOTLB_MISS) {
vhost_poll_queue(&node->vq->poll);
list_del(&node->node);
kfree(node);
vhost_free_msg_locked(node);
}
}
@ -1816,7 +1843,7 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
ret = copy_to_iter(start, size, to);
if (ret != size || msg->type != VHOST_IOTLB_MISS) {
kfree(node);
vhost_free_msg(dev, node);
return ret;
}
vhost_enqueue_msg(dev, &dev->pending_list, node);
@ -1848,7 +1875,19 @@ static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access)
msg->iova = iova;
msg->perm = access;
vhost_enqueue_msg(dev, &dev->read_list, node);
spin_lock(&dev->iotlb_lock);
/* VQ processing stops at the first miss until userspace resolves it. */
if (vq->iotlb_miss) {
spin_unlock(&dev->iotlb_lock);
kfree(node);
return 0;
}
vq->iotlb_miss = node;
list_add_tail(&node->node, &dev->read_list);
spin_unlock(&dev->iotlb_lock);
wake_up_interruptible_poll(&dev->wait, EPOLLIN | EPOLLRDNORM);
return 0;
}
@ -1918,6 +1957,13 @@ int vq_meta_prefetch(struct vhost_virtqueue *vq)
{
unsigned int num = vq->num;
/*
* vhost_vq_invalidate_access() clears all three addresses together.
* A single zero address may be a valid GIOVA in IOTLB mode.
*/
if (!vq->desc && !vq->avail && !vq->used)
return 0;
if (!vq->iotlb)
return 1;
@ -2287,6 +2333,40 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
}
EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
/* Caller must hold the device mutex. */
void vhost_clear_device_iotlb(struct vhost_dev *d)
{
struct vhost_iotlb *iotlb;
int i;
iotlb = d->iotlb;
if (!iotlb)
return;
vhost_dev_lock_vqs(d);
/*
* vhost_dev_lock_vqs() takes all VQ mutexes in index order. Drop the
* device-wide view while they are held, then clear each per-VQ view
* and its cached ring access before releasing the locks. Workers
* cannot observe a mixed address-space state during this handoff.
*/
d->iotlb = NULL;
for (i = 0; i < d->nvqs; ++i) {
struct vhost_virtqueue *vq = d->vqs[i];
vq->iotlb = NULL;
vhost_vq_invalidate_access(vq);
}
vhost_dev_unlock_vqs(d);
vhost_clear_msg(d);
vhost_iotlb_free(iotlb);
wake_up_interruptible_poll(&d->wait, EPOLLIN | EPOLLRDNORM);
}
EXPORT_SYMBOL_GPL(vhost_clear_device_iotlb);
int vhost_init_device_iotlb(struct vhost_dev *d)
{
struct vhost_iotlb *niotlb, *oiotlb;
@ -2307,7 +2387,10 @@ int vhost_init_device_iotlb(struct vhost_dev *d)
mutex_lock(&vq->mutex);
vq->iotlb = niotlb;
__vhost_vq_meta_reset(vq);
if (oiotlb)
__vhost_vq_meta_reset(vq);
else
vhost_vq_invalidate_access(vq);
mutex_unlock(&vq->mutex);
}

View File

@ -29,6 +29,7 @@ struct vhost_work {
struct vhost_worker;
struct vhost_dev;
struct vhost_msg_node;
struct vhost_worker_ops {
int (*create)(struct vhost_worker *worker, struct vhost_dev *dev,
@ -148,6 +149,8 @@ struct vhost_virtqueue {
/* Protected by virtqueue mutex. */
struct vhost_iotlb *umem;
struct vhost_iotlb *iotlb;
/* Protected by dev->iotlb_lock. */
struct vhost_msg_node *iotlb_miss;
void *private_data;
VIRTIO_DECLARE_FEATURES(acked_features);
u64 acked_backend_features;
@ -277,6 +280,7 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
int noblock);
ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
struct iov_iter *from);
void vhost_clear_device_iotlb(struct vhost_dev *d);
int vhost_init_device_iotlb(struct vhost_dev *d);
void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,

View File

@ -868,6 +868,8 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
if (vhost_init_device_iotlb(&vsock->dev))
goto err;
} else {
vhost_clear_device_iotlb(&vsock->dev);
}
vsock->seqpacket_allow = features & (1ULL << VIRTIO_VSOCK_F_SEQPACKET);

View File

@ -604,8 +604,8 @@ void unregister_virtio_device(struct virtio_device *dev)
{
int index = dev->index; /* save for after device release */
device_unregister(&dev->dev);
virtio_debug_device_exit(dev);
device_unregister(&dev->dev);
ida_free(&virtio_index_ida, index);
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);

View File

@ -49,9 +49,12 @@ static void virtinput_recv_events(struct virtqueue *vq)
le16_to_cpu(event->code),
le32_to_cpu(event->value));
spin_lock_irqsave(&vi->lock, flags);
if (!vi->ready)
continue;
virtinput_queue_evtbuf(vi, event);
}
virtqueue_kick(vq);
if (vi->ready)
virtqueue_kick(vq);
}
spin_unlock_irqrestore(&vi->lock, flags);
}
@ -331,6 +334,7 @@ static int virtinput_probe(struct virtio_device *vdev)
spin_lock_irqsave(&vi->lock, flags);
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
virtio_reset_device(vdev);
err_mt_init_slots:
input_free_device(vi->idev);
err_input_alloc:
@ -350,8 +354,9 @@ static void virtinput_remove(struct virtio_device *vdev)
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
input_unregister_device(vi->idev);
/* Callbacks use vi->idev. */
virtio_reset_device(vdev);
input_unregister_device(vi->idev);
while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
kfree(buf);
vdev->config->del_vqs(vdev);

View File

@ -88,6 +88,9 @@ struct virtio_mmio_device {
void __iomem *base;
unsigned long version;
/* True if enable_irq_wake() succeeded for the shared IRQ. */
bool wake_irq_enabled;
};
/* Configuration interface */
@ -336,11 +339,17 @@ static void vm_del_vqs(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
struct virtqueue *vq, *n;
int irq = platform_get_irq(vm_dev->pdev, 0);
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
vm_del_vq(vq);
free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev);
if (vm_dev->wake_irq_enabled) {
disable_irq_wake(irq);
vm_dev->wake_irq_enabled = false;
}
free_irq(irq, vm_dev);
}
static void vm_synchronize_cbs(struct virtio_device *vdev)
@ -467,8 +476,9 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
if (err)
return err;
if (of_property_read_bool(vm_dev->pdev->dev.of_node, "wakeup-source"))
enable_irq_wake(irq);
if (of_property_read_bool(vm_dev->pdev->dev.of_node, "wakeup-source") &&
!enable_irq_wake(irq))
vm_dev->wake_irq_enabled = true;
for (i = 0; i < nvqs; ++i) {
struct virtqueue_info *vqi = &vqs_info[i];

View File

@ -120,7 +120,9 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)
if (isr & VIRTIO_PCI_ISR_CONFIG)
vp_config_changed(irq, opaque);
return vp_vring_interrupt(irq, opaque);
vp_vring_interrupt(irq, opaque);
return IRQ_HANDLED;
}
static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,

View File

@ -1670,7 +1670,7 @@ static inline int virtqueue_add_packed(struct vring_virtqueue *vq,
struct scatterlist *sg;
unsigned int i, n, c, descs_used, err_idx, len;
__le16 head_flags, flags;
u16 head, id, prev, curr, avail_used_flags;
u16 head, id, prev, curr, avail_used_flags, unpub_flags;
int err;
START_USE(vq);
@ -1798,15 +1798,30 @@ static inline int virtqueue_add_packed(struct vring_virtqueue *vq,
curr = vq->free_head;
vq->packed.avail_used_flags = avail_used_flags;
unpub_flags = avail_used_flags ^ (1 << VRING_PACKED_DESC_F_AVAIL |
1 << VRING_PACKED_DESC_F_USED);
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
/*
* The mapping loop made every descriptor but the head
* available. Stamp the previous wrap counter's AVAIL and USED
* bits on those, so that a later and shorter chain at this head
* does not leave one of them available beyond its own last
* descriptor. Marking them used instead would hand
* is_used_desc_packed() a completion we never made.
*/
if (i != head)
desc[i].flags = cpu_to_le16(unpub_flags);
vring_unmap_extra_packed(vq, &vq->packed.desc_extra[curr]);
curr = vq->packed.desc_extra[curr].next;
i++;
if (i >= vq->packed.vring.num)
if (i >= vq->packed.vring.num) {
i = 0;
unpub_flags ^= 1 << VRING_PACKED_DESC_F_AVAIL |
1 << VRING_PACKED_DESC_F_USED;
}
}
END_USE(vq);
@ -1828,7 +1843,7 @@ static inline int virtqueue_add_packed_in_order(struct vring_virtqueue *vq,
struct scatterlist *sg;
unsigned int i, n, sg_count, err_idx, total_in_len = 0;
__le16 head_flags, flags;
u16 head, avail_used_flags;
u16 head, avail_used_flags, unpub_flags;
bool avail_wrap_counter;
int err;
@ -1955,14 +1970,29 @@ static inline int virtqueue_add_packed_in_order(struct vring_virtqueue *vq,
i = head;
vq->packed.avail_used_flags = avail_used_flags;
vq->packed.avail_wrap_counter = avail_wrap_counter;
unpub_flags = avail_used_flags ^ (1 << VRING_PACKED_DESC_F_AVAIL |
1 << VRING_PACKED_DESC_F_USED);
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
/*
* The mapping loop made every descriptor but the head
* available. Stamp the previous wrap counter's AVAIL and USED
* bits on those, so that a later and shorter chain at this head
* does not leave one of them available beyond its own last
* descriptor. Marking them used instead would hand
* is_used_desc_packed() a completion we never made.
*/
if (i != head)
desc[i].flags = cpu_to_le16(unpub_flags);
vring_unmap_extra_packed(vq, &vq->packed.desc_extra[i]);
i++;
if (i >= vq->packed.vring.num)
if (i >= vq->packed.vring.num) {
i = 0;
unpub_flags ^= 1 << VRING_PACKED_DESC_F_AVAIL |
1 << VRING_PACKED_DESC_F_USED;
}
}
END_USE(vq);

View File

@ -352,7 +352,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
continue;
}
vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, vqi->callback,
vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx, vqi->callback,
vqi->name, vqi->ctx);
if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]);
@ -360,7 +360,8 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
}
if (has_affinity)
ops->set_vq_affinity(vdpa, i, &masks[i]);
ops->set_vq_affinity(vdpa, queue_idx, &masks[i]);
queue_idx++;
}
cb.callback = virtio_vdpa_config_cb;