--- linux-4.9.37/drivers/dma-buf/sync_file.c 2017-07-12 16:42:41.000000000 +0300 +++ linux-4.9.y/drivers/dma-buf/sync_file.c 2021-06-07 13:01:33.000000000 +0300 @@ -67,9 +67,10 @@ * sync_file_create() - creates a sync file * @fence: fence to add to the sync_fence * - * Creates a sync_file containg @fence. Once this is called, the sync_file - * takes ownership of @fence. The sync_file can be released with - * fput(sync_file->file). Returns the sync_file or NULL in case of error. + * Creates a sync_file containg @fence. This function acquires and additional + * reference of @fence for the newly-created &sync_file, if it succeeds. The + * sync_file can be released with fput(sync_file->file). Returns the + * sync_file or NULL in case of error. */ struct sync_file *sync_file_create(struct fence *fence) { @@ -79,7 +80,7 @@ if (!sync_file) return NULL; - sync_file->fence = fence; + sync_file->fence = fence_get(fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence), @@ -90,14 +91,7 @@ } EXPORT_SYMBOL(sync_file_create); -/** - * sync_file_fdget() - get a sync_file from an fd - * @fd: fd referencing a fence - * - * Ensures @fd references a valid sync_file, increments the refcount of the - * backing file. Returns the sync_file or NULL in case of error. - */ -static struct sync_file *sync_file_fdget(int fd) +struct sync_file *sync_file_fdget(int fd) { struct file *file = fget(fd); @@ -114,6 +108,8 @@ return NULL; } +EXPORT_SYMBOL(sync_file_fdget); + /** * sync_file_get_fence - get the fence related to the sync_file fd * @fd: sync_file fd to get the fence from @@ -305,10 +301,9 @@ poll_wait(file, &sync_file->wq, wait); - if (!poll_does_not_wait(wait) && - !test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { + if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { if (fence_add_callback(sync_file->fence, &sync_file->cb, - fence_check_cb_func) < 0) + fence_check_cb_func) < 0) wake_up_all(&sync_file->wq); } @@ -370,7 +365,7 @@ return err; } -static void sync_fill_fence_info(struct fence *fence, +static int sync_fill_fence_info(struct fence *fence, struct sync_fence_info *info) { strlcpy(info->obj_name, fence->ops->get_timeline_name(fence), @@ -382,6 +377,8 @@ else info->status = 0; info->timestamp_ns = ktime_to_ns(fence->timestamp); + + return info->status; } static long sync_file_ioctl_fence_info(struct sync_file *sync_file, @@ -407,8 +404,12 @@ * sync_fence_info and return the actual number of fences on * info->num_fences. */ - if (!info.num_fences) + if (!info.num_fences) { + info.status = fence_is_signaled(sync_file->fence); goto no_fences; + } else { + info.status = 1; + } if (info.num_fences < num_fences) return -EINVAL; @@ -418,8 +419,10 @@ if (!fence_info) return -ENOMEM; - for (i = 0; i < num_fences; i++) - sync_fill_fence_info(fences[i], &fence_info[i]); + for (i = 0; i < num_fences; i++) { + int status = sync_fill_fence_info(fences[i], &fence_info[i]); + info.status = info.status <= 0 ? info.status : status; + } if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info, size)) { @@ -429,7 +432,6 @@ no_fences: strlcpy(info.name, sync_file->name, sizeof(info.name)); - info.status = fence_is_signaled(sync_file->fence); info.num_fences = num_fences; if (copy_to_user((void __user *)arg, &info, sizeof(info))) @@ -443,12 +445,26 @@ return ret; } +#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) +static long sync_fence_ioctl_wait(struct sync_file *sync_file, unsigned long arg) +{ + __s32 value; + + if (copy_from_user(&value, (void __user *)arg, sizeof(value))) + return -EFAULT; + if(value <= 0) + value = MAX_SCHEDULE_TIMEOUT; + return fence_wait_timeout(sync_file->fence, true, value); +} + static long sync_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct sync_file *sync_file = file->private_data; switch (cmd) { + case SYNC_IOC_WAIT: + return sync_fence_ioctl_wait(sync_file, arg); case SYNC_IOC_MERGE: return sync_file_ioctl_merge(sync_file, arg);