drm: drmGetDevice return correct device on multi GPU setups

Currently drmGetDevice always returns the first device it finds under
/dev/dri/.

Move the target device to the start of the list during iteration. This
way during deduplication it'll preserve its place and will be returned
to the user.

v2: Keep the memory leak separate.
v3: Move the drmFoldDuplicatedDevices description

Signed-off-by: Qiang Yu <Qiang.Yu@amd.com>
[Emil Velikov: move drmFoldDuplicatedDevices description, add
changelog, reword commit message]
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
main
Qiang Yu 2016-07-14 17:10:55 +08:00 committed by Emil Velikov
parent 5d83081948
commit 3c20893daa
1 changed files with 15 additions and 5 deletions

View File

@ -3050,6 +3050,11 @@ free_device:
return ret; return ret;
} }
/* Consider devices located on the same bus as duplicate and fold the respective
* entries into a single one.
*
* Note: this leaves "gaps" in the array, while preserving the length.
*/
static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
{ {
int node_type, i, j; int node_type, i, j;
@ -3088,6 +3093,7 @@ int drmGetDevice(int fd, drmDevicePtr *device)
int maj, min; int maj, min;
int ret, i, node_count; int ret, i, node_count;
int max_count = 16; int max_count = 16;
dev_t find_rdev;
if (fd == -1 || device == NULL) if (fd == -1 || device == NULL)
return -EINVAL; return -EINVAL;
@ -3095,6 +3101,7 @@ int drmGetDevice(int fd, drmDevicePtr *device)
if (fstat(fd, &sbuf)) if (fstat(fd, &sbuf))
return -errno; return -errno;
find_rdev = sbuf.st_rdev;
maj = major(sbuf.st_rdev); maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev); min = minor(sbuf.st_rdev);
@ -3155,17 +3162,21 @@ int drmGetDevice(int fd, drmDevicePtr *device)
local_devices = temp; local_devices = temp;
} }
local_devices[i] = d; /* store target at local_devices[0] for ease to use below */
if (find_rdev == sbuf.st_rdev && i) {
local_devices[i] = local_devices[0];
local_devices[0] = d;
}
else
local_devices[i] = d;
i++; i++;
} }
node_count = i; node_count = i;
/* Fold nodes into a single device if they share the same bus info */
drmFoldDuplicatedDevices(local_devices, node_count); drmFoldDuplicatedDevices(local_devices, node_count);
*device = local_devices[0]; *device = local_devices[0];
for (i = 1; i < node_count && local_devices[i]; i++) drmFreeDevices(&local_devices[1], node_count - 1);
drmFreeDevice(&local_devices[i]);
closedir(sysdir); closedir(sysdir);
free(local_devices); free(local_devices);
@ -3264,7 +3275,6 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
} }
node_count = i; node_count = i;
/* Fold nodes into a single device if they share the same bus info */
drmFoldDuplicatedDevices(local_devices, node_count); drmFoldDuplicatedDevices(local_devices, node_count);
device_count = 0; device_count = 0;