diff options
author | Jason Wang <jasowang@redhat.com> | 2019-05-24 04:12:17 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2019-06-05 16:23:53 -0400 |
commit | feebcaeac79ad86fb289ef55fa92f4a97ab8314e (patch) | |
tree | 653fe9ef4cb8914c9aef72f1074140462fd7c286 | |
parent | 4942e8254d93b31ea14cf63a9dfd10a8112caafa (diff) |
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>
-rw-r--r-- | drivers/vhost/vhost.c | 177 |
1 files changed, 103 insertions, 74 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 30afc79d551e..e27d1da5f979 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c | |||
@@ -1486,6 +1486,104 @@ err: | |||
1486 | return -EFAULT; | 1486 | return -EFAULT; |
1487 | } | 1487 | } |
1488 | 1488 | ||
1489 | static long vhost_vring_set_num(struct vhost_dev *d, | ||
1490 | struct vhost_virtqueue *vq, | ||
1491 | void __user *argp) | ||
1492 | { | ||
1493 | struct vhost_vring_state s; | ||
1494 | |||
1495 | /* Resizing ring with an active backend? | ||
1496 | * You don't want to do that. */ | ||
1497 | if (vq->private_data) | ||
1498 | return -EBUSY; | ||
1499 | |||
1500 | if (copy_from_user(&s, argp, sizeof s)) | ||
1501 | return -EFAULT; | ||
1502 | |||
1503 | if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) | ||
1504 | return -EINVAL; | ||
1505 | vq->num = s.num; | ||
1506 | |||
1507 | return 0; | ||
1508 | } | ||
1509 | |||
1510 | static long vhost_vring_set_addr(struct vhost_dev *d, | ||
1511 | struct vhost_virtqueue *vq, | ||
1512 | void __user *argp) | ||
1513 | { | ||
1514 | struct vhost_vring_addr a; | ||
1515 | |||
1516 | if (copy_from_user(&a, argp, sizeof a)) | ||
1517 | return -EFAULT; | ||
1518 | if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) | ||
1519 | return -EOPNOTSUPP; | ||
1520 | |||
1521 | /* For 32bit, verify that the top 32bits of the user | ||
1522 | data are set to zero. */ | ||
1523 | if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr || | ||
1524 | (u64)(unsigned long)a.used_user_addr != a.used_user_addr || | ||
1525 | (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) | ||
1526 | return -EFAULT; | ||
1527 | |||
1528 | /* Make sure it's safe to cast pointers to vring types. */ | ||
1529 | BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE); | ||
1530 | BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE); | ||
1531 | if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) || | ||
1532 | (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) || | ||
1533 | (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) | ||
1534 | return -EINVAL; | ||
1535 | |||
1536 | /* We only verify access here if backend is configured. | ||
1537 | * If it is not, we don't as size might not have been setup. | ||
1538 | * We will verify when backend is configured. */ | ||
1539 | if (vq->private_data) { | ||
1540 | if (!vq_access_ok(vq, vq->num, | ||
1541 | (void __user *)(unsigned long)a.desc_user_addr, | ||
1542 | (void __user *)(unsigned long)a.avail_user_addr, | ||
1543 | (void __user *)(unsigned long)a.used_user_addr)) | ||
1544 | return -EINVAL; | ||
1545 | |||
1546 | /* Also validate log access for used ring if enabled. */ | ||
1547 | if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) && | ||
1548 | !log_access_ok(vq->log_base, a.log_guest_addr, | ||
1549 | sizeof *vq->used + | ||
1550 | vq->num * sizeof *vq->used->ring)) | ||
1551 | return -EINVAL; | ||
1552 | } | ||
1553 | |||
1554 | vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG)); | ||
1555 | vq->desc = (void __user *)(unsigned long)a.desc_user_addr; | ||
1556 | vq->avail = (void __user *)(unsigned long)a.avail_user_addr; | ||
1557 | vq->log_addr = a.log_guest_addr; | ||
1558 | vq->used = (void __user *)(unsigned long)a.used_user_addr; | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | static long vhost_vring_set_num_addr(struct vhost_dev *d, | ||
1564 | struct vhost_virtqueue *vq, | ||
1565 | unsigned int ioctl, | ||
1566 | void __user *argp) | ||
1567 | { | ||
1568 | long r; | ||
1569 | |||
1570 | mutex_lock(&vq->mutex); | ||
1571 | |||
1572 | switch (ioctl) { | ||
1573 | case VHOST_SET_VRING_NUM: | ||
1574 | r = vhost_vring_set_num(d, vq, argp); | ||
1575 | break; | ||
1576 | case VHOST_SET_VRING_ADDR: | ||
1577 | r = vhost_vring_set_addr(d, vq, argp); | ||
1578 | break; | ||
1579 | default: | ||
1580 | BUG(); | ||
1581 | } | ||
1582 | |||
1583 | mutex_unlock(&vq->mutex); | ||
1584 | |||
1585 | return r; | ||
1586 | } | ||
1489 | long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) | 1587 | long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) |
1490 | { | 1588 | { |
1491 | struct file *eventfp, *filep = NULL; | 1589 | struct file *eventfp, *filep = NULL; |
@@ -1495,7 +1593,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg | |||
1495 | struct vhost_virtqueue *vq; | 1593 | struct vhost_virtqueue *vq; |
1496 | struct vhost_vring_state s; | 1594 | struct vhost_vring_state s; |
1497 | struct vhost_vring_file f; | 1595 | struct vhost_vring_file f; |
1498 | struct vhost_vring_addr a; | ||
1499 | u32 idx; | 1596 | u32 idx; |
1500 | long r; | 1597 | long r; |
1501 | 1598 | ||
@@ -1508,26 +1605,14 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg | |||
1508 | idx = array_index_nospec(idx, d->nvqs); | 1605 | idx = array_index_nospec(idx, d->nvqs); |
1509 | vq = d->vqs[idx]; | 1606 | vq = d->vqs[idx]; |
1510 | 1607 | ||
1608 | if (ioctl == VHOST_SET_VRING_NUM || | ||
1609 | ioctl == VHOST_SET_VRING_ADDR) { | ||
1610 | return vhost_vring_set_num_addr(d, vq, ioctl, argp); | ||
1611 | } | ||
1612 | |||
1511 | mutex_lock(&vq->mutex); | 1613 | mutex_lock(&vq->mutex); |
1512 | 1614 | ||
1513 | switch (ioctl) { | 1615 | switch (ioctl) { |
1514 | case VHOST_SET_VRING_NUM: | ||
1515 | /* Resizing ring with an active backend? | ||
1516 | * You don't want to do that. */ | ||
1517 | if (vq->private_data) { | ||
1518 | r = -EBUSY; | ||
1519 | break; | ||
1520 | } | ||
1521 | if (copy_from_user(&s, argp, sizeof s)) { | ||
1522 | r = -EFAULT; | ||
1523 | break; | ||
1524 | } | ||
1525 | if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) { | ||
1526 | r = -EINVAL; | ||
1527 | break; | ||
1528 | } | ||
1529 | vq->num = s.num; | ||
1530 | break; | ||
1531 | case VHOST_SET_VRING_BASE: | 1616 | case VHOST_SET_VRING_BASE: |
1532 | /* Moving base with an active backend? | 1617 | /* Moving base with an active backend? |
1533 | * You don't want to do that. */ | 1618 | * 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 | |||
1553 | if (copy_to_user(argp, &s, sizeof s)) | 1638 | if (copy_to_user(argp, &s, sizeof s)) |
1554 | r = -EFAULT; | 1639 | r = -EFAULT; |
1555 | break; | 1640 | break; |
1556 | case VHOST_SET_VRING_ADDR: | ||
1557 | if (copy_from_user(&a, argp, sizeof a)) { | ||
1558 | r = -EFAULT; | ||
1559 | break; | ||
1560 | } | ||
1561 | if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) { | ||
1562 | r = -EOPNOTSUPP; | ||
1563 | break; | ||
1564 | } | ||
1565 | /* For 32bit, verify that the top 32bits of the user | ||
1566 | data are set to zero. */ | ||
1567 | if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr || | ||
1568 | (u64)(unsigned long)a.used_user_addr != a.used_user_addr || | ||
1569 | (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) { | ||
1570 | r = -EFAULT; | ||
1571 | break; | ||
1572 | } | ||
1573 | |||
1574 | /* Make sure it's safe to cast pointers to vring types. */ | ||
1575 | BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE); | ||
1576 | BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE); | ||
1577 | if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) || | ||
1578 | (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) || | ||
1579 | (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) { | ||
1580 | r = -EINVAL; | ||
1581 | break; | ||
1582 | } | ||
1583 | |||
1584 | /* We only verify access here if backend is configured. | ||
1585 | * If it is not, we don't as size might not have been setup. | ||
1586 | * We will verify when backend is configured. */ | ||
1587 | if (vq->private_data) { | ||
1588 | if (!vq_access_ok(vq, vq->num, | ||
1589 | (void __user *)(unsigned long)a.desc_user_addr, | ||
1590 | (void __user *)(unsigned long)a.avail_user_addr, | ||
1591 | (void __user *)(unsigned long)a.used_user_addr)) { | ||
1592 | r = -EINVAL; | ||
1593 | break; | ||
1594 | } | ||
1595 | |||
1596 | /* Also validate log access for used ring if enabled. */ | ||
1597 | if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) && | ||
1598 | !log_access_ok(vq->log_base, a.log_guest_addr, | ||
1599 | sizeof *vq->used + | ||
1600 | vq->num * sizeof *vq->used->ring)) { | ||
1601 | r = -EINVAL; | ||
1602 | break; | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1606 | vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG)); | ||
1607 | vq->desc = (void __user *)(unsigned long)a.desc_user_addr; | ||
1608 | vq->avail = (void __user *)(unsigned long)a.avail_user_addr; | ||
1609 | vq->log_addr = a.log_guest_addr; | ||
1610 | vq->used = (void __user *)(unsigned long)a.used_user_addr; | ||
1611 | break; | ||
1612 | case VHOST_SET_VRING_KICK: | 1641 | case VHOST_SET_VRING_KICK: |
1613 | if (copy_from_user(&f, argp, sizeof f)) { | 1642 | if (copy_from_user(&f, argp, sizeof f)) { |
1614 | r = -EFAULT; | 1643 | r = -EFAULT; |