drm/syncobj: Stop reusing the same struct file for all syncobj -> fd

The vk cts test:
dEQP-VK.api.external.semaphore.opaque_fd.export_multiple_times_temporary

triggers a lot of
VFS: Close: file count is 0

Dave pointed out that clearing the syncobj->file from
drm_syncobj_file_release() was sufficient to silence the test, but that
opens a can of worm since we assumed that the syncobj->file was never
unset. Stop trying to reuse the same struct file for every fd pointing
to the drm_syncobj, and allocate one file for each fd instead.

v2: Fixup return handling of drm_syncobj_fd_to_handle
v2.1: [airlied: fix possible syncobj ref race]

Reported-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Tested-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by Chris Wilson and committed by Dave Airlie e7cdf5c8 12e412d7

+29 -48
+29 -48
drivers/gpu/drm/drm_syncobj.c
··· 369 .release = drm_syncobj_file_release, 370 }; 371 372 - static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj) 373 - { 374 - struct file *file = anon_inode_getfile("syncobj_file", 375 - &drm_syncobj_file_fops, 376 - syncobj, 0); 377 - if (IS_ERR(file)) 378 - return PTR_ERR(file); 379 - 380 - drm_syncobj_get(syncobj); 381 - if (cmpxchg(&syncobj->file, NULL, file)) { 382 - /* lost the race */ 383 - fput(file); 384 - } 385 - 386 - return 0; 387 - } 388 - 389 int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd) 390 { 391 - int ret; 392 int fd; 393 394 fd = get_unused_fd_flags(O_CLOEXEC); 395 if (fd < 0) 396 return fd; 397 398 - if (!syncobj->file) { 399 - ret = drm_syncobj_alloc_file(syncobj); 400 - if (ret) { 401 - put_unused_fd(fd); 402 - return ret; 403 - } 404 } 405 - fd_install(fd, syncobj->file); 406 *p_fd = fd; 407 return 0; 408 } ··· 408 return ret; 409 } 410 411 - static struct drm_syncobj *drm_syncobj_fdget(int fd) 412 - { 413 - struct file *file = fget(fd); 414 - 415 - if (!file) 416 - return NULL; 417 - if (file->f_op != &drm_syncobj_file_fops) 418 - goto err; 419 - 420 - return file->private_data; 421 - err: 422 - fput(file); 423 - return NULL; 424 - }; 425 - 426 static int drm_syncobj_fd_to_handle(struct drm_file *file_private, 427 int fd, u32 *handle) 428 { 429 - struct drm_syncobj *syncobj = drm_syncobj_fdget(fd); 430 int ret; 431 432 - if (!syncobj) 433 return -EINVAL; 434 435 /* take a reference to put in the idr */ 436 drm_syncobj_get(syncobj); 437 438 idr_preload(GFP_KERNEL); ··· 434 spin_unlock(&file_private->syncobj_table_lock); 435 idr_preload_end(); 436 437 - if (ret < 0) { 438 - fput(syncobj->file); 439 - return ret; 440 - } 441 - *handle = ret; 442 - return 0; 443 } 444 445 static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
··· 369 .release = drm_syncobj_file_release, 370 }; 371 372 int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd) 373 { 374 + struct file *file; 375 int fd; 376 377 fd = get_unused_fd_flags(O_CLOEXEC); 378 if (fd < 0) 379 return fd; 380 381 + file = anon_inode_getfile("syncobj_file", 382 + &drm_syncobj_file_fops, 383 + syncobj, 0); 384 + if (IS_ERR(file)) { 385 + put_unused_fd(fd); 386 + return PTR_ERR(file); 387 } 388 + 389 + drm_syncobj_get(syncobj); 390 + fd_install(fd, file); 391 + 392 *p_fd = fd; 393 return 0; 394 } ··· 422 return ret; 423 } 424 425 static int drm_syncobj_fd_to_handle(struct drm_file *file_private, 426 int fd, u32 *handle) 427 { 428 + struct drm_syncobj *syncobj; 429 + struct file *file; 430 int ret; 431 432 + file = fget(fd); 433 + if (!file) 434 return -EINVAL; 435 436 + if (file->f_op != &drm_syncobj_file_fops) { 437 + fput(file); 438 + return -EINVAL; 439 + } 440 + 441 /* take a reference to put in the idr */ 442 + syncobj = file->private_data; 443 drm_syncobj_get(syncobj); 444 445 idr_preload(GFP_KERNEL); ··· 455 spin_unlock(&file_private->syncobj_table_lock); 456 idr_preload_end(); 457 458 + if (ret > 0) { 459 + *handle = ret; 460 + ret = 0; 461 + } else 462 + drm_syncobj_put(syncobj); 463 + 464 + fput(file); 465 + return ret; 466 } 467 468 static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,