diff options
Diffstat (limited to 'drivers/gpu/drm/drm_ioctl.c')
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 85 | 
1 files changed, 66 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 76d3d18056d..7b03b197fc0 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -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;  		}  	}  |