Skip to content

Commit 333c515

Browse files
author
Paolo Abeni
committed
vhost-net: allow configuring extended features
Use the extended feature type for 'acked_features' and implement two new ioctls operation allowing the user-space to set/query an unbounded amount of features. The actual number of processed features is limited by VIRTIO_FEATURES_MAX and attempts to set features above such limit fail with EOPNOTSUPP. Note that: the legacy ioctls implicitly truncate the negotiated features to the lower 64 bits range and the 'acked_backend_features' field don't need conversion, as the only negotiated feature there is in the low 64 bit range. Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 69b9461 commit 333c515

File tree

5 files changed

+82
-23
lines changed

5 files changed

+82
-23
lines changed

drivers/vhost/net.c

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
6969

7070
#define VHOST_DMA_IS_DONE(len) ((__force u32)(len) >= (__force u32)VHOST_DMA_DONE_LEN)
7171

72-
enum {
73-
VHOST_NET_FEATURES = VHOST_FEATURES |
74-
(1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
75-
(1ULL << VIRTIO_NET_F_MRG_RXBUF) |
76-
(1ULL << VIRTIO_F_ACCESS_PLATFORM) |
77-
(1ULL << VIRTIO_F_RING_RESET)
72+
static const u64 vhost_net_features[VIRTIO_FEATURES_DWORDS] = {
73+
VHOST_FEATURES |
74+
(1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
75+
(1ULL << VIRTIO_NET_F_MRG_RXBUF) |
76+
(1ULL << VIRTIO_F_ACCESS_PLATFORM) |
77+
(1ULL << VIRTIO_F_RING_RESET),
7878
};
7979

8080
enum {
@@ -1614,16 +1614,17 @@ static long vhost_net_reset_owner(struct vhost_net *n)
16141614
return err;
16151615
}
16161616

1617-
static int vhost_net_set_features(struct vhost_net *n, u64 features)
1617+
static int vhost_net_set_features(struct vhost_net *n, const u64 *features)
16181618
{
16191619
size_t vhost_hlen, sock_hlen, hdr_len;
16201620
int i;
16211621

1622-
hdr_len = (features & ((1ULL << VIRTIO_NET_F_MRG_RXBUF) |
1623-
(1ULL << VIRTIO_F_VERSION_1))) ?
1624-
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
1625-
sizeof(struct virtio_net_hdr);
1626-
if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
1622+
hdr_len = virtio_features_test_bit(features, VIRTIO_NET_F_MRG_RXBUF) ||
1623+
virtio_features_test_bit(features, VIRTIO_F_VERSION_1) ?
1624+
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
1625+
sizeof(struct virtio_net_hdr);
1626+
1627+
if (virtio_features_test_bit(features, VHOST_NET_F_VIRTIO_NET_HDR)) {
16271628
/* vhost provides vnet_hdr */
16281629
vhost_hlen = hdr_len;
16291630
sock_hlen = 0;
@@ -1633,18 +1634,19 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
16331634
sock_hlen = hdr_len;
16341635
}
16351636
mutex_lock(&n->dev.mutex);
1636-
if ((features & (1 << VHOST_F_LOG_ALL)) &&
1637+
if (virtio_features_test_bit(features, VHOST_F_LOG_ALL) &&
16371638
!vhost_log_access_ok(&n->dev))
16381639
goto out_unlock;
16391640

1640-
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
1641+
if (virtio_features_test_bit(features, VIRTIO_F_ACCESS_PLATFORM)) {
16411642
if (vhost_init_device_iotlb(&n->dev))
16421643
goto out_unlock;
16431644
}
16441645

16451646
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
16461647
mutex_lock(&n->vqs[i].vq.mutex);
1647-
n->vqs[i].vq.acked_features = features;
1648+
virtio_features_copy(n->vqs[i].vq.acked_features_array,
1649+
features);
16481650
n->vqs[i].vhost_hlen = vhost_hlen;
16491651
n->vqs[i].sock_hlen = sock_hlen;
16501652
mutex_unlock(&n->vqs[i].vq.mutex);
@@ -1681,29 +1683,74 @@ static long vhost_net_set_owner(struct vhost_net *n)
16811683
static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
16821684
unsigned long arg)
16831685
{
1686+
u64 all_features[VIRTIO_FEATURES_DWORDS];
16841687
struct vhost_net *n = f->private_data;
16851688
void __user *argp = (void __user *)arg;
16861689
u64 __user *featurep = argp;
16871690
struct vhost_vring_file backend;
1688-
u64 features;
1689-
int r;
1691+
u64 features, count, copied;
1692+
int r, i;
16901693

16911694
switch (ioctl) {
16921695
case VHOST_NET_SET_BACKEND:
16931696
if (copy_from_user(&backend, argp, sizeof backend))
16941697
return -EFAULT;
16951698
return vhost_net_set_backend(n, backend.index, backend.fd);
16961699
case VHOST_GET_FEATURES:
1697-
features = VHOST_NET_FEATURES;
1700+
features = vhost_net_features[0];
16981701
if (copy_to_user(featurep, &features, sizeof features))
16991702
return -EFAULT;
17001703
return 0;
17011704
case VHOST_SET_FEATURES:
17021705
if (copy_from_user(&features, featurep, sizeof features))
17031706
return -EFAULT;
1704-
if (features & ~VHOST_NET_FEATURES)
1707+
if (features & ~vhost_net_features[0])
17051708
return -EOPNOTSUPP;
1706-
return vhost_net_set_features(n, features);
1709+
1710+
virtio_features_from_u64(all_features, features);
1711+
return vhost_net_set_features(n, all_features);
1712+
case VHOST_GET_FEATURES_ARRAY:
1713+
if (copy_from_user(&count, featurep, sizeof(count)))
1714+
return -EFAULT;
1715+
1716+
/* Copy the net features, up to the user-provided buffer size */
1717+
argp += sizeof(u64);
1718+
copied = min(count, VIRTIO_FEATURES_DWORDS);
1719+
if (copy_to_user(argp, vhost_net_features,
1720+
copied * sizeof(u64)))
1721+
return -EFAULT;
1722+
1723+
/* Zero the trailing space provided by user-space, if any */
1724+
if (clear_user(argp, size_mul(count - copied, sizeof(u64))))
1725+
return -EFAULT;
1726+
return 0;
1727+
case VHOST_SET_FEATURES_ARRAY:
1728+
if (copy_from_user(&count, featurep, sizeof(count)))
1729+
return -EFAULT;
1730+
1731+
virtio_features_zero(all_features);
1732+
argp += sizeof(u64);
1733+
copied = min(count, VIRTIO_FEATURES_DWORDS);
1734+
if (copy_from_user(all_features, argp, copied * sizeof(u64)))
1735+
return -EFAULT;
1736+
1737+
/*
1738+
* Any feature specified by user-space above
1739+
* VIRTIO_FEATURES_MAX is not supported by definition.
1740+
*/
1741+
for (i = copied; i < count; ++i) {
1742+
if (copy_from_user(&features, featurep + 1 + i,
1743+
sizeof(features)))
1744+
return -EFAULT;
1745+
if (features)
1746+
return -EOPNOTSUPP;
1747+
}
1748+
1749+
for (i = 0; i < VIRTIO_FEATURES_DWORDS; i++)
1750+
if (all_features[i] & ~vhost_net_features[i])
1751+
return -EOPNOTSUPP;
1752+
1753+
return vhost_net_set_features(n, all_features);
17071754
case VHOST_GET_BACKEND_FEATURES:
17081755
features = VHOST_NET_BACKEND_FEATURES;
17091756
if (copy_to_user(featurep, &features, sizeof(features)))

drivers/vhost/vhost.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
372372
vq->log_used = false;
373373
vq->log_addr = -1ull;
374374
vq->private_data = NULL;
375-
vq->acked_features = 0;
375+
virtio_features_zero(vq->acked_features_array);
376376
vq->acked_backend_features = 0;
377377
vq->log_base = NULL;
378378
vq->error_ctx = NULL;

drivers/vhost/vhost.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ struct vhost_virtqueue {
133133
struct vhost_iotlb *umem;
134134
struct vhost_iotlb *iotlb;
135135
void *private_data;
136-
u64 acked_features;
136+
VIRTIO_DECLARE_FEATURES(acked_features);
137137
u64 acked_backend_features;
138138
/* Log write descriptors */
139139
void __user *log_base;
@@ -291,7 +291,7 @@ static inline void *vhost_vq_get_backend(struct vhost_virtqueue *vq)
291291

292292
static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit)
293293
{
294-
return vq->acked_features & (1ULL << bit);
294+
return virtio_features_test_bit(vq->acked_features_array, bit);
295295
}
296296

297297
static inline bool vhost_backend_has_feature(struct vhost_virtqueue *vq, int bit)

include/uapi/linux/vhost.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,11 @@
235235
*/
236236
#define VHOST_VDPA_GET_VRING_SIZE _IOWR(VHOST_VIRTIO, 0x82, \
237237
struct vhost_vring_state)
238+
239+
/* Extended features manipulation */
240+
#define VHOST_GET_FEATURES_ARRAY _IOR(VHOST_VIRTIO, 0x83, \
241+
struct vhost_features_array)
242+
#define VHOST_SET_FEATURES_ARRAY _IOW(VHOST_VIRTIO, 0x83, \
243+
struct vhost_features_array)
244+
238245
#endif

include/uapi/linux/vhost_types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ struct vhost_msg_v2 {
110110
};
111111
};
112112

113+
struct vhost_features_array {
114+
__u64 count; /* number of entries present in features array */
115+
__u64 features[] __counted_by(count);
116+
};
117+
113118
struct vhost_memory_region {
114119
__u64 guest_phys_addr;
115120
__u64 memory_size; /* bytes */

0 commit comments

Comments
 (0)