Commit 3fb688fd authored by Chris Wilson's avatar Chris Wilson Committed by Dave Airlie

drm: Cleanup after failing to create master->unique and dev->name

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: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent dc77de12
...@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data, ...@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data,
return 0; 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. * Set the bus id.
* *
...@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data,
master->unique_len = u->unique_len; master->unique_len = u->unique_len;
master->unique_size = u->unique_len + 1; master->unique_size = u->unique_len + 1;
master->unique = kmalloc(master->unique_size, GFP_KERNEL); master->unique = kmalloc(master->unique_size, GFP_KERNEL);
if (!master->unique) if (!master->unique) {
return -ENOMEM; ret = -ENOMEM;
if (copy_from_user(master->unique, u->unique, master->unique_len)) goto err;
return -EFAULT; }
if (copy_from_user(master->unique, u->unique, master->unique_len)) {
ret = -EFAULT;
goto err;
}
master->unique[master->unique_len] = '\0'; master->unique[master->unique_len] = '\0';
dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
strlen(master->unique) + 2, GFP_KERNEL); strlen(master->unique) + 2, GFP_KERNEL);
if (!dev->devname) if (!dev->devname) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique); master->unique);
...@@ -113,24 +133,36 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -113,24 +133,36 @@ int drm_setunique(struct drm_device *dev, void *data,
* busid. * busid.
*/ */
ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3) if (ret != 3) {
return -EINVAL; ret = -EINVAL;
goto err;
}
domain = bus >> 8; domain = bus >> 8;
bus &= 0xff; bus &= 0xff;
if ((domain != drm_get_pci_domain(dev)) || if ((domain != drm_get_pci_domain(dev)) ||
(bus != dev->pdev->bus->number) || (bus != dev->pdev->bus->number) ||
(slot != PCI_SLOT(dev->pdev->devfn)) || (slot != PCI_SLOT(dev->pdev->devfn)) ||
(func != PCI_FUNC(dev->pdev->devfn))) (func != PCI_FUNC(dev->pdev->devfn))) {
return -EINVAL; ret = -EINVAL;
goto err;
}
return 0; return 0;
err:
drm_unset_busid(dev, master);
return ret;
} }
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{ {
struct drm_master *master = file_priv->master; 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)) { if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
master->unique_len = 10 + strlen(dev->platformdev->name); master->unique_len = 10 + strlen(dev->platformdev->name);
...@@ -142,15 +174,20 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) ...@@ -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, len = snprintf(master->unique, master->unique_len,
"platform:%s", dev->platformdev->name); "platform:%s", dev->platformdev->name);
if (len > master->unique_len) if (len > master->unique_len) {
DRM_ERROR("Unique buffer overflowed\n"); DRM_ERROR("Unique buffer overflowed\n");
ret = -EINVAL;
goto err;
}
dev->devname = dev->devname =
kmalloc(strlen(dev->platformdev->name) + kmalloc(strlen(dev->platformdev->name) +
master->unique_len + 2, GFP_KERNEL); master->unique_len + 2, GFP_KERNEL);
if (dev->devname == NULL) if (dev->devname == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->platformdev->name, sprintf(dev->devname, "%s@%s", dev->platformdev->name,
master->unique); master->unique);
...@@ -168,23 +205,31 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) ...@@ -168,23 +205,31 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
dev->pdev->bus->number, dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn), PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn)); PCI_FUNC(dev->pdev->devfn));
if (len >= master->unique_len) if (len >= master->unique_len) {
DRM_ERROR("buffer overflow"); DRM_ERROR("buffer overflow");
else ret = -EINVAL;
goto err;
} else
master->unique_len = len; master->unique_len = len;
dev->devname = dev->devname =
kmalloc(strlen(dev->driver->pci_driver.name) + kmalloc(strlen(dev->driver->pci_driver.name) +
master->unique_len + 2, GFP_KERNEL); master->unique_len + 2, GFP_KERNEL);
if (dev->devname == NULL) if (dev->devname == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique); master->unique);
} }
return 0; return 0;
err:
drm_unset_busid(dev, master);
return ret;
} }
/** /**
...@@ -348,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri ...@@ -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 * 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;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment