Skip to content

Commit

Permalink
drm: Cleanup after failing to create master->unique and dev->name
Browse files Browse the repository at this point in the history
v2: Userspace (notably xf86-video-{intel,ati}) became confused when
drmSetInterfaceVersion() started returning -EBUSY as they used a second
call (the first done in drmOpen()) to check their master credentials.
Since userspace wants to be able to repeatedly call
drmSetInterfaceVersion() allow them to do so.

v3: Rebase to drm-core-next.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Chris Wilson authored and Dave Airlie committed Aug 4, 2010
1 parent dc77de1 commit 3fb688f
Showing 1 changed file with 66 additions and 19 deletions.
85 changes: 66 additions & 19 deletions drivers/gpu/drm/drm_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data,
return 0;
}

static void
drm_unset_busid(struct drm_device *dev,
struct drm_master *master)
{
kfree(dev->devname);
dev->devname = NULL;

kfree(master->unique);
master->unique = NULL;
master->unique_len = 0;
master->unique_size = 0;
}

/**
* Set the bus id.
*
Expand Down Expand Up @@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data,
master->unique_len = u->unique_len;
master->unique_size = u->unique_len + 1;
master->unique = kmalloc(master->unique_size, GFP_KERNEL);
if (!master->unique)
return -ENOMEM;
if (copy_from_user(master->unique, u->unique, master->unique_len))
return -EFAULT;
if (!master->unique) {
ret = -ENOMEM;
goto err;
}

if (copy_from_user(master->unique, u->unique, master->unique_len)) {
ret = -EFAULT;
goto err;
}

master->unique[master->unique_len] = '\0';

dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
strlen(master->unique) + 2, GFP_KERNEL);
if (!dev->devname)
return -ENOMEM;
if (!dev->devname) {
ret = -ENOMEM;
goto err;
}

sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique);
Expand All @@ -113,24 +133,36 @@ int drm_setunique(struct drm_device *dev, void *data,
* busid.
*/
ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3)
return -EINVAL;
if (ret != 3) {
ret = -EINVAL;
goto err;
}

domain = bus >> 8;
bus &= 0xff;

if ((domain != drm_get_pci_domain(dev)) ||
(bus != dev->pdev->bus->number) ||
(slot != PCI_SLOT(dev->pdev->devfn)) ||
(func != PCI_FUNC(dev->pdev->devfn)))
return -EINVAL;
(func != PCI_FUNC(dev->pdev->devfn))) {
ret = -EINVAL;
goto err;
}

return 0;

err:
drm_unset_busid(dev, master);
return ret;
}

static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_master *master = file_priv->master;
int len;
int len, ret;

if (master->unique != NULL)
drm_unset_busid(dev, master);

if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
master->unique_len = 10 + strlen(dev->platformdev->name);
Expand All @@ -142,15 +174,20 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
len = snprintf(master->unique, master->unique_len,
"platform:%s", dev->platformdev->name);

if (len > master->unique_len)
if (len > master->unique_len) {
DRM_ERROR("Unique buffer overflowed\n");
ret = -EINVAL;
goto err;
}

dev->devname =
kmalloc(strlen(dev->platformdev->name) +
master->unique_len + 2, GFP_KERNEL);

if (dev->devname == NULL)
return -ENOMEM;
if (dev->devname == NULL) {
ret = -ENOMEM;
goto err;
}

sprintf(dev->devname, "%s@%s", dev->platformdev->name,
master->unique);
Expand All @@ -168,23 +205,31 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn));
if (len >= master->unique_len)
if (len >= master->unique_len) {
DRM_ERROR("buffer overflow");
else
ret = -EINVAL;
goto err;
} else
master->unique_len = len;

dev->devname =
kmalloc(strlen(dev->driver->pci_driver.name) +
master->unique_len + 2, GFP_KERNEL);

if (dev->devname == NULL)
return -ENOMEM;
if (dev->devname == NULL) {
ret = -ENOMEM;
goto err;
}

sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique);
}

return 0;

err:
drm_unset_busid(dev, master);
return ret;
}

/**
Expand Down Expand Up @@ -348,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
/*
* Version 1.1 includes tying of DRM to specific device
*/
drm_set_busid(dev, file_priv);
retcode = drm_set_busid(dev, file_priv);
if (retcode)
goto done;
}
}

Expand Down

0 comments on commit 3fb688f

Please sign in to comment.