Skip to content

Commit 429711a

Browse files
jasowangdavem330
authored andcommitted
vhost: switch to use new message format
We use to have message like: struct vhost_msg { int type; union { struct vhost_iotlb_msg iotlb; __u8 padding[64]; }; }; Unfortunately, there will be a hole of 32bit in 64bit machine because of the alignment. This leads a different formats between 32bit API and 64bit API. What's more it will break 32bit program running on 64bit machine. So fixing this by introducing a new message type with an explicit 32bit reserved field after type like: struct vhost_msg_v2 { __u32 type; __u32 reserved; union { struct vhost_iotlb_msg iotlb; __u8 padding[64]; }; }; We will have a consistent ABI after switching to use this. To enable this capability, introduce a new ioctl (VHOST_SET_BAKCEND_FEATURE) for userspace to enable this feature (VHOST_BACKEND_F_IOTLB_V2). Fixes: 6b1e6cc ("vhost: new device IOTLB API") Signed-off-by: Jason Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9c2e955 commit 429711a

File tree

4 files changed

+111
-19
lines changed

4 files changed

+111
-19
lines changed

drivers/vhost/net.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ enum {
7777
(1ULL << VIRTIO_F_IOMMU_PLATFORM)
7878
};
7979

80+
enum {
81+
VHOST_NET_BACKEND_FEATURES = (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)
82+
};
83+
8084
enum {
8185
VHOST_NET_VQ_RX = 0,
8286
VHOST_NET_VQ_TX = 1,
@@ -1399,6 +1403,21 @@ static long vhost_net_reset_owner(struct vhost_net *n)
13991403
return err;
14001404
}
14011405

