summaryrefslogtreecommitdiffstats
path: root/src/gallium/winsys/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/winsys/nouveau')
-rw-r--r--src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
index 1dfdaacb620..063524655b6 100644
--- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
+++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
@@ -1,4 +1,5 @@
#include <sys/stat.h>
+#include <unistd.h>
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/u_format.h"
@@ -59,7 +60,7 @@ nouveau_drm_screen_create(int fd)
struct nouveau_device *dev = NULL;
struct pipe_screen *(*init)(struct nouveau_device *);
struct nouveau_screen *screen;
- int ret;
+ int ret, dupfd = -1;
pipe_mutex_lock(nouveau_screen_mutex);
if (!fd_tab) {
@@ -75,7 +76,17 @@ nouveau_drm_screen_create(int fd)
return &screen->base;
}
- ret = nouveau_device_wrap(fd, 0, &dev);
+ /* Since the screen re-use is based on the device node and not the fd,
+ * create a copy of the fd to be owned by the device. Otherwise a
+ * scenario could occur where two screens are created, and the first
+ * one is shut down, along with the fd being closed. The second
+ * (identical) screen would now have a reference to the closed fd. We
+ * avoid this by duplicating the original fd. Note that
+ * nouveau_device_wrap does not close the fd in case of a device
+ * creation error.
+ */
+ dupfd = dup(fd);
+ ret = nouveau_device_wrap(dupfd, 1, &dev);
if (ret)
goto err;
@@ -115,6 +126,10 @@ nouveau_drm_screen_create(int fd)
return &screen->base;
err:
+ if (dev)
+ nouveau_device_del(&dev);
+ else if (dupfd >= 0)
+ close(dupfd);
pipe_mutex_unlock(nouveau_screen_mutex);
return NULL;
}