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

sync_file: Return consistent status in SYNC_IOC_FILE_INFO

sync_file_ioctl_fence_info has a race between filling the status
of the underlying fences and the overall status of the sync_file.
If fence transitions in the time frame between its sync_fill_fence_info
and the later dma_fence_is_signaled for the sync_file, the returned
information is inconsistent showing non-signaled underlying fences but
an overall signaled state.

This patch changes sync_file_ioctl_fence_info to track what has been
encoded and using that as the overall sync_file status.

Tested-by: Vamsidhar Reddy Gaddam <vamsidhar.gaddam@arm.com>
Signed-off-by: John Einar Reitan <john.reitan@arm.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Gustavo Padovan <gustavo@padovan.org>
Cc: dri-devel@lists.freedesktop.org
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171009134936.27219-1-john.reitan@arm.com

authored by

John Einar Reitan and committed by
Gustavo Padovan
f7974880 78279127

+12 -5
+12 -5
drivers/dma-buf/sync_file.c
··· 383 383 return err; 384 384 } 385 385 386 - static void sync_fill_fence_info(struct dma_fence *fence, 386 + static int sync_fill_fence_info(struct dma_fence *fence, 387 387 struct sync_fence_info *info) 388 388 { 389 389 strlcpy(info->obj_name, fence->ops->get_timeline_name(fence), ··· 399 399 test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ? 400 400 ktime_to_ns(fence->timestamp) : 401 401 ktime_set(0, 0); 402 + 403 + return info->status; 402 404 } 403 405 404 406 static long sync_file_ioctl_fence_info(struct sync_file *sync_file, ··· 426 424 * sync_fence_info and return the actual number of fences on 427 425 * info->num_fences. 428 426 */ 429 - if (!info.num_fences) 427 + if (!info.num_fences) { 428 + info.status = dma_fence_is_signaled(sync_file->fence); 430 429 goto no_fences; 430 + } else { 431 + info.status = 1; 432 + } 431 433 432 434 if (info.num_fences < num_fences) 433 435 return -EINVAL; ··· 441 435 if (!fence_info) 442 436 return -ENOMEM; 443 437 444 - for (i = 0; i < num_fences; i++) 445 - sync_fill_fence_info(fences[i], &fence_info[i]); 438 + for (i = 0; i < num_fences; i++) { 439 + int status = sync_fill_fence_info(fences[i], &fence_info[i]); 440 + info.status = info.status <= 0 ? info.status : status; 441 + } 446 442 447 443 if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info, 448 444 size)) { ··· 454 446 455 447 no_fences: 456 448 sync_file_get_name(sync_file, info.name, sizeof(info.name)); 457 - info.status = dma_fence_is_signaled(sync_file->fence); 458 449 info.num_fences = num_fences; 459 450 460 451 if (copy_to_user((void __user *)arg, &info, sizeof(info)))