r300g: fix a possible race condition when mapping a buffer
This is the last one I think.
This commit is contained in:
@@ -107,6 +107,7 @@ void radeon_bo_unref(struct radeon_bo *bo)
|
||||
/* Close object. */
|
||||
args.handle = bo->handle;
|
||||
drmIoctl(bo->rws->fd, DRM_IOCTL_GEM_CLOSE, &args);
|
||||
pipe_mutex_destroy(bo->map_mutex);
|
||||
FREE(bo);
|
||||
}
|
||||
|
||||
@@ -156,6 +157,7 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
|
||||
struct radeon_bo *bo = radeon_bo(_buf);
|
||||
struct radeon_drm_cs *cs = flush_ctx;
|
||||
struct drm_radeon_gem_mmap args = {};
|
||||
void *ptr;
|
||||
/* prevents a call to radeon_bo_wait if (usage & DONTBLOCK) and
|
||||
* radeon_is_busy returns FALSE. */
|
||||
boolean may_be_busy = TRUE;
|
||||
@@ -182,31 +184,35 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
|
||||
radeon_bo_wait((struct r300_winsys_bo*)bo);
|
||||
}
|
||||
|
||||
/* Map buffer if it's not already mapped. */
|
||||
/* XXX We may get a race in bo->ptr. */
|
||||
if (!bo->ptr) {
|
||||
void *ptr;
|
||||
/* Return the pointer if it's already mapped. */
|
||||
if (bo->ptr)
|
||||
return bo->ptr;
|
||||
|
||||
args.handle = bo->handle;
|
||||
args.offset = 0;
|
||||
args.size = (uint64_t)bo->size;
|
||||
if (drmCommandWriteRead(bo->rws->fd,
|
||||
DRM_RADEON_GEM_MMAP,
|
||||
&args,
|
||||
sizeof(args))) {
|
||||
fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
|
||||
bo, bo->handle);
|
||||
return NULL;
|
||||
}
|
||||
ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
|
||||
bo->rws->fd, args.addr_ptr);
|
||||
if (ptr == MAP_FAILED) {
|
||||
fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
|
||||
return NULL;
|
||||
}
|
||||
bo->ptr = ptr;
|
||||
/* Map the buffer. */
|
||||
pipe_mutex_lock(bo->map_mutex);
|
||||
args.handle = bo->handle;
|
||||
args.offset = 0;
|
||||
args.size = (uint64_t)bo->size;
|
||||
if (drmCommandWriteRead(bo->rws->fd,
|
||||
DRM_RADEON_GEM_MMAP,
|
||||
&args,
|
||||
sizeof(args))) {
|
||||
pipe_mutex_unlock(bo->map_mutex);
|
||||
fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
|
||||
bo, bo->handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
|
||||
bo->rws->fd, args.addr_ptr);
|
||||
if (ptr == MAP_FAILED) {
|
||||
pipe_mutex_unlock(bo->map_mutex);
|
||||
fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
|
||||
return NULL;
|
||||
}
|
||||
bo->ptr = ptr;
|
||||
pipe_mutex_unlock(bo->map_mutex);
|
||||
|
||||
return bo->ptr;
|
||||
}
|
||||
|
||||
@@ -284,6 +290,7 @@ static struct pb_buffer *radeon_bomgr_create_bo(struct pb_manager *_mgr,
|
||||
bo->rws = mgr->rws;
|
||||
bo->handle = args.handle;
|
||||
bo->size = size;
|
||||
pipe_mutex_init(bo->map_mutex);
|
||||
|
||||
radeon_bo_ref(bo);
|
||||
return &bo->base;
|
||||
@@ -514,6 +521,7 @@ static struct r300_winsys_bo *radeon_winsys_bo_from_handle(struct r300_winsys_sc
|
||||
bo->base.vtbl = &radeon_bo_vtbl;
|
||||
bo->mgr = mgr;
|
||||
bo->rws = mgr->rws;
|
||||
pipe_mutex_init(bo->map_mutex);
|
||||
|
||||
util_hash_table_set(mgr->bo_handles, (void*)(uintptr_t)whandle->handle, bo);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "radeon_winsys.h"
|
||||
#include "pipebuffer/pb_bufmgr.h"
|
||||
#include "os/os_thread.h"
|
||||
|
||||
#define RADEON_PB_USAGE_CACHE (1 << 28)
|
||||
#define RADEON_PB_USAGE_DOMAIN_GTT (1 << 29)
|
||||
@@ -47,6 +48,8 @@ struct radeon_bo {
|
||||
struct radeon_drm_winsys *rws;
|
||||
|
||||
void *ptr;
|
||||
pipe_mutex map_mutex;
|
||||
|
||||
uint32_t size;
|
||||
uint32_t handle;
|
||||
uint32_t name;
|
||||
|
||||
Reference in New Issue
Block a user