Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7cdf5c8 authored by Chris Wilson's avatar Chris Wilson Committed by Dave Airlie
Browse files

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: default avatarDave Airlie <airlied@redhat.com>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Tested-by: default avatarDave Airlie <airlied@redhat.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 12e412d7
Loading
Loading
Loading
Loading
+29 −48
Original line number Diff line number Diff line
@@ -369,40 +369,26 @@ static const struct file_operations drm_syncobj_file_fops = {
	.release = drm_syncobj_file_release,
};

static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj)
{
	struct file *file = anon_inode_getfile("syncobj_file",
					       &drm_syncobj_file_fops,
					       syncobj, 0);
	if (IS_ERR(file))
		return PTR_ERR(file);

	drm_syncobj_get(syncobj);
	if (cmpxchg(&syncobj->file, NULL, file)) {
		/* lost the race */
		fput(file);
	}

	return 0;
}

int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
{
	int ret;
	struct file *file;
	int fd;

	fd = get_unused_fd_flags(O_CLOEXEC);
	if (fd < 0)
		return fd;

	if (!syncobj->file) {
		ret = drm_syncobj_alloc_file(syncobj);
		if (ret) {
	file = anon_inode_getfile("syncobj_file",
				  &drm_syncobj_file_fops,
				  syncobj, 0);
	if (IS_ERR(file)) {
		put_unused_fd(fd);
			return ret;
		}
		return PTR_ERR(file);
	}
	fd_install(fd, syncobj->file);

	drm_syncobj_get(syncobj);
	fd_install(fd, file);

	*p_fd = fd;
	return 0;
}
@@ -422,31 +408,24 @@ static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
	return ret;
}

static struct drm_syncobj *drm_syncobj_fdget(int fd)
{
	struct file *file = fget(fd);

	if (!file)
		return NULL;
	if (file->f_op != &drm_syncobj_file_fops)
		goto err;

	return file->private_data;
err:
	fput(file);
	return NULL;
};

static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
				    int fd, u32 *handle)
{
	struct drm_syncobj *syncobj = drm_syncobj_fdget(fd);
	struct drm_syncobj *syncobj;
	struct file *file;
	int ret;

	if (!syncobj)
	file = fget(fd);
	if (!file)
		return -EINVAL;

	if (file->f_op != &drm_syncobj_file_fops) {
		fput(file);
		return -EINVAL;
	}

	/* take a reference to put in the idr */
	syncobj = file->private_data;
	drm_syncobj_get(syncobj);

	idr_preload(GFP_KERNEL);
@@ -455,12 +434,14 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
	spin_unlock(&file_private->syncobj_table_lock);
	idr_preload_end();

	if (ret < 0) {
		fput(syncobj->file);
		return ret;
	}
	if (ret > 0) {
		*handle = ret;
	return 0;
		ret = 0;
	} else
		drm_syncobj_put(syncobj);

	fput(file);
	return ret;
}

static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,