| @@ -262,15 +262,21 @@ again: · 261 unmodified lines |
| 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); · 35 unmodified lines |
| 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, · 2 unmodified lines |
| 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); |
| | 347 | out: |
| | 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) · 49 unmodified lines |
| 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 | } |
| 391 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | 409 | EXPORT_SYMBOL(drm_framebuffer_cleanup); |
| 392 | | 410 | |
| @@ -406,6 +424,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) · 13 unmodified lines |
| 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) · 20 unmodified lines |
| 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 | } |
| 439 | EXPORT_SYMBOL(drm_framebuffer_remove); | 456 | EXPORT_SYMBOL(drm_framebuffer_remove); |
| @@ -989,6 +1006,7 @@ void drm_mode_config_init(struct drm_device *dev) · 549 unmodified lines |
| 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) · 96 unmodified lines |
| 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, · 123 unmodified lines |
| 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, · 1 unmodified line |
| 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, · 17 unmodified lines |
| 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, · 492 unmodified lines |
| 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, · 135 unmodified lines |
| 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, · 235 unmodified lines |
| 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); |
| 2162 | out: | | |
| 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, · 166 unmodified lines |
| 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 | |
| 2344 | out: | | |
| 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, · 24 unmodified lines |
| 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); |
| 2395 | out: | 2431 | out: |
| 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, · 22 unmodified lines |
| 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, · 31 unmodified lines |
| 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) · 68 unmodified lines |
| 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, · 998 unmodified lines |
| 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); |