mirror of https://gitee.com/openkylin/linux.git
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 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
|
|||
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)
|
||||
{
|
||||
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_vring_state s;
|
||||
struct vhost_vring_file f;
|
||||
struct vhost_vring_addr a;
|
||||
u32 idx;
|
||||
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);
|
||||
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);
|
||||
|
||||
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:
|
||||
/* Moving base with an active backend?
|
||||
* 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))
|
||||
r = -EFAULT;
|
||||
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:
|
||||
if (copy_from_user(&f, argp, sizeof f)) {
|
||||
r = -EFAULT;
|
||||
|
|
Loading…
Reference in New Issue