diff options
author | Seung-Woo Kim <sw0312.kim@samsung.com> | 2013-07-01 20:53:28 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-07-03 20:53:37 -0400 |
commit | df9b6a9c3333a99d4483e92ca6b225b335567313 (patch) | |
tree | f0478c4990796a3843cb863e66c884a5d10f2e80 | |
parent | fe2ef780669d9bbd2f921b247dc79266b00b99ab (diff) |
drm: fix error routines in drm_open_helper
There are missing parts to handle error in drm_open_helper().
The priv->minor, assigned by idr_find() which can return NULL,
should be checked whether it is NULL or not before referencing it.
put_pid(), drm_gem_release(), and drm_prime_destory_file_private()
should be called when error happens after their pair functions are
called. If an error occurs after executing dev->driver->open()
which allocates driver specific per-file private data, then the
private data should be released.
Signed-off-by: YoungJun Cho <yj44.cho@samsung.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Chris Wilson <chris-wilson.co.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 429e07d0b0f1..3a24385e0368 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -271,6 +271,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
271 | priv->uid = current_euid(); | 271 | priv->uid = current_euid(); |
272 | priv->pid = get_pid(task_pid(current)); | 272 | priv->pid = get_pid(task_pid(current)); |
273 | priv->minor = idr_find(&drm_minors_idr, minor_id); | 273 | priv->minor = idr_find(&drm_minors_idr, minor_id); |
274 | if (!priv->minor) { | ||
275 | ret = -ENODEV; | ||
276 | goto out_put_pid; | ||
277 | } | ||
278 | |||
274 | priv->ioctl_count = 0; | 279 | priv->ioctl_count = 0; |
275 | /* for compatibility root is always authenticated */ | 280 | /* for compatibility root is always authenticated */ |
276 | priv->authenticated = capable(CAP_SYS_ADMIN); | 281 | priv->authenticated = capable(CAP_SYS_ADMIN); |
@@ -292,7 +297,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
292 | if (dev->driver->open) { | 297 | if (dev->driver->open) { |
293 | ret = dev->driver->open(dev, priv); | 298 | ret = dev->driver->open(dev, priv); |
294 | if (ret < 0) | 299 | if (ret < 0) |
295 | goto out_free; | 300 | goto out_prime_destroy; |
296 | } | 301 | } |
297 | 302 | ||
298 | 303 | ||
@@ -304,7 +309,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
304 | if (!priv->minor->master) { | 309 | if (!priv->minor->master) { |
305 | mutex_unlock(&dev->struct_mutex); | 310 | mutex_unlock(&dev->struct_mutex); |
306 | ret = -ENOMEM; | 311 | ret = -ENOMEM; |
307 | goto out_free; | 312 | goto out_close; |
308 | } | 313 | } |
309 | 314 | ||
310 | priv->is_master = 1; | 315 | priv->is_master = 1; |
@@ -322,7 +327,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
322 | drm_master_put(&priv->minor->master); | 327 | drm_master_put(&priv->minor->master); |
323 | drm_master_put(&priv->master); | 328 | drm_master_put(&priv->master); |
324 | mutex_unlock(&dev->struct_mutex); | 329 | mutex_unlock(&dev->struct_mutex); |
325 | goto out_free; | 330 | goto out_close; |
326 | } | 331 | } |
327 | } | 332 | } |
328 | mutex_lock(&dev->struct_mutex); | 333 | mutex_lock(&dev->struct_mutex); |
@@ -333,7 +338,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
333 | drm_master_put(&priv->minor->master); | 338 | drm_master_put(&priv->minor->master); |
334 | drm_master_put(&priv->master); | 339 | drm_master_put(&priv->master); |
335 | mutex_unlock(&dev->struct_mutex); | 340 | mutex_unlock(&dev->struct_mutex); |
336 | goto out_free; | 341 | goto out_close; |
337 | } | 342 | } |
338 | } | 343 | } |
339 | mutex_unlock(&dev->struct_mutex); | 344 | mutex_unlock(&dev->struct_mutex); |
@@ -367,7 +372,17 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
367 | #endif | 372 | #endif |
368 | 373 | ||
369 | return 0; | 374 | return 0; |
370 | out_free: | 375 | |
376 | out_close: | ||
377 | if (dev->driver->postclose) | ||
378 | dev->driver->postclose(dev, priv); | ||
379 | out_prime_destroy: | ||
380 | if (drm_core_check_feature(dev, DRIVER_PRIME)) | ||
381 | drm_prime_destroy_file_private(&priv->prime); | ||
382 | if (dev->driver->driver_features & DRIVER_GEM) | ||
383 | drm_gem_release(dev, priv); | ||
384 | out_put_pid: | ||
385 | put_pid(priv->pid); | ||
371 | kfree(priv); | 386 | kfree(priv); |
372 | filp->private_data = NULL; | 387 | filp->private_data = NULL; |
373 | return ret; | 388 | return ret; |