Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: make minor->index available early

Instead of allocating the minor-index during registration, we now do this
during allocation. This way, debug-messages between minor-allocation and
minor-registration will now use the correct minor instead of 0. Same is
done for unregistration vs. free, so debug-messages between
device-shutdown and device-destruction show proper indices.

Even though minor-indices are allocated early, we don't enable minor
lookup early. Instead, we keep the entry set to NULL and replace it during
registration / unregistration. This way, the index is allocated but lookup
only works if registered.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

+46 -38
+46 -38
drivers/gpu/drm/drm_stub.c
··· 256 256 static int drm_minor_alloc(struct drm_device *dev, unsigned int type) 257 257 { 258 258 struct drm_minor *minor; 259 + unsigned long flags; 260 + int r; 259 261 260 262 minor = kzalloc(sizeof(*minor), GFP_KERNEL); 261 263 if (!minor) ··· 266 264 minor->type = type; 267 265 minor->dev = dev; 268 266 267 + idr_preload(GFP_KERNEL); 268 + spin_lock_irqsave(&drm_minor_lock, flags); 269 + r = idr_alloc(&drm_minors_idr, 270 + NULL, 271 + 64 * type, 272 + 64 * (type + 1), 273 + GFP_NOWAIT); 274 + spin_unlock_irqrestore(&drm_minor_lock, flags); 275 + idr_preload_end(); 276 + 277 + if (r < 0) 278 + goto err_free; 279 + 280 + minor->index = r; 281 + 269 282 *drm_minor_get_slot(dev, type) = minor; 270 283 return 0; 284 + 285 + err_free: 286 + kfree(minor); 287 + return r; 271 288 } 272 289 273 290 static void drm_minor_free(struct drm_device *dev, unsigned int type) 274 291 { 275 - struct drm_minor **slot; 292 + struct drm_minor **slot, *minor; 293 + unsigned long flags; 276 294 277 295 slot = drm_minor_get_slot(dev, type); 278 - if (*slot) { 279 - drm_mode_group_destroy(&(*slot)->mode_group); 280 - kfree(*slot); 281 - *slot = NULL; 282 - } 296 + minor = *slot; 297 + if (!minor) 298 + return; 299 + 300 + drm_mode_group_destroy(&minor->mode_group); 301 + 302 + spin_lock_irqsave(&drm_minor_lock, flags); 303 + idr_remove(&drm_minors_idr, minor->index); 304 + spin_unlock_irqrestore(&drm_minor_lock, flags); 305 + 306 + kfree(minor); 307 + *slot = NULL; 283 308 } 284 309 285 310 static int drm_minor_register(struct drm_device *dev, unsigned int type) 286 311 { 287 - struct drm_minor *new_minor; 312 + struct drm_minor *minor; 288 313 unsigned long flags; 289 314 int ret; 290 - int minor_id; 291 315 292 316 DRM_DEBUG("\n"); 293 317 294 - new_minor = *drm_minor_get_slot(dev, type); 295 - if (!new_minor) 318 + minor = *drm_minor_get_slot(dev, type); 319 + if (!minor) 296 320 return 0; 297 321 298 - idr_preload(GFP_KERNEL); 299 - spin_lock_irqsave(&drm_minor_lock, flags); 300 - minor_id = idr_alloc(&drm_minors_idr, 301 - NULL, 302 - 64 * type, 303 - 64 * (type + 1), 304 - GFP_NOWAIT); 305 - spin_unlock_irqrestore(&drm_minor_lock, flags); 306 - idr_preload_end(); 307 - 308 - if (minor_id < 0) 309 - return minor_id; 310 - 311 - new_minor->index = minor_id; 312 - 313 - ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); 322 + ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); 314 323 if (ret) { 315 324 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); 316 - goto err_id; 325 + return ret; 317 326 } 318 327 319 - ret = drm_sysfs_device_add(new_minor); 328 + ret = drm_sysfs_device_add(minor); 320 329 if (ret) { 321 330 DRM_ERROR("DRM: Error sysfs_device_add.\n"); 322 331 goto err_debugfs; ··· 335 322 336 323 /* replace NULL with @minor so lookups will succeed from now on */ 337 324 spin_lock_irqsave(&drm_minor_lock, flags); 338 - idr_replace(&drm_minors_idr, new_minor, new_minor->index); 325 + idr_replace(&drm_minors_idr, minor, minor->index); 339 326 spin_unlock_irqrestore(&drm_minor_lock, flags); 340 327 341 - DRM_DEBUG("new minor assigned %d\n", minor_id); 328 + DRM_DEBUG("new minor registered %d\n", minor->index); 342 329 return 0; 343 330 344 331 err_debugfs: 345 - drm_debugfs_cleanup(new_minor); 346 - err_id: 347 - spin_lock_irqsave(&drm_minor_lock, flags); 348 - idr_remove(&drm_minors_idr, minor_id); 349 - spin_unlock_irqrestore(&drm_minor_lock, flags); 350 - new_minor->index = 0; 332 + drm_debugfs_cleanup(minor); 351 333 return ret; 352 334 } 353 335 ··· 355 347 if (!minor || !minor->kdev) 356 348 return; 357 349 350 + /* replace @minor with NULL so lookups will fail from now on */ 358 351 spin_lock_irqsave(&drm_minor_lock, flags); 359 - idr_remove(&drm_minors_idr, minor->index); 352 + idr_replace(&drm_minors_idr, NULL, minor->index); 360 353 spin_unlock_irqrestore(&drm_minor_lock, flags); 361 - minor->index = 0; 362 354 363 355 drm_debugfs_cleanup(minor); 364 356 drm_sysfs_device_remove(minor);