@@ -502,21 +502,22 @@ static int sync_fill_fence_info(struct fence *fence, void *data, int size)
static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
unsigned long arg)
{
- struct sync_file_info *info;
+ struct sync_file_info in, *info;
+ struct sync_fence_info *fence_info;
__u32 size;
__u32 len = 0;
int ret, i;
- if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
+ if (copy_from_user(&in, (void __user *)arg, sizeof(*info)))
return -EFAULT;
- if (size < sizeof(struct sync_file_info))
- return -EINVAL;
+ if (in.status || strcmp(in.name, "\0"))
+ return -EFAULT;
- if (size > 4096)
- size = 4096;
+ if (in.num_fences && !in.sync_fence_info)
+ return -EFAULT;
- info = kzalloc(size, GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -525,24 +526,55 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
if (info->status >= 0)
info->status = !info->status;
- info->num_fences = sync_file->num_fences;
+ /*
+ * Passing num_fences = 0 means that userspace want to know how
+ * many fences are in the sync_file to be able to allocate a buffer to
+ * fit all sync_fence_infos and call the ioctl again with the buffer
+ * assigned to info->sync_fence_info. The second call pass the
+ * num_fences value received in the first call.
+ */
+ if (!in.num_fences)
+ goto no_fences;
- len = sizeof(struct sync_file_info);
+ size = sync_file->num_fences * sizeof(*fence_info);
+ if (in.len != size) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ fence_info = kzalloc(size, GFP_KERNEL);
+ if (!fence_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < sync_file->num_fences; ++i) {
struct fence *fence = sync_file->cbs[i].fence;
- ret = sync_fill_fence_info(fence, (u8 *)info + len, size - len);
+ ret = sync_fill_fence_info(fence, (u8 *)fence_info + len,
+ size - len);
- if (ret < 0)
+ if (ret < 0) {
+ kfree(fence_info);
goto out;
+ }
len += ret;
}
+ if (copy_to_user((void __user *)in.sync_fence_info, fence_info, size)) {
+ ret = -EFAULT;
+ kfree(fence_info);
+ goto out;
+ }
+
info->len = len;
+ info->sync_fence_info = (__u64) in.sync_fence_info;
+
+no_fences:
+ info->num_fences = sync_file->num_fences;
- if (copy_to_user((void __user *)arg, info, len))
+ if (copy_to_user((void __user *)arg, info, sizeof(*info)))
ret = -EFAULT;
else
ret = 0;
@@ -42,21 +42,20 @@ struct sync_fence_info {
/**
* struct sync_file_info - data returned from fence info ioctl
- * @len: ioctl caller writes the size of the buffer its passing in.
- * ioctl returns length of sync_file_info returned to
- * userspace including pt_info.
* @name: name of fence
* @status: status of fence. 1: signaled 0:active <0:error
* @num_fences number of fences in the sync_file
+ * @len: ioctl caller writes the size of the buffer its passing in.
+ * ioctl returns length of all fence_infos summed.
* @sync_fence_info: array of sync_fence_info for every fence in the sync_file
*/
struct sync_file_info {
- __u32 len;
char name[32];
__s32 status;
__u32 num_fences;
+ __u32 len;
- __u8 sync_fence_info[0];
+ __u64 sync_fence_info;
};
#define SYNC_IOC_MAGIC '>'