aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-08-04 06:09:42 -0400
committerDave Airlie <airlied@redhat.com>2010-08-04 18:42:19 -0400
commit3fb688fdc1890f9e8e97597f690c145ab888aec0 (patch)
tree51d00db10f866092486ccde2ec20ac794c8f2651 /drivers/gpu
parentdc77de12dde95c8da39e4c417eb70c7d445cf84b (diff)
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: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/drm_ioctl.c85
1 files changed, 66 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 76d3d18056dd..7b03b197fc00 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,
64 return 0; 64 return 0;
65} 65}
66 66
67static void
68drm_unset_busid(struct drm_device *dev,
69 struct drm_master *master)
70{
71 kfree(dev->devname);
72 dev->devname = NULL;
73
74 kfree(master->unique);
75 master->unique = NULL;
76 master->unique_len = 0;
77 master->unique_size = 0;
78}
79
67/** 80/**
68 * Set the bus id. 81 * Set the bus id.
69 * 82 *
@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data,
94 master->unique_len = u->unique_len; 107 master->unique_len = u->unique_len;
95 master->unique_size = u->unique_len + 1; 108 master->unique_size = u->unique_len + 1;
96 master->unique = kmalloc(master->unique_size, GFP_KERNEL); 109 master->unique = kmalloc(master->unique_size, GFP_KERNEL);
97 if (!master->unique) 110 if (!master->unique) {
98 return -ENOMEM; 111 ret = -ENOMEM;
99 if (copy_from_user(master->unique, u->unique, master->unique_len)) 112 goto err;
100 return -EFAULT; 113 }
114
115 if (copy_from_user(master->unique, u->unique, master->unique_len)) {
116 ret = -EFAULT;
117 goto err;
118 }
101 119
102 master->unique[master->unique_len] = '\0'; 120 master->unique[master->unique_len] = '\0';
103 121
104 dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + 122 dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
105 strlen(master->unique) + 2, GFP_KERNEL); 123 strlen(master->unique) + 2, GFP_KERNEL);
106 if (!dev->devname) 124 if (!dev->devname) {
107 return -ENOMEM; 125 ret = -ENOMEM;
126 goto err;
127 }
108 128
109 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, 129 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
110 master->unique); 130 master->unique);
@@ -113,24 +133,36 @@ int drm_setunique(struct drm_device *dev, void *data,
113 * busid. 133 * busid.
114 */ 134 */
115 ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); 135 ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
116 if (ret != 3) 136 if (ret != 3) {
117 return -EINVAL; 137 ret = -EINVAL;
138 goto err;
139 }
140
118 domain = bus >> 8; 141 domain = bus >> 8;
119 bus &= 0xff; 142 bus &= 0xff;
120 143
121 if ((domain != drm_get_pci_domain(dev)) || 144 if ((domain != drm_get_pci_domain(dev)) ||
122 (bus != dev->pdev->bus->number) || 145 (bus != dev->pdev->bus->number) ||
123 (slot != PCI_SLOT(dev->pdev->devfn)) || 146 (slot != PCI_SLOT(dev->pdev->devfn)) ||
124 (func != PCI_FUNC(dev->pdev->devfn))) 147 (func != PCI_FUNC(dev->pdev->devfn))) {
125 return -EINVAL; 148 ret = -EINVAL;
149 goto err;
150 }
126 151
127 return 0; 152 return 0;
153
154err:
155 drm_unset_busid(dev, master);
156 return ret;
128} 157}
129 158
130static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) 159static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
131{ 160{
132 struct drm_master *master = file_priv->master; 161 struct drm_master *master = file_priv->master;
133 int len; 162 int len, ret;
163
164 if (master->unique != NULL)
165 drm_unset_busid(dev, master);
134 166
135 if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) { 167 if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
136 master->unique_len = 10 + strlen(dev->platformdev->name); 168 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 len = snprintf(master->unique, master->unique_len, 174 len = snprintf(master->unique, master->unique_len,
143 "platform:%s", dev->platformdev->name); 175 "platform:%s", dev->platformdev->name);
144 176
145 if (len > master->unique_len) 177 if (len > master->unique_len) {
146 DRM_ERROR("Unique buffer overflowed\n"); 178 DRM_ERROR("Unique buffer overflowed\n");
179 ret = -EINVAL;
180 goto err;
181 }
147 182
148 dev->devname = 183 dev->devname =
149 kmalloc(strlen(dev->platformdev->name) + 184 kmalloc(strlen(dev->platformdev->name) +
150 master->unique_len + 2, GFP_KERNEL); 185 master->unique_len + 2, GFP_KERNEL);
151 186
152 if (dev->devname == NULL) 187 if (dev->devname == NULL) {
153 return -ENOMEM; 188 ret = -ENOMEM;
189 goto err;
190 }
154 191
155 sprintf(dev->devname, "%s@%s", dev->platformdev->name, 192 sprintf(dev->devname, "%s@%s", dev->platformdev->name,
156 master->unique); 193 master->unique);
@@ -168,23 +205,31 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
168 dev->pdev->bus->number, 205 dev->pdev->bus->number,
169 PCI_SLOT(dev->pdev->devfn), 206 PCI_SLOT(dev->pdev->devfn),
170 PCI_FUNC(dev->pdev->devfn)); 207 PCI_FUNC(dev->pdev->devfn));
171 if (len >= master->unique_len) 208 if (len >= master->unique_len) {
172 DRM_ERROR("buffer overflow"); 209 DRM_ERROR("buffer overflow");
173 else 210 ret = -EINVAL;
211 goto err;
212 } else
174 master->unique_len = len; 213 master->unique_len = len;
175 214
176 dev->devname = 215 dev->devname =
177 kmalloc(strlen(dev->driver->pci_driver.name) + 216 kmalloc(strlen(dev->driver->pci_driver.name) +
178 master->unique_len + 2, GFP_KERNEL); 217 master->unique_len + 2, GFP_KERNEL);
179 218
180 if (dev->devname == NULL) 219 if (dev->devname == NULL) {
181 return -ENOMEM; 220 ret = -ENOMEM;
221 goto err;
222 }
182 223
183 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, 224 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
184 master->unique); 225 master->unique);
185 } 226 }
186 227
187 return 0; 228 return 0;
229
230err:
231 drm_unset_busid(dev, master);
232 return ret;
188} 233}
189 234
190/** 235/**
@@ -348,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
348 /* 393 /*
349 * Version 1.1 includes tying of DRM to specific device 394 * Version 1.1 includes tying of DRM to specific device
350 */ 395 */
351 drm_set_busid(dev, file_priv); 396 retcode = drm_set_busid(dev, file_priv);
397 if (retcode)
398 goto done;
352 } 399 }
353 } 400 }
354 401