Hi Emil, 2016-02-27 Emil Velikov <emil.l.velikov@xxxxxxxxx>: > Hi Gustavo, > > On 26 February 2016 at 21:00, Gustavo Padovan <gustavo@xxxxxxxxxxx> wrote: > > From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> > > > > Change SYNC_IOC_FILE_INFO behaviour to avoid future API breaks and > > optimize buffer allocation. In the new approach the ioctl needs to be called > > twice to retrieve the array of fence_infos pointed by info->sync_fence_info. > > > I might have misunderstood things but I no one says you "need" to call > it twice - you can just request a "random" amount of fences_info. Upon > return (if num_fences was non zero) it will report how many fence_info > were retrieved. Right, I don't see any problem doing it in one request, I just didn't think about that in the new proposal. I'll update the code and commit message accordinly. > > > The first call should pass num_fences = 0, the kernel will then fill > > info->num_fences. Userspace receives back the number of fences and > > allocates a buffer size num_fences * sizeof(struct sync_fence_info) on > > info->sync_fence_info. > > > > It then call the ioctl again passing num_fences received in info->num_fences. > "calls" > > > The kernel checks if info->num_fences > 0 and if yes it fill > > info->sync_fence_info with an array containing all fence_infos. > > > The above sentence sounds a bit strange. I believe you meant to say > something like "Then the kernel fills the fence_infos array with data. > One should read back the actual number from info->num_fences." ? > > > info->len now represents the length of the buffer sync_fence_info points > > to. > Now that I think about it, I'm wondering if there'll be a case where > len != info->num_fences * sizeof(struct sync_file_info). If that's not > possible one could just drop len and nicely simplify things. > > > Also, info->sync_fence_info was converted to __u64 pointer. > > > ... pointer to prevent 32bit compatibility issues. > > > An example userspace code would be: > > > > struct sync_file_info *info; > > int err, size, num_fences; > > > > info = malloc(sizeof(*info)); > > > > memset(info, 0, sizeof(*info)); > > > > err = ioctl(fd, SYNC_IOC_FILE_INFO, info); > > num_fences = info->num_fences; > > > > if (num_fences) { > > memset(info, 0, sizeof(*info)); > > size = sizeof(struct sync_fence_info) * num_fences; > > info->len = size; > > info->num_fences = num_fences; > > info->sync_fence_info = (uint64_t) calloc(num_fences, > > sizeof(struct sync_fence_info)); > > > > err = ioctl(fd, SYNC_IOC_FILE_INFO, info); > > } > > > > v2: fix fence_info memory leak > > > > Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> > > --- > > drivers/staging/android/sync.c | 52 +++++++++++++++++++++++++++++-------- > > drivers/staging/android/uapi/sync.h | 9 +++---- > > 2 files changed, 45 insertions(+), 16 deletions(-) > > > > diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c > > index dc5f382..2379f23 100644 > > --- a/drivers/staging/android/sync.c > > +++ b/drivers/staging/android/sync.c > > @@ -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 = NULL; > > __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))) > s/*info/in/ > > > return -EFAULT; > > > > - if (size < sizeof(struct sync_file_info)) > > - return -EINVAL; > > + if (in.status || strcmp(in.name, "\0")) > Afaict these two are outputs, so we should be checking them ? Hmm. Maybe not. > > > + return -EFAULT; > > > As originally, input validation should return -EINVAL on error. > > > > - if (size > 4096) > > - size = 4096; > > + if (in.num_fences && !in.sync_fence_info) > > + return -EFAULT; > > > Ditto. > > > - info = kzalloc(size, GFP_KERNEL); > > + info = kzalloc(sizeof(*info), GFP_KERNEL); > > if (!info) > > return -ENOMEM; > > > > @@ -525,14 +526,33 @@ 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; > > + > We should clamp in.num_fences to min2(in.num_fences, > sync_file->num_fences) and use it over sync_file->num_fences though > the rest of the function. Or just bail out when the two are not the > same. > > Depends on what the planned semantics are. Fwiw I'm leaning towards the former. If num_fences received is smaller than the actual num_fences I think we should fails, otherwise we should just fill the buffer with all fence_infos... > > > + size = sync_file->num_fences * sizeof(*fence_info); > > + if (in.len != size) { > > + ret = -EFAULT; > EINVAL or just drop len from the struct. ...so this check now would be in.len < size. > > > + goto out; > > + } > > > > - len = sizeof(struct sync_file_info); > > + 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, > A few comments about sync_fill_fence_info() > - Internal function so make the second argument of the correct type - > struct sync_fence_info * > - Drop the third argument size, as that one is always sizeof(sync_fence_info). > - Remove the size checking in the same function and make its return type void > > Then one can simplify this loop even further :-) Sounds good to me. > > > + size - len); > > > > if (ret < 0) > > goto out; > > @@ -540,14 +560,24 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, > > len += ret; > > } > > > > + if (copy_to_user((void __user *)in.sync_fence_info, fence_info, size)) { > > + ret = -EFAULT; > > + goto out; > > + } > > + > > info->len = len; > > + info->sync_fence_info = (__u64) in.sync_fence_info; > Why the cast ? > > > + > > +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))) > Don't know if we should be returning (copying) any other information > but info->num_fences in case of "no_fences". In case it's not clear - > I'm thinking about the data we already have in in info->name and > info->status. Userspace might want to know all info about the sync_file but sync_fence_info. Gustavo _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel