Skip to content

Commit feebcae

Browse files
jasowangmstsirkin
authored andcommitted
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 <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 4942e82 commit feebcae

File tree

1 file changed

+103
-74
lines changed

1 file changed

+103
-74
lines changed

drivers/vhost/vhost.c

Lines changed: 103 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,104 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
14861486
return -EFAULT;
14871487
}
14881488

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+
}
14891587
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
14901588
{
14911589
struct file *eventfp, *filep = NULL;
@@ -1495,7 +1593,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
14951593
struct vhost_virtqueue *vq;
14961594
struct vhost_vring_state s;
14971595
struct vhost_vring_file f;
1498-
struct vhost_vring_addr a;
14991596
u32 idx;
15001597
long r;
15011598

@@ -1508,26 +1605,14 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
15081605
idx = array_index_nospec(idx, d->nvqs);
15091606
vq = d->vqs[idx];
15101607

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+
15111613
mutex_lock(&vq->mutex);
15121614

15131615
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;
15311616
case VHOST_SET_VRING_BASE:
15321617
/* Moving base with an active backend?
15331618
* 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
15531638
if (copy_to_user(argp, &s, sizeof s))
15541639
r = -EFAULT;
15551640
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;
16121641
case VHOST_SET_VRING_KICK:
16131642
if (copy_from_user(&f, argp, sizeof f)) {
16141643
r = -EFAULT;

0 commit comments

Comments
 (0)