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 | 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 | 84 | enum { |
| 81 | 85 | VHOST_NET_VQ_RX = 0, |
| 82 | 86 | VHOST_NET_VQ_TX = 1, |
| @@ -1399,6 +1403,21 @@ done: · 1316 unmodified lines | ||
| 1399 | 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 | 1421 | static int vhost_net_set_features(struct vhost_net *n, u64 features) |
| 1403 | 1422 | { |
| 1404 | 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 | 1508 | if (features & ~VHOST_NET_FEATURES) |
| 1490 | 1509 | return -EOPNOTSUPP; |
| 1491 | 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 | 1522 | case VHOST_RESET_OWNER: |
| 1493 | 1523 | return vhost_net_reset_owner(n); |
| 1494 | 1524 | case VHOST_SET_OWNER: |
| @@ -315,6 +315,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, · 314 unmodified lines | ||
| 315 | 315 | vq->log_addr = -1ull; |
| 316 | 316 | vq->private_data = NULL; |
| 317 | 317 | vq->acked_features = 0; |
| 318 | + vq->acked_backend_features = 0; | |
| 318 | 319 | vq->log_base = NULL; |
| 319 | 320 | vq->error_ctx = NULL; |
| 320 | 321 | vq->kick = NULL; |
| @@ -1027,28 +1028,40 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, · 706 unmodified lines | ||
| 1027 | 1028 | ssize_t vhost_chr_write_iter(struct vhost_dev *dev, |
| 1028 | 1029 | struct iov_iter *from) |
| 1029 | 1030 | { |
| 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; | |
| 1034 | 1034 | |
| 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)) | |
| 1039 | 1037 | goto done; |
| 1040 | 1038 | |
| 1041 | − switch (node.msg.type) { | |
| 1039 | + switch (type) { | |
| 1042 | 1040 | 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); | |
| 1046 | 1048 | break; |
| 1047 | 1049 | default: |
| 1048 | 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 | 1065 | done: |
| 1053 | 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 | 1120 | finish_wait(&dev->wait, &wait); |
| 1108 | 1121 | |
| 1109 | 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 | 1142 | kfree(node); |
| 1114 | 1143 | return ret; |
| 1115 | 1144 | } |
| 1116 | − | |
| 1117 | 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 | 1154 | struct vhost_dev *dev = vq->dev; |
| 1127 | 1155 | struct vhost_msg_node *node; |
| 1128 | 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 | 1160 | if (!node) |
| 1132 | 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 | 1170 | msg->type = VHOST_IOTLB_MISS; |
| 1136 | 1171 | msg->iova = iova; |
| 1137 | 1172 | msg->perm = access; |
| @@ -132,6 +132,7 @@ struct vhost_virtqueue { · 131 unmodified lines | ||
| 132 | 132 | struct vhost_umem *iotlb; |
| 133 | 133 | void *private_data; |
| 134 | 134 | u64 acked_features; |
| 135 | + u64 acked_backend_features; | |
| 135 | 136 | /* Log write descriptors */ |
| 136 | 137 | void __user *log_base; |
| 137 | 138 | struct vhost_log *log; |
| @@ -147,7 +148,10 @@ struct vhost_virtqueue { · 9 unmodified lines | ||
| 147 | 148 | }; |
| 148 | 149 | |
| 149 | 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 | 155 | struct vhost_virtqueue *vq; |
| 152 | 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 | 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 | 250 | #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY |
| 242 | 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 | 67 | #define VHOST_IOTLB_MSG 0x1 |
| 68 | +#define VHOST_IOTLB_MSG_V2 0x2 | |
| 68 | 69 | |
| 69 | 70 | struct vhost_msg { |
| 70 | 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 | 87 | struct vhost_memory_region { |
| 78 | 88 | __u64 guest_phys_addr; |
| 79 | 89 | __u64 memory_size; /* bytes */ |
| @@ -160,6 +170,14 @@ struct vhost_memory { · 80 unmodified lines | ||
| 160 | 170 | #define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ |
| 161 | 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 | 181 | /* VHOST_NET specific defines */ |
| 164 | 182 | |
| 165 | 183 | /* Attach virtio net ring to a raw socket, or tap device. |