Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio: Add get_region_info_caps op

This op does the copy to/from user for the info and can return back
a cap chain through a vfio_info_cap * result.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Pranjal Shrivastava <praan@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/15-v2-2a9e24d62f1b+e10a-vfio_get_region_info_op_jgg@nvidia.com
Signed-off-by: Alex Williamson <alex@shazbot.org>

authored by

Jason Gunthorpe and committed by
Alex Williamson
775f726a f9785950

+56 -4
+52 -4
drivers/vfio/vfio_main.c
··· 1259 1259 } 1260 1260 } 1261 1261 1262 + static long vfio_get_region_info(struct vfio_device *device, 1263 + struct vfio_region_info __user *arg) 1264 + { 1265 + unsigned long minsz = offsetofend(struct vfio_region_info, offset); 1266 + struct vfio_region_info info = {}; 1267 + struct vfio_info_cap caps = {}; 1268 + int ret; 1269 + 1270 + if (copy_from_user(&info, arg, minsz)) 1271 + return -EFAULT; 1272 + if (info.argsz < minsz) 1273 + return -EINVAL; 1274 + 1275 + if (device->ops->get_region_info_caps) { 1276 + ret = device->ops->get_region_info_caps(device, &info, &caps); 1277 + if (ret) 1278 + goto out_free; 1279 + 1280 + if (caps.size) { 1281 + info.flags |= VFIO_REGION_INFO_FLAG_CAPS; 1282 + if (info.argsz < sizeof(info) + caps.size) { 1283 + info.argsz = sizeof(info) + caps.size; 1284 + info.cap_offset = 0; 1285 + } else { 1286 + vfio_info_cap_shift(&caps, sizeof(info)); 1287 + if (copy_to_user(arg + 1, caps.buf, 1288 + caps.size)) { 1289 + ret = -EFAULT; 1290 + goto out_free; 1291 + } 1292 + info.cap_offset = sizeof(info); 1293 + } 1294 + } 1295 + 1296 + if (copy_to_user(arg, &info, minsz)) { 1297 + ret = -EFAULT; 1298 + goto out_free; 1299 + } 1300 + } else if (device->ops->get_region_info) { 1301 + ret = device->ops->get_region_info(device, arg); 1302 + if (ret) 1303 + return ret; 1304 + } else { 1305 + return -EINVAL; 1306 + } 1307 + 1308 + out_free: 1309 + kfree(caps.buf); 1310 + return ret; 1311 + } 1312 + 1262 1313 static long vfio_device_fops_unl_ioctl(struct file *filep, 1263 1314 unsigned int cmd, unsigned long arg) 1264 1315 { ··· 1348 1297 break; 1349 1298 1350 1299 case VFIO_DEVICE_GET_REGION_INFO: 1351 - if (unlikely(!device->ops->get_region_info)) 1352 - ret = -EINVAL; 1353 - else 1354 - ret = device->ops->get_region_info(device, uptr); 1300 + ret = vfio_get_region_info(device, uptr); 1355 1301 break; 1356 1302 1357 1303 default:
+4
include/linux/vfio.h
··· 21 21 struct iommufd_ctx; 22 22 struct iommufd_device; 23 23 struct iommufd_access; 24 + struct vfio_info_cap; 24 25 25 26 /* 26 27 * VFIO devices can be placed in a set, this allows all devices to share this ··· 135 134 unsigned long arg); 136 135 int (*get_region_info)(struct vfio_device *vdev, 137 136 struct vfio_region_info __user *arg); 137 + int (*get_region_info_caps)(struct vfio_device *vdev, 138 + struct vfio_region_info *info, 139 + struct vfio_info_cap *caps); 138 140 int (*mmap)(struct vfio_device *vdev, struct vm_area_struct *vma); 139 141 void (*request)(struct vfio_device *vdev, unsigned int count); 140 142 int (*match)(struct vfio_device *vdev, char *buf);