1406+
static int vhost_net_set_backend_features(struct vhost_net *n, u64 features)
1407+
{
1408+
int i;
1409+
1410+
mutex_lock(&n->dev.mutex);
1411+
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
1412+
mutex_lock(&n->vqs[i].vq.mutex);
1413+
n->vqs[i].vq.acked_backend_features = features;
1414+
mutex_unlock(&n->vqs[i].vq.mutex);
1415+
}
1416+
mutex_unlock(&n->dev.mutex);
1417+
1418+
return 0;
1419+
}
1420+
14021421
static int vhost_net_set_features(struct vhost_net *n, u64 features)
14031422
{
14041423
size_t vhost_hlen, sock_hlen, hdr_len;
@@ -1489,6 +1508,17 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
14891508
if (features & ~VHOST_NET_FEATURES)
14901509
return -EOPNOTSUPP;
14911510
return vhost_net_set_features(n, features);
1511+
case VHOST_GET_BACKEND_FEATURES:
1512+
features = VHOST_NET_BACKEND_FEATURES;
1513+
if (copy_to_user(featurep, &features, sizeof(features)))
1514+
return -EFAULT;
1515+
return 0;
1516+
case VHOST_SET_BACKEND_FEATURES:
1517+
if (copy_from_user(&features, featurep, sizeof(features)))
1518+
return -EFAULT;
1519+
if (features & ~VHOST_NET_BACKEND_FEATURES)
1520+
return -EOPNOTSUPP;
1521+
return vhost_net_set_backend_features(n, features);
14921522
case VHOST_RESET_OWNER:
14931523
return vhost_net_reset_owner(n);
14941524
case VHOST_SET_OWNER:

drivers/vhost/vhost.c

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
315315
vq->log_addr = -1ull;
316316
vq->private_data = NULL;
317317
vq->acked_features = 0;
318+
vq->acked_backend_features = 0;
318319
vq->log_base = NULL;
319320
vq->error_ctx = NULL;
320321
vq->kick = NULL;
@@ -1027,28 +1028,40 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
10271028
ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
10281029
struct iov_iter *from)
10291030
{
1030-
struct vhost_msg_node node;
1031-
unsigned size = sizeof(struct vhost_msg);
1032-
size_t ret;
1033-
int err;
1031+
struct vhost_iotlb_msg msg;
1032+
size_t offset;
1033+
int type, ret;
10341034

1035-
if (iov_iter_count(from) < size)
1036-
return 0;
1037-
ret = copy_from_iter(&node.msg, size, from);
1038-
if (ret != size)
1035+
ret = copy_from_iter(&type, sizeof(type), from);
1036+
if (ret != sizeof(type))
10391037
goto done;
10401038

1041-
switch (node.msg.type) {
1039+
switch (type) {
10421040
case VHOST_IOTLB_MSG:
1043-
err = vhost_process_iotlb_msg(dev, &node.msg.iotlb);
1044-
if (err)
1045-
ret = err;
1041+
/* There maybe a hole after type for V1 message type,
1042+
* so skip it here.
1043+
*/
1044+
offset = offsetof(struct vhost_msg, iotlb) - sizeof(int);
1045+
break;
1046+
case VHOST_IOTLB_MSG_V2:
1047+
offset = sizeof(__u32);
10461048
break;
10471049
default:
10481050
ret = -EINVAL;
1049-
break;
1051+
goto done;
1052+
}
1053+
1054+
iov_iter_advance(from, offset);
1055+
ret = copy_from_iter(&msg, sizeof(msg), from);
1056+
if (ret != sizeof(msg))
1057+
goto done;
1058+
if (vhost_process_iotlb_msg(dev, &msg)) {
1059+
ret = -EFAULT;
1060+
goto done;
10501061
}
10511062

1063+
ret = (type == VHOST_IOTLB_MSG) ? sizeof(struct vhost_msg) :
1064+
sizeof(struct vhost_msg_v2);
10521065
done:
10531066
return ret;
10541067
}
@@ -1107,13 +1120,28 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
11071120
finish_wait(&dev->wait, &wait);
11081121

11091122
if (node) {
1110-
ret = copy_to_iter(&node->msg, size, to);
1123+
struct vhost_iotlb_msg *msg;
1124+
void *start = &node->msg;
1125+
1126+
switch (node->msg.type) {
1127+
case VHOST_IOTLB_MSG:
1128+
size = sizeof(node->msg);
1129+
msg = &node->msg.iotlb;
1130+
break;
1131+
case VHOST_IOTLB_MSG_V2:
1132+
size = sizeof(node->msg_v2);
1133+
msg = &node->msg_v2.iotlb;
1134+
break;
1135+
default:
1136+
BUG();
1137+
break;
1138+
}
11111139

1112-
if (ret != size || node->msg.type != VHOST_IOTLB_MISS) {
1140+
ret = copy_to_iter(start, size, to);
1141+
if (ret != size || msg->type != VHOST_IOTLB_MISS) {
11131142
kfree(node);
11141143
return ret;
11151144
}
1116-
11171145
vhost_enqueue_msg(dev, &dev->pending_list, node);
11181146
}
11191147

@@ -1126,12 +1154,19 @@ static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access)
11261154
struct vhost_dev *dev = vq->dev;
11271155
struct vhost_msg_node *node;
11281156
struct vhost_iotlb_msg *msg;
1157+
bool v2 = vhost_backend_has_feature(vq, VHOST_BACKEND_F_IOTLB_MSG_V2);
11291158

1130-
node = vhost_new_msg(vq, VHOST_IOTLB_MISS);
1159+
node = vhost_new_msg(vq, v2 ? VHOST_IOTLB_MSG_V2 : VHOST_IOTLB_MSG);
11311160
if (!node)
11321161
return -ENOMEM;
11331162

1134-
msg = &node->msg.iotlb;
1163+
if (v2) {
1164+
node->msg_v2.type = VHOST_IOTLB_MSG_V2;
1165+
msg = &node->msg_v2.iotlb;
1166+
} else {
1167+
msg = &node->msg.iotlb;
1168+
}
1169+
11351170
msg->type = VHOST_IOTLB_MISS;
11361171
msg->iova = iova;
11371172
msg->perm = access;

drivers/vhost/vhost.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ struct vhost_virtqueue {
132132
struct vhost_umem *iotlb;
133133
void *private_data;
134134
u64 acked_features;
135+
u64 acked_backend_features;
135136
/* Log write descriptors */
136137
void __user *log_base;
137138
struct vhost_log *log;
@@ -147,7 +148,10 @@ struct vhost_virtqueue {
147148
};
148149

149150
struct vhost_msg_node {
150-
struct vhost_msg msg;
151+
union {
152+
struct vhost_msg msg;
153+
struct vhost_msg_v2 msg_v2;
154+
};
151155
struct vhost_virtqueue *vq;
152156
struct list_head node;
153157
};
@@ -238,6 +242,11 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit)
238242
return vq->acked_features & (1ULL << bit);
239243
}
240244

245+
static inline bool vhost_backend_has_feature(struct vhost_virtqueue *vq, int bit)
246+
{
247+
return vq->acked_backend_features & (1ULL << bit);
248+
}
249+
241250
#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
242251
static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
243252
{

include/uapi/linux/vhost.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct vhost_iotlb_msg {
6565
};
6666

6767
#define VHOST_IOTLB_MSG 0x1
68+
#define VHOST_IOTLB_MSG_V2 0x2
6869

6970
struct vhost_msg {
7071
int type;
@@ -74,6 +75,15 @@ struct vhost_msg {
7475
};
7576
};
7677

78+
struct vhost_msg_v2 {
79+
__u32 type;
80+
__u32 reserved;
81+
union {
82+
struct vhost_iotlb_msg iotlb;
83+
__u8 padding[64];
84+
};
85+
};
86+
7787
struct vhost_memory_region {
7888
__u64 guest_phys_addr;
7989
__u64 memory_size; /* bytes */
@@ -160,6 +170,14 @@ struct vhost_memory {
160170
#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \
161171
struct vhost_vring_state)
162172

173+
/* Set or get vhost backend capability */
174+
175+
/* Use message type V2 */
176+
#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1
177+
178+
#define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
179+
#define VHOST_GET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x26, __u64)
180+
163181
/* VHOST_NET specific defines */
164182

165183
/* Attach virtio net ring to a raw socket, or tap device.

0 commit comments

Comments
 (0)