summaryrefslogtreecommitdiff
path: root/src/gallium/winsys/sw
diff options
context:
space:
mode:
authorLepton Wu <lepton@chromium.org>2018-03-19 15:01:30 -0700
committerEmil Velikov <emil.l.velikov@gmail.com>2018-03-22 18:10:42 +0000
commitd891f28df9a4efeda47ee307e7b13147597e8863 (patch)
tree207737624acc4488a11daf094cecf972c162b768 /src/gallium/winsys/sw
parent4db269f30c2b8859fcf111ee2da6979dbb6794e8 (diff)
gallium/winsys/kms: Fix possible leak in map/unmap.
If user calls map twice for kms_sw_displaytarget, the first mapped buffer could get leaked. Instead of calling mmap every time, just reuse previous mapping. Since user could map same displaytarget with different flags, we have to keep two different pointers, one for rw mapping and one for ro mapping. Also introduce reference count for mapped buffer so we can unmap them at right time. v2: - avoid duplicated mapping and leaked mapping (Tomasz) v3: - split from larger patch (Emil) v4: - remove munmap from dt_destory (Emil) v5: - introduce reference count for mapping (Tomasz) - add back munmap in dt_destory v6: - remove change-id in commit message (Tomasz) v7: - remove munmap from dt_destory again (Emil) - add revision history in commit message (Emil) Reviewed-by: Emil Velikov <emil.velikov@collabora.com> Reviewed-by: Tomasz Figa <tfiga@chromium.org> Signed-off-by: Lepton Wu <lepton@chromium.org>
Diffstat (limited to 'src/gallium/winsys/sw')
-rw-r--r--src/gallium/winsys/sw/kms-dri/kms_dri_sw_winsys.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/src/gallium/winsys/sw/kms-dri/kms_dri_sw_winsys.c b/src/gallium/winsys/sw/kms-dri/kms_dri_sw_winsys.c
index 22e1c936ac5..f7bad06edb2 100644
--- a/src/gallium/winsys/sw/kms-dri/kms_dri_sw_winsys.c
+++ b/src/gallium/winsys/sw/kms-dri/kms_dri_sw_winsys.c
@@ -70,8 +70,10 @@ struct kms_sw_displaytarget
uint32_t handle;
void *mapped;
+ void *ro_mapped;
int ref_count;
+ int map_count;
struct list_head link;
};
@@ -170,6 +172,10 @@ kms_sw_displaytarget_destroy(struct sw_winsys *ws,
if (kms_sw_dt->ref_count > 0)
return;
+ if (kms_sw_dt->map_count > 0) {
+ DEBUG_PRINT("KMS-DEBUG: leaked map buffer %u\n", kms_sw_dt->handle);
+ }
+
memset(&destroy_req, 0, sizeof destroy_req);
destroy_req.handle = kms_sw_dt->handle;
drmIoctl(kms_sw->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
@@ -198,16 +204,21 @@ kms_sw_displaytarget_map(struct sw_winsys *ws,
return NULL;
prot = (flags == PIPE_TRANSFER_READ) ? PROT_READ : (PROT_READ | PROT_WRITE);
- kms_sw_dt->mapped = mmap(0, kms_sw_dt->size, prot, MAP_SHARED,
- kms_sw->fd, map_req.offset);
-
- if (kms_sw_dt->mapped == MAP_FAILED)
- return NULL;
+ void **ptr = (flags == PIPE_TRANSFER_READ) ? &kms_sw_dt->ro_mapped : &kms_sw_dt->mapped;
+ if (!*ptr) {
+ void *tmp = mmap(0, kms_sw_dt->size, prot, MAP_SHARED,
+ kms_sw->fd, map_req.offset);
+ if (tmp == MAP_FAILED)
+ return NULL;
+ *ptr = tmp;
+ }
DEBUG_PRINT("KMS-DEBUG: mapped buffer %u (size %u) at %p\n",
- kms_sw_dt->handle, kms_sw_dt->size, kms_sw_dt->mapped);
+ kms_sw_dt->handle, kms_sw_dt->size, *ptr);
+
+ kms_sw_dt->map_count++;
- return kms_sw_dt->mapped;
+ return *ptr;
}
static struct kms_sw_displaytarget *
@@ -277,10 +288,23 @@ kms_sw_displaytarget_unmap(struct sw_winsys *ws,
{
struct kms_sw_displaytarget *kms_sw_dt = kms_sw_displaytarget(dt);
+ if (!kms_sw_dt->map_count) {
+ DEBUG_PRINT("KMS-DEBUG: ignore duplicated unmap %u", kms_sw_dt->handle);
+ return;
+ }
+ kms_sw_dt->map_count--;
+ if (kms_sw_dt->map_count) {
+ DEBUG_PRINT("KMS-DEBUG: ignore unmap for busy buffer %u", kms_sw_dt->handle);
+ return;
+ }
+
DEBUG_PRINT("KMS-DEBUG: unmapped buffer %u (was %p)\n", kms_sw_dt->handle, kms_sw_dt->mapped);
+ DEBUG_PRINT("KMS-DEBUG: unmapped buffer %u (was %p)\n", kms_sw_dt->handle, kms_sw_dt->ro_mapped);
munmap(kms_sw_dt->mapped, kms_sw_dt->size);
kms_sw_dt->mapped = NULL;
+ munmap(kms_sw_dt->ro_mapped, kms_sw_dt->size);
+ kms_sw_dt->ro_mapped = NULL;
}
static struct sw_displaytarget *