vhost: factor out setting vring addr and num
authorJason Wang <jasowang@redhat.com>
Fri, 24 May 2019 08:12:17 +0000 (04:12 -0400)
committerMichael S. Tsirkin <mst@redhat.com>
Wed, 5 Jun 2019 20:23:53 +0000 (16:23 -0400)
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>
drivers/vhost/vhost.c

index 30afc79..e27d1da 100644 (file)
@@ -1486,6 +1486,104 @@ err:
        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;