Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+66 −19
Original line number Diff line number Diff line
@@ -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.
 *
@@ -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);
@@ -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);
@@ -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);
@@ -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;
}

/**
@@ -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;
		}
	}