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).
Unified · Split
| @@ -77,6 +77,10 @@ enum { · 76 unmodified lines | |||
| 77 | (1ULL << VIRTIO_F_IOMMU_PLATFORM) | 77 | (1ULL << VIRTIO_F_IOMMU_PLATFORM) |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | enum { | ||
| 81 | VHOST_NET_BACKEND_FEATURES = (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2) | ||
| 82 | }; | ||
| 83 | |||
| 80 | enum { | 84 | enum { |
| 81 | VHOST_NET_VQ_RX = 0, | 85 | VHOST_NET_VQ_RX = 0, |
| 82 | VHOST_NET_VQ_TX = 1, | 86 | VHOST_NET_VQ_TX = 1, |
| @@ -1399,6 +1403,21 @@ done: · 1316 unmodified lines | |||
| 1399 | return err; | 1403 | return err; |
| 1400 | } | 1404 | } |
| 1401 | 1405 | ||
| 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 | |||
| 1402 | static int vhost_net_set_features(struct vhost_net *n, u64 features) | 1421 | static int vhost_net_set_features(struct vhost_net *n, u64 features) |
| 1403 | { | 1422 | { |
| 1404 | size_t vhost_hlen, sock_hlen, hdr_len; | 1423 | size_t vhost_hlen, sock_hlen, hdr_len; |
| @@ -1489,6 +1508,17 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, · 84 unmodified lines | |||
| 1489 | if (features & ~VHOST_NET_FEATURES) | 1508 | if (features & ~VHOST_NET_FEATURES) |
| 1490 | return -EOPNOTSUPP; | 1509 | return -EOPNOTSUPP; |
| 1491 | return vhost_net_set_features(n, features); | 1510 | 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); | ||
| 1492 | case VHOST_RESET_OWNER: | 1522 | case VHOST_RESET_OWNER: |
| 1493 | return vhost_net_reset_owner(n); | 1523 | return vhost_net_reset_owner(n); |
| 1494 | case VHOST_SET_OWNER: | 1524 | case VHOST_SET_OWNER: |
| @@ -315,6 +315,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, · 314 unmodified lines | |||
| 315 | vq->log_addr = -1ull; | 315 | vq->log_addr = -1ull; |
| 316 | vq->private_data = NULL; | 316 | vq->private_data = NULL; |
| 317 | vq->acked_features = 0; | 317 | vq->acked_features = 0; |
| 318 | vq->acked_backend_features = 0; | ||
| 318 | vq->log_base = NULL; | 319 | vq->log_base = NULL; |
| 319 | vq->error_ctx = NULL; | 320 | vq->error_ctx = NULL; |
| 320 | vq->kick = NULL; | 321 | vq->kick = NULL; |
| @@ -1027,28 +1028,40 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, · 706 unmodified lines | |||
| 1027 | ssize_t vhost_chr_write_iter(struct vhost_dev *dev, | 1028 | ssize_t vhost_chr_write_iter(struct vhost_dev *dev, |
| 1028 | struct iov_iter *from) | 1029 | struct iov_iter *from) |
| 1029 | { | 1030 | { |
| 1030 | struct vhost_msg_node node; | 1031 | struct vhost_iotlb_msg msg; |
| 1031 | unsigned size = sizeof(struct vhost_msg); | 1032 | size_t offset; |
| 1032 | size_t ret; | 1033 | int type, ret; |
| 1033 | int err; | ||
| 1034 | 1034 | ||
| 1035 | if (iov_iter_count(from) < size) | 1035 | ret = copy_from_iter(&type, sizeof(type), from); |
| 1036 | return 0; | 1036 | if (ret != sizeof(type)) |
| 1037 | ret = copy_from_iter(&node.msg, size, from); | ||
| 1038 | if (ret != size) | ||
| 1039 | goto done; | 1037 | goto done; |
| 1040 | 1038 | ||
| 1041 | switch (node.msg.type) { | 1039 | switch (type) { |
| 1042 | case VHOST_IOTLB_MSG: | 1040 | case VHOST_IOTLB_MSG: |
| 1043 | err = vhost_process_iotlb_msg(dev, &node.msg.iotlb); | 1041 | /* There maybe a hole after type for V1 message type, |
| 1044 | if (err) | 1042 | * so skip it here. |
| 1045 | ret = err; | 1043 | */ |
| 1044 | offset = offsetof(struct vhost_msg, iotlb) - sizeof(int); | ||
| 1045 | break; | ||
| 1046 | case VHOST_IOTLB_MSG_V2: | ||
| 1047 | offset = sizeof(__u32); | ||
| 1046 | break; | 1048 | break; |
| 1047 | default: | 1049 | default: |
| 1048 | ret = -EINVAL; | 1050 | 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; | ||
| 1050 | } | 1061 | } |
| 1051 | 1062 | ||
| 1063 | ret = (type == VHOST_IOTLB_MSG) ? sizeof(struct vhost_msg) : | ||
| 1064 | sizeof(struct vhost_msg_v2); | ||
| 1052 | done: | 1065 | done: |
| 1053 | return ret; | 1066 | return ret; |
| 1054 | } | 1067 | } |
| @@ -1107,13 +1120,28 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, · 52 unmodified lines | |||
| 1107 | finish_wait(&dev->wait, &wait); | 1120 | finish_wait(&dev->wait, &wait); |
| 1108 | 1121 | ||
| 1109 | if (node) { | 1122 | 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 | } | ||
| 1111 | 1139 | ||
| 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) { | ||
| 1113 | kfree(node); | 1142 | kfree(node); |
| 1114 | return ret; | 1143 | return ret; |
| 1115 | } | 1144 | } |
| 1116 | |||
| 1117 | vhost_enqueue_msg(dev, &dev->pending_list, node); | 1145 | vhost_enqueue_msg(dev, &dev->pending_list, node); |
| 1118 | } | 1146 | } |
| 1119 | 1147 | ||
| @@ -1126,12 +1154,19 @@ static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access) · 6 unmodified lines | |||
| 1126 | struct vhost_dev *dev = vq->dev; | 1154 | struct vhost_dev *dev = vq->dev; |
| 1127 | struct vhost_msg_node *node; | 1155 | struct vhost_msg_node *node; |
| 1128 | struct vhost_iotlb_msg *msg; | 1156 | struct vhost_iotlb_msg *msg; |
| 1157 | bool v2 = vhost_backend_has_feature(vq, VHOST_BACKEND_F_IOTLB_MSG_V2); | ||
| 1129 | 1158 | ||
| 1130 | node = vhost_new_msg(vq, VHOST_IOTLB_MISS); | 1159 | node = vhost_new_msg(vq, v2 ? VHOST_IOTLB_MSG_V2 : VHOST_IOTLB_MSG); |
| 1131 | if (!node) | 1160 | if (!node) |
| 1132 | return -ENOMEM; | 1161 | return -ENOMEM; |
| 1133 | 1162 | ||
| 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 | |||
| 1135 | msg->type = VHOST_IOTLB_MISS; | 1170 | msg->type = VHOST_IOTLB_MISS; |
| 1136 | msg->iova = iova; | 1171 | msg->iova = iova; |
| 1137 | msg->perm = access; | 1172 | msg->perm = access; |
| @@ -132,6 +132,7 @@ struct vhost_virtqueue { · 131 unmodified lines | |||
| 132 | struct vhost_umem *iotlb; | 132 | struct vhost_umem *iotlb; |
| 133 | void *private_data; | 133 | void *private_data; |
| 134 | u64 acked_features; | 134 | u64 acked_features; |
| 135 | u64 acked_backend_features; | ||
| 135 | /* Log write descriptors */ | 136 | /* Log write descriptors */ |
| 136 | void __user *log_base; | 137 | void __user *log_base; |
| 137 | struct vhost_log *log; | 138 | struct vhost_log *log; |
| @@ -147,7 +148,10 @@ struct vhost_virtqueue { · 9 unmodified lines | |||
| 147 | }; | 148 | }; |
| 148 | 149 | ||
| 149 | struct vhost_msg_node { | 150 | struct vhost_msg_node { |
| 150 | struct vhost_msg msg; | 151 | union { |
| 152 | struct vhost_msg msg; | ||
| 153 | struct vhost_msg_v2 msg_v2; | ||
| 154 | }; | ||
| 151 | struct vhost_virtqueue *vq; | 155 | struct vhost_virtqueue *vq; |
| 152 | struct list_head node; | 156 | struct list_head node; |
| 153 | }; | 157 | }; |
| @@ -238,6 +242,11 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) · 84 unmodified lines | |||
| 238 | return vq->acked_features & (1ULL << bit); | 242 | return vq->acked_features & (1ULL << bit); |
| 239 | } | 243 | } |
| 240 | 244 | ||
| 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 | |||
| 241 | #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY | 250 | #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY |
| 242 | static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) | 251 | static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) |
| 243 | { | 252 | { |
| @@ -65,6 +65,7 @@ struct vhost_iotlb_msg { · 64 unmodified lines | |||
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | #define VHOST_IOTLB_MSG 0x1 | 67 | #define VHOST_IOTLB_MSG 0x1 |
| 68 | #define VHOST_IOTLB_MSG_V2 0x2 | ||
| 68 | 69 | ||
| 69 | struct vhost_msg { | 70 | struct vhost_msg { |
| 70 | int type; | 71 | int type; |
| @@ -74,6 +75,15 @@ struct vhost_msg { · 3 unmodified lines | |||
| 74 | }; | 75 | }; |
| 75 | }; | 76 | }; |
| 76 | 77 | ||
| 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 | |||
| 77 | struct vhost_memory_region { | 87 | struct vhost_memory_region { |
| 78 | __u64 guest_phys_addr; | 88 | __u64 guest_phys_addr; |
| 79 | __u64 memory_size; /* bytes */ | 89 | __u64 memory_size; /* bytes */ |
| @@ -160,6 +170,14 @@ struct vhost_memory { · 80 unmodified lines | |||
| 160 | #define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ | 170 | #define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ |
| 161 | struct vhost_vring_state) | 171 | struct vhost_vring_state) |
| 162 | 172 | ||
| 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 | |||
| 163 | /* VHOST_NET specific defines */ | 181 | /* VHOST_NET specific defines */ |
| 164 | 182 | ||
| 165 | /* Attach virtio net ring to a raw socket, or tap device. | 183 | /* Attach virtio net ring to a raw socket, or tap device. |