vhost: factor out setting vring addr and num
Factoring vring address and num setting which needs special care for accelerating vq metadata accessing. Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
4942e8254d
commit
feebcaeac7
@ -1486,6 +1486,104 @@ err:
|
|||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long vhost_vring_set_num(struct vhost_dev *d,
|
||||||
|
struct vhost_virtqueue *vq,
|
||||||
|
void __user *argp)
|
||||||
|
{
|
||||||
|
struct vhost_vring_state s;
|
||||||
|
|
||||||
|
/* Resizing ring with an active backend?
|
||||||
|
* You don't want to do that. */
|
||||||
|
if (vq->private_data)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (copy_from_user(&s, argp, sizeof s))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (!s.num || s.num > 0xffff || (s.num & (s.num - 1)))
|
||||||
|
return -EINVAL;
|
||||||
|
vq->num = s.num;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long vhost_vring_set_addr(struct vhost_dev *d,
|
||||||
|
struct vhost_virtqueue *vq,
|
||||||
|
void __user *argp)
|
||||||
|
{
|
||||||
|
struct vhost_vring_addr a;
|
||||||
|
|
||||||
|
if (copy_from_user(&a, argp, sizeof a))
|
||||||
|
return -EFAULT;
|
||||||
|
if (a.flags & ~(0x1 << VHOST_VRING_F_LOG))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/* For 32bit, verify that the top 32bits of the user
|
||||||
|
data are set to zero. */
|
||||||
|
if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
|
||||||
|
(u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
|
||||||
|
(u64)(unsigned long)a.avail_user_addr != a.avail_user_addr)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Make sure it's safe to cast pointers to vring types. */
|
||||||
|
BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
|
||||||
|
BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
|
||||||
|
if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
|
||||||
|
(a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
|
||||||
|
(a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* We only verify access here if backend is configured.
|
||||||
|
* If it is not, we don't as size might not have been setup.
|
||||||
|
* We will verify when backend is configured. */
|
||||||
|
if (vq->private_data) {
|
||||||
|
if (!vq_access_ok(vq, vq->num,
|
||||||
|
(void __user *)(unsigned long)a.desc_user_addr,
|
||||||
|
(void __user *)(unsigned long)a.avail_user_addr,
|
||||||
|
(void __user *)(unsigned long)a.used_user_addr))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Also validate log access for used ring if enabled. */
|
||||||
|
if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
|
||||||
|
!log_access_ok(vq->log_base, a.log_guest_addr,
|
||||||
|
sizeof *vq->used +
|
||||||
|
vq->num * sizeof *vq->used->ring))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
|
||||||
|
vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
|
||||||
|
vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
|
||||||
|
vq->log_addr = a.log_guest_addr;
|
||||||
|
vq->used = (void __user *)(unsigned long)a.used_user_addr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long vhost_vring_set_num_addr(struct vhost_dev *d,
|
||||||
|
struct vhost_virtqueue *vq,
|
||||||
|
unsigned int ioctl,
|
||||||
|
void __user *argp)
|
||||||
|
{
|
||||||
|
long r;
|
||||||
|
|
||||||
|
mutex_lock(&vq->mutex);
|
||||||
|
|
||||||
|
switch (ioctl) {
|
||||||
|
case VHOST_SET_VRING_NUM:
|
||||||
|
r = vhost_vring_set_num(d, vq, argp);
|
||||||
|
break;
|
||||||
|
case VHOST_SET_VRING_ADDR:
|
||||||
|
r = vhost_vring_set_addr(d, vq, argp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&vq->mutex);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
|
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
|
||||||
{
|
{
|
||||||
struct file *eventfp, *filep = NULL;
|
struct file *eventfp, *filep = NULL;
|
||||||
@ -1495,7 +1593,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
|
|||||||
struct vhost_virtqueue *vq;
|
struct vhost_virtqueue *vq;
|
||||||
struct vhost_vring_state s;
|
struct vhost_vring_state s;
|
||||||
struct vhost_vring_file f;
|
struct vhost_vring_file f;
|
||||||
struct vhost_vring_addr a;
|
|
||||||
u32 idx;
|
u32 idx;
|
||||||
long r;
|
long r;
|
||||||
|
|
||||||
@ -1508,26 +1605,14 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
|
|||||||
idx = array_index_nospec(idx, d->nvqs);
|
idx = array_index_nospec(idx, d->nvqs);
|
||||||
vq = d->vqs[idx];
|
vq = d->vqs[idx];
|
||||||
|
|
||||||
|
if (ioctl == VHOST_SET_VRING_NUM ||
|
||||||
|
ioctl == VHOST_SET_VRING_ADDR) {
|
||||||
|
return vhost_vring_set_num_addr(d, vq, ioctl, argp);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&vq->mutex);
|
mutex_lock(&vq->mutex);
|
||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
case VHOST_SET_VRING_NUM:
|
|
||||||
/* Resizing ring with an active backend?
|
|
||||||
* You don't want to do that. */
|
|
||||||
if (vq->private_data) {
|
|
||||||
r = -EBUSY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (copy_from_user(&s, argp, sizeof s)) {
|
|
||||||
r = -EFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vq->num = s.num;
|
|
||||||
break;
|
|
||||||
case VHOST_SET_VRING_BASE:
|
case VHOST_SET_VRING_BASE:
|
||||||
/* Moving base with an active backend?
|
/* Moving base with an active backend?
|
||||||
* You don't want to do that. */
|
* You don't want to do that. */
|
||||||
@ -1553,62 +1638,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
|
|||||||
if (copy_to_user(argp, &s, sizeof s))
|
if (copy_to_user(argp, &s, sizeof s))
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
break;
|
break;
|
||||||
case VHOST_SET_VRING_ADDR:
|
|
||||||
if (copy_from_user(&a, argp, sizeof a)) {
|
|
||||||
r = -EFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
|
|
||||||
r = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* For 32bit, verify that the top 32bits of the user
|
|
||||||
data are set to zero. */
|
|
||||||
if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
|
|
||||||
(u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
|
|
||||||
(u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
|
|
||||||
r = -EFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure it's safe to cast pointers to vring types. */
|
|
||||||
BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
|
|
||||||
BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
|
|
||||||
if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
|
|
||||||
(a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
|
|
||||||
(a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) {
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We only verify access here if backend is configured.
|
|
||||||
* If it is not, we don't as size might not have been setup.
|
|
||||||
* We will verify when backend is configured. */
|
|
||||||
if (vq->private_data) {
|
|
||||||
if (!vq_access_ok(vq, vq->num,
|
|
||||||
(void __user *)(unsigned long)a.desc_user_addr,
|
|
||||||
(void __user *)(unsigned long)a.avail_user_addr,
|
|
||||||
(void __user *)(unsigned long)a.used_user_addr)) {
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Also validate log access for used ring if enabled. */
|
|
||||||
if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
|
|
||||||
!log_access_ok(vq->log_base, a.log_guest_addr,
|
|
||||||
sizeof *vq->used +
|
|
||||||
vq->num * sizeof *vq->used->ring)) {
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
|
|
||||||
vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
|
|
||||||
vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
|
|
||||||
vq->log_addr = a.log_guest_addr;
|
|
||||||
vq->used = (void __user *)(unsigned long)a.used_user_addr;
|
|
||||||
break;
|
|
||||||
case VHOST_SET_VRING_KICK:
|
case VHOST_SET_VRING_KICK:
|
||||||
if (copy_from_user(&f, argp, sizeof f)) {
|
if (copy_from_user(&f, argp, sizeof f)) {
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
|
Loading…
Reference in New Issue
Block a user