diff options
Diffstat (limited to 'drivers/vfio/vfio.c')
-rw-r--r-- | drivers/vfio/vfio.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 842f4507883e..1eab4ace0671 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -1109,7 +1109,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) | |||
1109 | * We can't use anon_inode_getfd() because we need to modify | 1109 | * We can't use anon_inode_getfd() because we need to modify |
1110 | * the f_mode flags directly to allow more than just ioctls | 1110 | * the f_mode flags directly to allow more than just ioctls |
1111 | */ | 1111 | */ |
1112 | ret = get_unused_fd(); | 1112 | ret = get_unused_fd_flags(O_CLOEXEC); |
1113 | if (ret < 0) { | 1113 | if (ret < 0) { |
1114 | device->ops->release(device->device_data); | 1114 | device->ops->release(device->device_data); |
1115 | break; | 1115 | break; |
@@ -1353,6 +1353,68 @@ static const struct file_operations vfio_device_fops = { | |||
1353 | }; | 1353 | }; |
1354 | 1354 | ||
1355 | /** | 1355 | /** |
1356 | * External user API, exported by symbols to be linked dynamically. | ||
1357 | * | ||
1358 | * The protocol includes: | ||
1359 | * 1. do normal VFIO init operation: | ||
1360 | * - opening a new container; | ||
1361 | * - attaching group(s) to it; | ||
1362 | * - setting an IOMMU driver for a container. | ||
1363 | * When IOMMU is set for a container, all groups in it are | ||
1364 | * considered ready to use by an external user. | ||
1365 | * | ||
1366 | * 2. User space passes a group fd to an external user. | ||
1367 | * The external user calls vfio_group_get_external_user() | ||
1368 | * to verify that: | ||
1369 | * - the group is initialized; | ||
1370 | * - IOMMU is set for it. | ||
1371 | * If both checks passed, vfio_group_get_external_user() | ||
1372 | * increments the container user counter to prevent | ||
1373 | * the VFIO group from disposal before KVM exits. | ||
1374 | * | ||
1375 | * 3. The external user calls vfio_external_user_iommu_id() | ||
1376 | * to know an IOMMU ID. | ||
1377 | * | ||
1378 | * 4. When the external KVM finishes, it calls | ||
1379 | * vfio_group_put_external_user() to release the VFIO group. | ||
1380 | * This call decrements the container user counter. | ||
1381 | */ | ||
1382 | struct vfio_group *vfio_group_get_external_user(struct file *filep) | ||
1383 | { | ||
1384 | struct vfio_group *group = filep->private_data; | ||
1385 | |||
1386 | if (filep->f_op != &vfio_group_fops) | ||
1387 | return ERR_PTR(-EINVAL); | ||
1388 | |||
1389 | if (!atomic_inc_not_zero(&group->container_users)) | ||
1390 | return ERR_PTR(-EINVAL); | ||
1391 | |||
1392 | if (!group->container->iommu_driver || | ||
1393 | !vfio_group_viable(group)) { | ||
1394 | atomic_dec(&group->container_users); | ||
1395 | return ERR_PTR(-EINVAL); | ||
1396 | } | ||
1397 | |||
1398 | vfio_group_get(group); | ||
1399 | |||
1400 | return group; | ||
1401 | } | ||
1402 | EXPORT_SYMBOL_GPL(vfio_group_get_external_user); | ||
1403 | |||
1404 | void vfio_group_put_external_user(struct vfio_group *group) | ||
1405 | { | ||
1406 | vfio_group_put(group); | ||
1407 | vfio_group_try_dissolve_container(group); | ||
1408 | } | ||
1409 | EXPORT_SYMBOL_GPL(vfio_group_put_external_user); | ||
1410 | |||
1411 | int vfio_external_user_iommu_id(struct vfio_group *group) | ||
1412 | { | ||
1413 | return iommu_group_id(group->iommu_group); | ||
1414 | } | ||
1415 | EXPORT_SYMBOL_GPL(vfio_external_user_iommu_id); | ||
1416 | |||
1417 | /** | ||
1356 | * Module/class support | 1418 | * Module/class support |
1357 | */ | 1419 | */ |
1358 | static char *vfio_devnode(struct device *dev, umode_t *mode) | 1420 | static char *vfio_devnode(struct device *dev, umode_t *mode) |