diff options
| -rw-r--r-- | drivers/vfio/vfio.c | 91 |
1 files changed, 54 insertions, 37 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 2fb29dfeffbd..563c510f285c 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
| @@ -689,6 +689,23 @@ struct vfio_device *vfio_device_get_from_dev(struct device *dev) | |||
| 689 | } | 689 | } |
| 690 | EXPORT_SYMBOL_GPL(vfio_device_get_from_dev); | 690 | EXPORT_SYMBOL_GPL(vfio_device_get_from_dev); |
| 691 | 691 | ||
| 692 | static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group, | ||
| 693 | char *buf) | ||
| 694 | { | ||
| 695 | struct vfio_device *device; | ||
| 696 | |||
| 697 | mutex_lock(&group->device_lock); | ||
| 698 | list_for_each_entry(device, &group->device_list, group_next) { | ||
| 699 | if (!strcmp(dev_name(device->dev), buf)) { | ||
| 700 | vfio_device_get(device); | ||
| 701 | break; | ||
| 702 | } | ||
| 703 | } | ||
| 704 | mutex_unlock(&group->device_lock); | ||
| 705 | |||
| 706 | return device; | ||
| 707 | } | ||
| 708 | |||
| 692 | /* | 709 | /* |
| 693 | * Caller must hold a reference to the vfio_device | 710 | * Caller must hold a reference to the vfio_device |
| 694 | */ | 711 | */ |
| @@ -1198,53 +1215,53 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) | |||
| 1198 | { | 1215 | { |
| 1199 | struct vfio_device *device; | 1216 | struct vfio_device *device; |
| 1200 | struct file *filep; | 1217 | struct file *filep; |
| 1201 | int ret = -ENODEV; | 1218 | int ret; |
| 1202 | 1219 | ||
| 1203 | if (0 == atomic_read(&group->container_users) || | 1220 | if (0 == atomic_read(&group->container_users) || |
| 1204 | !group->container->iommu_driver || !vfio_group_viable(group)) | 1221 | !group->container->iommu_driver || !vfio_group_viable(group)) |
| 1205 | return -EINVAL; | 1222 | return -EINVAL; |
| 1206 | 1223 | ||
| 1207 | mutex_lock(&group->device_lock); | 1224 | device = vfio_device_get_from_name(group, buf); |
| 1208 | list_for_each_entry(device, &group->device_list, group_next) { | 1225 | if (!device) |
| 1209 | if (strcmp(dev_name(device->dev), buf)) | 1226 | return -ENODEV; |
| 1210 | continue; | ||
| 1211 | 1227 | ||
| 1212 | ret = device->ops->open(device->device_data); | 1228 | ret = device->ops->open(device->device_data); |
| 1213 | if (ret) | 1229 | if (ret) { |
| 1214 | break; | 1230 | vfio_device_put(device); |
| 1215 | /* | 1231 | return ret; |
| 1216 | * We can't use anon_inode_getfd() because we need to modify | 1232 | } |
| 1217 | * the f_mode flags directly to allow more than just ioctls | ||
| 1218 | */ | ||
| 1219 | ret = get_unused_fd_flags(O_CLOEXEC); | ||
| 1220 | if (ret < 0) { | ||
| 1221 | device->ops->release(device->device_data); | ||
| 1222 | break; | ||
| 1223 | } | ||
| 1224 | 1233 | ||
| 1225 | filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops, | 1234 | /* |
| 1226 | device, O_RDWR); | 1235 | * We can't use anon_inode_getfd() because we need to modify |
| 1227 | if (IS_ERR(filep)) { | 1236 | * the f_mode flags directly to allow more than just ioctls |
| 1228 | put_unused_fd(ret); | 1237 | */ |
| 1229 | ret = PTR_ERR(filep); | 1238 | ret = get_unused_fd_flags(O_CLOEXEC); |
| 1230 | device->ops->release(device->device_data); | 1239 | if (ret < 0) { |
| 1231 | break; | 1240 | device->ops->release(device->device_data); |
| 1232 | } | 1241 | vfio_device_put(device); |
| 1242 | return ret; | ||
| 1243 | } | ||
| 1233 | 1244 | ||
| 1234 | /* | 1245 | filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops, |
| 1235 | * TODO: add an anon_inode interface to do this. | 1246 | device, O_RDWR); |
| 1236 | * Appears to be missing by lack of need rather than | 1247 | if (IS_ERR(filep)) { |
| 1237 | * explicitly prevented. Now there's need. | 1248 | put_unused_fd(ret); |
| 1238 | */ | 1249 | ret = PTR_ERR(filep); |
| 1239 | filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); | 1250 | device->ops->release(device->device_data); |
| 1251 | vfio_device_put(device); | ||
| 1252 | return ret; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /* | ||
| 1256 | * TODO: add an anon_inode interface to do this. | ||
| 1257 | * Appears to be missing by lack of need rather than | ||
| 1258 | * explicitly prevented. Now there's need. | ||
| 1259 | */ | ||
| 1260 | filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); | ||
| 1240 | 1261 | ||
| 1241 | vfio_device_get(device); | 1262 | atomic_inc(&group->container_users); |
| 1242 | atomic_inc(&group->container_users); | ||
| 1243 | 1263 | ||
| 1244 | fd_install(ret, filep); | 1264 | fd_install(ret, filep); |
| 1245 | break; | ||
| 1246 | } | ||
| 1247 | mutex_unlock(&group->device_lock); | ||
| 1248 | 1265 | ||
| 1249 | return ret; | 1266 | return ret; |
| 1250 | } | 1267 | } |
