Skip to content

Commit 309bba3

Browse files
stefano-garzarellamstsirkin
authored andcommitted
vringh: iterate on iotlb_translate to handle large translations
iotlb_translate() can return -ENOBUFS if the bio_vec is not big enough to contain all the ranges for translation. This can happen for example if the VMM maps a large bounce buffer, without using hugepages, that requires more than 16 ranges to translate the addresses. To handle this case, let's extend iotlb_translate() to also return the number of bytes successfully translated. In copy_from_iotlb()/copy_to_iotlb() loops by calling iotlb_translate() several times until we complete the translation. Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Message-Id: <20220624075656.13997-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 96ef18a commit 309bba3

File tree

1 file changed

+56
-22
lines changed

1 file changed

+56
-22
lines changed

drivers/vhost/vringh.c

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,8 @@ EXPORT_SYMBOL(vringh_need_notify_kern);
10951095
#if IS_REACHABLE(CONFIG_VHOST_IOTLB)
10961096

10971097
static int iotlb_translate(const struct vringh *vrh,
1098-
u64 addr, u64 len, struct bio_vec iov[],
1098+
u64 addr, u64 len, u64 *translated,
1099+
struct bio_vec iov[],
10991100
int iov_size, u32 perm)
11001101
{
11011102
struct vhost_iotlb_map *map;
@@ -1136,43 +1137,76 @@ static int iotlb_translate(const struct vringh *vrh,
11361137

11371138
spin_unlock(vrh->iotlb_lock);
11381139

1140+
if (translated)
1141+
*translated = min(len, s);
1142+
11391143
return ret;
11401144
}
11411145

11421146
static inline int copy_from_iotlb(const struct vringh *vrh, void *dst,
11431147
void *src, size_t len)
11441148
{
1145-
struct iov_iter iter;
1146-
struct bio_vec iov[16];
1147-
int ret;
1149+
u64 total_translated = 0;
11481150

1149-
ret = iotlb_translate(vrh, (u64)(uintptr_t)src,
1150-
len, iov, 16, VHOST_MAP_RO);
1151-
if (ret < 0)
1152-
return ret;
1151+
while (total_translated < len) {
1152+
struct bio_vec iov[16];
1153+
struct iov_iter iter;
1154+
u64 translated;
1155+
int ret;
11531156

1154-
iov_iter_bvec(&iter, READ, iov, ret, len);
1157+
ret = iotlb_translate(vrh, (u64)(uintptr_t)src,
1158+
len - total_translated, &translated,
1159+
iov, ARRAY_SIZE(iov), VHOST_MAP_RO);
1160+
if (ret == -ENOBUFS)
1161+
ret = ARRAY_SIZE(iov);
1162+
else if (ret < 0)
1163+
return ret;
11551164

1156-
ret = copy_from_iter(dst, len, &iter);
1165+
iov_iter_bvec(&iter, READ, iov, ret, translated);
11571166

1158-
return ret;
1167+
ret = copy_from_iter(dst, translated, &iter);
1168+
if (ret < 0)
1169+
return ret;
1170+
1171+
src += translated;
1172+
dst += translated;
1173+
total_translated += translated;
1174+
}
1175+
1176+
return total_translated;
11591177
}
11601178

11611179
static inline int copy_to_iotlb(const struct vringh *vrh, void *dst,
11621180
void *src, size_t len)
11631181
{
1164-
struct iov_iter iter;
1165-
struct bio_vec iov[16];
1166-
int ret;
1182+
u64 total_translated = 0;
11671183

1168-
ret = iotlb_translate(vrh, (u64)(uintptr_t)dst,
1169-
len, iov, 16, VHOST_MAP_WO);
1170-
if (ret < 0)
1171-
return ret;
1184+
while (total_translated < len) {
1185+
struct bio_vec iov[16];
1186+
struct iov_iter iter;
1187+
u64 translated;
1188+
int ret;
1189+
1190+
ret = iotlb_translate(vrh, (u64)(uintptr_t)dst,
1191+
len - total_translated, &translated,
1192+
iov, ARRAY_SIZE(iov), VHOST_MAP_WO);
1193+
if (ret == -ENOBUFS)
1194+
ret = ARRAY_SIZE(iov);
1195+
else if (ret < 0)
1196+
return ret;
11721197

1173-
iov_iter_bvec(&iter, WRITE, iov, ret, len);
1198+
iov_iter_bvec(&iter, WRITE, iov, ret, translated);
1199+
1200+
ret = copy_to_iter(src, translated, &iter);
1201+
if (ret < 0)
1202+
return ret;
1203+
1204+
src += translated;
1205+
dst += translated;
1206+
total_translated += translated;
1207+
}
11741208

1175-
return copy_to_iter(src, len, &iter);
1209+
return total_translated;
11761210
}
11771211

11781212
static inline int getu16_iotlb(const struct vringh *vrh,
@@ -1183,7 +1217,7 @@ static inline int getu16_iotlb(const struct vringh *vrh,
11831217
int ret;
11841218

11851219
/* Atomic read is needed for getu16 */
1186-
ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p),
1220+
ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL,
11871221
&iov, 1, VHOST_MAP_RO);
11881222
if (ret < 0)
11891223
return ret;
@@ -1204,7 +1238,7 @@ static inline int putu16_iotlb(const struct vringh *vrh,
12041238
int ret;
12051239

12061240
/* Atomic write is needed for putu16 */
1207-
ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p),
1241+
ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL,
12081242
&iov, 1, VHOST_MAP_WO);
12091243
if (ret < 0)
12101244
return ret;

0 commit comments

Comments
 (0)