aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_crtc.c116
-rw-r--r--drivers/gpu/drm/drm_fops.c1
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c4
-rw-r--r--drivers/staging/omapdrm/omap_debugfs.c2
-rw-r--r--include/drm/drmP.h8
-rw-r--r--include/drm/drm_crtc.h14
7 files changed, 113 insertions, 37 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4af6a3d5c9a1..13a3d3426961 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -262,15 +262,21 @@ again:
262 262
263 mutex_lock(&dev->mode_config.idr_mutex); 263 mutex_lock(&dev->mode_config.idr_mutex);
264 ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); 264 ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id);
265
266 if (!ret) {
267 /*
268 * Set up the object linking under the protection of the idr
269 * lock so that other users can't see inconsistent state.
270 */
271 obj->id = new_id;
272 obj->type = obj_type;
273 }
265 mutex_unlock(&dev->mode_config.idr_mutex); 274 mutex_unlock(&dev->mode_config.idr_mutex);
275
266 if (ret == -EAGAIN) 276 if (ret == -EAGAIN)
267 goto again; 277 goto again;
268 else if (ret)
269 return ret;
270 278
271 obj->id = new_id; 279 return ret;
272 obj->type = obj_type;
273 return 0;
274} 280}
275 281
276/** 282/**
@@ -312,6 +318,12 @@ EXPORT_SYMBOL(drm_mode_object_find);
312 * Allocates an ID for the framebuffer's parent mode object, sets its mode 318 * Allocates an ID for the framebuffer's parent mode object, sets its mode
313 * functions & device file and adds it to the master fd list. 319 * functions & device file and adds it to the master fd list.
314 * 320 *
321 * IMPORTANT:
322 * This functions publishes the fb and makes it available for concurrent access
323 * by other users. Which means by this point the fb _must_ be fully set up -
324 * since all the fb attributes are invariant over its lifetime, no further
325 * locking but only correct reference counting is required.
326 *
315 * RETURNS: 327 * RETURNS:
316 * Zero on success, error code on failure. 328 * Zero on success, error code on failure.
317 */ 329 */
@@ -320,16 +332,20 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
320{ 332{
321 int ret; 333 int ret;
322 334
335 mutex_lock(&dev->mode_config.fb_lock);
323 kref_init(&fb->refcount); 336 kref_init(&fb->refcount);
337 INIT_LIST_HEAD(&fb->filp_head);
338 fb->dev = dev;
339 fb->funcs = funcs;
324 340
325 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 341 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
326 if (ret) 342 if (ret)
327 return ret; 343 goto out;
328 344
329 fb->dev = dev;
330 fb->funcs = funcs;
331 dev->mode_config.num_fb++; 345 dev->mode_config.num_fb++;
332 list_add(&fb->head, &dev->mode_config.fb_list); 346 list_add(&fb->head, &dev->mode_config.fb_list);
347out:
348 mutex_unlock(&dev->mode_config.fb_lock);
333 349
334 return 0; 350 return 0;
335} 351}
@@ -385,8 +401,10 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
385 * this.) 401 * this.)
386 */ 402 */
387 drm_mode_object_put(dev, &fb->base); 403 drm_mode_object_put(dev, &fb->base);
404 mutex_lock(&dev->mode_config.fb_lock);
388 list_del(&fb->head); 405 list_del(&fb->head);
389 dev->mode_config.num_fb--; 406 dev->mode_config.num_fb--;
407 mutex_unlock(&dev->mode_config.fb_lock);
390} 408}
391EXPORT_SYMBOL(drm_framebuffer_cleanup); 409EXPORT_SYMBOL(drm_framebuffer_cleanup);
392 410
@@ -406,6 +424,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
406 int ret; 424 int ret;
407 425
408 WARN_ON(!drm_modeset_is_locked(dev)); 426 WARN_ON(!drm_modeset_is_locked(dev));
427 WARN_ON(!list_empty(&fb->filp_head));
409 428
410 /* remove from any CRTC */ 429 /* remove from any CRTC */
411 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 430 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -432,8 +451,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
432 } 451 }
433 } 452 }
434 453
435 list_del(&fb->filp_head);
436
437 drm_framebuffer_unreference(fb); 454 drm_framebuffer_unreference(fb);
438} 455}
439EXPORT_SYMBOL(drm_framebuffer_remove); 456EXPORT_SYMBOL(drm_framebuffer_remove);
@@ -989,6 +1006,7 @@ void drm_mode_config_init(struct drm_device *dev)
989{ 1006{
990 mutex_init(&dev->mode_config.mutex); 1007 mutex_init(&dev->mode_config.mutex);
991 mutex_init(&dev->mode_config.idr_mutex); 1008 mutex_init(&dev->mode_config.idr_mutex);
1009 mutex_init(&dev->mode_config.fb_lock);
992 INIT_LIST_HEAD(&dev->mode_config.fb_list); 1010 INIT_LIST_HEAD(&dev->mode_config.fb_list);
993 INIT_LIST_HEAD(&dev->mode_config.crtc_list); 1011 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
994 INIT_LIST_HEAD(&dev->mode_config.connector_list); 1012 INIT_LIST_HEAD(&dev->mode_config.connector_list);
@@ -1091,6 +1109,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
1091 drm_property_destroy(dev, property); 1109 drm_property_destroy(dev, property);
1092 } 1110 }
1093 1111
1112 /* Single-threaded teardown context, so it's not requied to grab the
1113 * fb_lock to protect against concurrent fb_list access. Contrary, it
1114 * would actually deadlock with the drm_framebuffer_cleanup function. */
1094 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 1115 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
1095 drm_framebuffer_remove(fb); 1116 drm_framebuffer_remove(fb);
1096 } 1117 }
@@ -1220,8 +1241,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
1220 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1241 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1221 return -EINVAL; 1242 return -EINVAL;
1222 1243
1223 drm_modeset_lock_all(dev);
1224 1244
1245 mutex_lock(&file_priv->fbs_lock);
1225 /* 1246 /*
1226 * For the non-control nodes we need to limit the list of resources 1247 * For the non-control nodes we need to limit the list of resources
1227 * by IDs in the group list for this node 1248 * by IDs in the group list for this node
@@ -1229,6 +1250,23 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
1229 list_for_each(lh, &file_priv->fbs) 1250 list_for_each(lh, &file_priv->fbs)
1230 fb_count++; 1251 fb_count++;
1231 1252
1253 /* handle this in 4 parts */
1254 /* FBs */
1255 if (card_res->count_fbs >= fb_count) {
1256 copied = 0;
1257 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1258 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1259 if (put_user(fb->base.id, fb_id + copied)) {
1260 mutex_unlock(&file_priv->fbs_lock);
1261 return -EFAULT;
1262 }
1263 copied++;
1264 }
1265 }
1266 card_res->count_fbs = fb_count;
1267 mutex_unlock(&file_priv->fbs_lock);
1268
1269 drm_modeset_lock_all(dev);
1232 mode_group = &file_priv->master->minor->mode_group; 1270 mode_group = &file_priv->master->minor->mode_group;
1233 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { 1271 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1234 1272
@@ -1252,21 +1290,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
1252 card_res->max_width = dev->mode_config.max_width; 1290 card_res->max_width = dev->mode_config.max_width;
1253 card_res->min_width = dev->mode_config.min_width; 1291 card_res->min_width = dev->mode_config.min_width;
1254 1292
1255 /* handle this in 4 parts */
1256 /* FBs */
1257 if (card_res->count_fbs >= fb_count) {
1258 copied = 0;
1259 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1260 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1261 if (put_user(fb->base.id, fb_id + copied)) {
1262 ret = -EFAULT;
1263 goto out;
1264 }
1265 copied++;
1266 }
1267 }
1268 card_res->count_fbs = fb_count;
1269
1270 /* CRTCs */ 1293 /* CRTCs */
1271 if (card_res->count_crtcs >= crtc_count) { 1294 if (card_res->count_crtcs >= crtc_count) {
1272 copied = 0; 1295 copied = 0;
@@ -1765,8 +1788,10 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
1765 } 1788 }
1766 crtc = obj_to_crtc(obj); 1789 crtc = obj_to_crtc(obj);
1767 1790
1791 mutex_lock(&dev->mode_config.fb_lock);
1768 obj = drm_mode_object_find(dev, plane_req->fb_id, 1792 obj = drm_mode_object_find(dev, plane_req->fb_id,
1769 DRM_MODE_OBJECT_FB); 1793 DRM_MODE_OBJECT_FB);
1794 mutex_unlock(&dev->mode_config.fb_lock);
1770 if (!obj) { 1795 if (!obj) {
1771 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 1796 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
1772 plane_req->fb_id); 1797 plane_req->fb_id);
@@ -1908,8 +1933,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
1908 } 1933 }
1909 fb = crtc->fb; 1934 fb = crtc->fb;
1910 } else { 1935 } else {
1936 mutex_lock(&dev->mode_config.fb_lock);
1911 obj = drm_mode_object_find(dev, crtc_req->fb_id, 1937 obj = drm_mode_object_find(dev, crtc_req->fb_id,
1912 DRM_MODE_OBJECT_FB); 1938 DRM_MODE_OBJECT_FB);
1939 mutex_unlock(&dev->mode_config.fb_lock);
1913 if (!obj) { 1940 if (!obj) {
1914 DRM_DEBUG_KMS("Unknown FB ID%d\n", 1941 DRM_DEBUG_KMS("Unknown FB ID%d\n",
1915 crtc_req->fb_id); 1942 crtc_req->fb_id);
@@ -2151,16 +2178,17 @@ int drm_mode_addfb(struct drm_device *dev,
2151 fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); 2178 fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
2152 if (IS_ERR(fb)) { 2179 if (IS_ERR(fb)) {
2153 DRM_DEBUG_KMS("could not create framebuffer\n"); 2180 DRM_DEBUG_KMS("could not create framebuffer\n");
2154 ret = PTR_ERR(fb); 2181 drm_modeset_unlock_all(dev);
2155 goto out; 2182 return PTR_ERR(fb);
2156 } 2183 }
2157 2184
2185 mutex_lock(&file_priv->fbs_lock);
2158 or->fb_id = fb->base.id; 2186 or->fb_id = fb->base.id;
2159 list_add(&fb->filp_head, &file_priv->fbs); 2187 list_add(&fb->filp_head, &file_priv->fbs);
2160 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 2188 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
2161 2189 mutex_unlock(&file_priv->fbs_lock);
2162out:
2163 drm_modeset_unlock_all(dev); 2190 drm_modeset_unlock_all(dev);
2191
2164 return ret; 2192 return ret;
2165} 2193}
2166 2194
@@ -2333,16 +2361,18 @@ int drm_mode_addfb2(struct drm_device *dev,
2333 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 2361 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
2334 if (IS_ERR(fb)) { 2362 if (IS_ERR(fb)) {
2335 DRM_DEBUG_KMS("could not create framebuffer\n"); 2363 DRM_DEBUG_KMS("could not create framebuffer\n");
2336 ret = PTR_ERR(fb); 2364 drm_modeset_unlock_all(dev);
2337 goto out; 2365 return PTR_ERR(fb);
2338 } 2366 }
2339 2367
2368 mutex_lock(&file_priv->fbs_lock);
2340 r->fb_id = fb->base.id; 2369 r->fb_id = fb->base.id;
2341 list_add(&fb->filp_head, &file_priv->fbs); 2370 list_add(&fb->filp_head, &file_priv->fbs);
2342 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 2371 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
2372 mutex_unlock(&file_priv->fbs_lock);
2343 2373
2344out:
2345 drm_modeset_unlock_all(dev); 2374 drm_modeset_unlock_all(dev);
2375
2346 return ret; 2376 return ret;
2347} 2377}
2348 2378
@@ -2373,27 +2403,34 @@ int drm_mode_rmfb(struct drm_device *dev,
2373 return -EINVAL; 2403 return -EINVAL;
2374 2404
2375 drm_modeset_lock_all(dev); 2405 drm_modeset_lock_all(dev);
2406 mutex_lock(&dev->mode_config.fb_lock);
2376 obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); 2407 obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
2377 /* TODO check that we really get a framebuffer back. */ 2408 /* TODO check that we really get a framebuffer back. */
2378 if (!obj) { 2409 if (!obj) {
2410 mutex_unlock(&dev->mode_config.fb_lock);
2379 ret = -EINVAL; 2411 ret = -EINVAL;
2380 goto out; 2412 goto out;
2381 } 2413 }
2382 fb = obj_to_fb(obj); 2414 fb = obj_to_fb(obj);
2415 mutex_unlock(&dev->mode_config.fb_lock);
2383 2416
2417 mutex_lock(&file_priv->fbs_lock);
2384 list_for_each_entry(fbl, &file_priv->fbs, filp_head) 2418 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2385 if (fb == fbl) 2419 if (fb == fbl)
2386 found = 1; 2420 found = 1;
2387
2388 if (!found) { 2421 if (!found) {
2389 ret = -EINVAL; 2422 ret = -EINVAL;
2423 mutex_unlock(&file_priv->fbs_lock);
2390 goto out; 2424 goto out;
2391 } 2425 }
2392 2426
2393 drm_framebuffer_remove(fb); 2427 list_del_init(&fb->filp_head);
2428 mutex_unlock(&file_priv->fbs_lock);
2394 2429
2430 drm_framebuffer_remove(fb);
2395out: 2431out:
2396 drm_modeset_unlock_all(dev); 2432 drm_modeset_unlock_all(dev);
2433
2397 return ret; 2434 return ret;
2398} 2435}
2399 2436
@@ -2422,7 +2459,9 @@ int drm_mode_getfb(struct drm_device *dev,
2422 return -EINVAL; 2459 return -EINVAL;
2423 2460
2424 drm_modeset_lock_all(dev); 2461 drm_modeset_lock_all(dev);
2462 mutex_lock(&dev->mode_config.fb_lock);
2425 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 2463 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
2464 mutex_unlock(&dev->mode_config.fb_lock);
2426 if (!obj) { 2465 if (!obj) {
2427 ret = -EINVAL; 2466 ret = -EINVAL;
2428 goto out; 2467 goto out;
@@ -2460,7 +2499,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2460 return -EINVAL; 2499 return -EINVAL;
2461 2500
2462 drm_modeset_lock_all(dev); 2501 drm_modeset_lock_all(dev);
2502 mutex_lock(&dev->mode_config.fb_lock);
2463 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 2503 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
2504 mutex_unlock(&dev->mode_config.fb_lock);
2464 if (!obj) { 2505 if (!obj) {
2465 ret = -EINVAL; 2506 ret = -EINVAL;
2466 goto out_err1; 2507 goto out_err1;
@@ -2535,9 +2576,12 @@ void drm_fb_release(struct drm_file *priv)
2535 struct drm_framebuffer *fb, *tfb; 2576 struct drm_framebuffer *fb, *tfb;
2536 2577
2537 drm_modeset_lock_all(dev); 2578 drm_modeset_lock_all(dev);
2579 mutex_lock(&priv->fbs_lock);
2538 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 2580 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
2581 list_del_init(&fb->filp_head);
2539 drm_framebuffer_remove(fb); 2582 drm_framebuffer_remove(fb);
2540 } 2583 }
2584 mutex_unlock(&priv->fbs_lock);
2541 drm_modeset_unlock_all(dev); 2585 drm_modeset_unlock_all(dev);
2542} 2586}
2543 2587
@@ -3542,7 +3586,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
3542 if (crtc->funcs->page_flip == NULL) 3586 if (crtc->funcs->page_flip == NULL)
3543 goto out; 3587 goto out;
3544 3588
3589 mutex_lock(&dev->mode_config.fb_lock);
3545 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); 3590 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
3591 mutex_unlock(&dev->mode_config.fb_lock);
3546 if (!obj) 3592 if (!obj)
3547 goto out; 3593 goto out;
3548 fb = obj_to_fb(obj); 3594 fb = obj_to_fb(obj);
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 133b4132983e..13fdcd10a605 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -276,6 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
276 276
277 INIT_LIST_HEAD(&priv->lhead); 277 INIT_LIST_HEAD(&priv->lhead);
278 INIT_LIST_HEAD(&priv->fbs); 278 INIT_LIST_HEAD(&priv->fbs);
279 mutex_init(&priv->fbs_lock);
279 INIT_LIST_HEAD(&priv->event_list); 280 INIT_LIST_HEAD(&priv->event_list);
280 init_waitqueue_head(&priv->event_wait); 281 init_waitqueue_head(&priv->event_wait);
281 priv->event_space = 4096; /* set aside 4k for event buffer */ 282 priv->event_space = 4096; /* set aside 4k for event buffer */
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index e6a11ca85eaf..a40c674a57be 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1374,7 +1374,9 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
1374 fb->base.bits_per_pixel); 1374 fb->base.bits_per_pixel);
1375 describe_obj(m, fb->obj); 1375 describe_obj(m, fb->obj);
1376 seq_printf(m, "\n"); 1376 seq_printf(m, "\n");
1377 mutex_unlock(&dev->mode_config.mutex);
1377 1378
1379 mutex_lock(&dev->mode_config.fb_lock);
1378 list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { 1380 list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
1379 if (&fb->base == ifbdev->helper.fb) 1381 if (&fb->base == ifbdev->helper.fb)
1380 continue; 1382 continue;
@@ -1387,8 +1389,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
1387 describe_obj(m, fb->obj); 1389 describe_obj(m, fb->obj);
1388 seq_printf(m, "\n"); 1390 seq_printf(m, "\n");
1389 } 1391 }
1390 1392 mutex_unlock(&dev->mode_config.fb_lock);
1391 mutex_unlock(&dev->mode_config.mutex);
1392 1393
1393 return 0; 1394 return 0;
1394} 1395}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index a135498a1298..0d6a161b204b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -165,7 +165,9 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
165 165
166 drm_modeset_lock_all(dev); 166 drm_modeset_lock_all(dev);
167 167
168 mutex_lock(&dev->mode_config.fb_lock);
168 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); 169 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
170 mutex_unlock(&dev->mode_config.fb_lock);
169 if (!obj) { 171 if (!obj) {
170 DRM_ERROR("Invalid framebuffer id.\n"); 172 DRM_ERROR("Invalid framebuffer id.\n");
171 ret = -EINVAL; 173 ret = -EINVAL;
@@ -248,7 +250,9 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
248 250
249 drm_modeset_lock_all(dev); 251 drm_modeset_lock_all(dev);
250 252
253 mutex_lock(&dev->mode_config.fb_lock);
251 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); 254 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
255 mutex_unlock(&dev->mode_config.fb_lock);
252 if (!obj) { 256 if (!obj) {
253 DRM_ERROR("Invalid framebuffer id.\n"); 257 DRM_ERROR("Invalid framebuffer id.\n");
254 ret = -EINVAL; 258 ret = -EINVAL;
diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c
index 2f122e00b51d..e95540b3e2f6 100644
--- a/drivers/staging/omapdrm/omap_debugfs.c
+++ b/drivers/staging/omapdrm/omap_debugfs.c
@@ -72,6 +72,7 @@ static int fb_show(struct seq_file *m, void *arg)
72 seq_printf(m, "fbcon "); 72 seq_printf(m, "fbcon ");
73 omap_framebuffer_describe(priv->fbdev->fb, m); 73 omap_framebuffer_describe(priv->fbdev->fb, m);
74 74
75 mutex_lock(&dev->mode_config.fb_lock);
75 list_for_each_entry(fb, &dev->mode_config.fb_list, head) { 76 list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
76 if (fb == priv->fbdev->fb) 77 if (fb == priv->fbdev->fb)
77 continue; 78 continue;
@@ -79,6 +80,7 @@ static int fb_show(struct seq_file *m, void *arg)
79 seq_printf(m, "user "); 80 seq_printf(m, "user ");
80 omap_framebuffer_describe(fb, m); 81 omap_framebuffer_describe(fb, m);
81 } 82 }
83 mutex_unlock(&dev->mode_config.fb_lock);
82 84
83 mutex_unlock(&dev->struct_mutex); 85 mutex_unlock(&dev->struct_mutex);
84 mutex_unlock(&dev->mode_config.mutex); 86 mutex_unlock(&dev->mode_config.mutex);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3c609abe8c80..e74731c1a912 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -446,7 +446,15 @@ struct drm_file {
446 int is_master; /* this file private is a master for a minor */ 446 int is_master; /* this file private is a master for a minor */
447 struct drm_master *master; /* master this node is currently associated with 447 struct drm_master *master; /* master this node is currently associated with
448 N.B. not always minor->master */ 448 N.B. not always minor->master */
449
450 /**
451 * fbs - List of framebuffers associated with this file.
452 *
453 * Protected by fbs_lock. Note that the fbs list holds a reference on
454 * the fb object to prevent it from untimely disappearing.
455 */
449 struct list_head fbs; 456 struct list_head fbs;
457 struct mutex fbs_lock;
450 458
451 wait_queue_head_t event_wait; 459 wait_queue_head_t event_wait;
452 struct list_head event_list; 460 struct list_head event_list;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c89b1161f0be..c35a807d7e5c 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -254,6 +254,10 @@ struct drm_framebuffer {
254 * userspace perspective. 254 * userspace perspective.
255 */ 255 */
256 struct kref refcount; 256 struct kref refcount;
257 /*
258 * Place on the dev->mode_config.fb_list, access protected by
259 * dev->mode_config.fb_lock.
260 */
257 struct list_head head; 261 struct list_head head;
258 struct drm_mode_object base; 262 struct drm_mode_object base;
259 const struct drm_framebuffer_funcs *funcs; 263 const struct drm_framebuffer_funcs *funcs;
@@ -780,8 +784,18 @@ struct drm_mode_config {
780 struct mutex idr_mutex; /* for IDR management */ 784 struct mutex idr_mutex; /* for IDR management */
781 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ 785 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
782 /* this is limited to one for now */ 786 /* this is limited to one for now */
787
788
789 /**
790 * fb_lock - mutex to protect fb state
791 *
792 * Besides the global fb list his also protects the fbs list in the
793 * file_priv
794 */
795 struct mutex fb_lock;
783 int num_fb; 796 int num_fb;
784 struct list_head fb_list; 797 struct list_head fb_list;
798
785 int num_connector; 799 int num_connector;
786 struct list_head connector_list; 800 struct list_head connector_list;
787 int num_encoder; 801 int num_encoder;