| .. | .. |
|---|
| 11 | 11 | #include <linux/device.h> |
|---|
| 12 | 12 | #include <linux/dma-buf.h> |
|---|
| 13 | 13 | #include <linux/err.h> |
|---|
| 14 | +#include <linux/xarray.h> |
|---|
| 14 | 15 | #include <linux/list.h> |
|---|
| 15 | 16 | #include <linux/slab.h> |
|---|
| 16 | 17 | #include <linux/nospec.h> |
|---|
| .. | .. |
|---|
| 49 | 50 | static DEFINE_MUTEX(heap_list_lock); |
|---|
| 50 | 51 | static dev_t dma_heap_devt; |
|---|
| 51 | 52 | static struct class *dma_heap_class; |
|---|
| 52 | | - |
|---|
| 53 | | -static DEFINE_MUTEX(heap_devnode_lock); |
|---|
| 54 | | -static DECLARE_BITMAP(heap_devnode_nums, NUM_HEAP_MINORS); |
|---|
| 53 | +static DEFINE_XARRAY_ALLOC(dma_heap_minors); |
|---|
| 55 | 54 | |
|---|
| 56 | 55 | struct dma_heap *dma_heap_find(const char *name) |
|---|
| 57 | 56 | { |
|---|
| .. | .. |
|---|
| 124 | 123 | { |
|---|
| 125 | 124 | struct dma_heap *heap; |
|---|
| 126 | 125 | |
|---|
| 127 | | - mutex_lock(&heap_devnode_lock); |
|---|
| 128 | | - heap = container_of(inode->i_cdev, struct dma_heap, heap_cdev); |
|---|
| 126 | + heap = xa_load(&dma_heap_minors, iminor(inode)); |
|---|
| 129 | 127 | if (!heap) { |
|---|
| 130 | 128 | pr_err("dma_heap: minor %d unknown.\n", iminor(inode)); |
|---|
| 131 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 132 | 129 | return -ENODEV; |
|---|
| 133 | 130 | } |
|---|
| 134 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 135 | 131 | |
|---|
| 136 | 132 | /* instance data as context */ |
|---|
| 137 | 133 | file->private_data = heap; |
|---|
| .. | .. |
|---|
| 273 | 269 | |
|---|
| 274 | 270 | device_destroy(dma_heap_class, heap->heap_devt); |
|---|
| 275 | 271 | cdev_del(&heap->heap_cdev); |
|---|
| 276 | | - mutex_lock(&heap_devnode_lock); |
|---|
| 277 | | - clear_bit(minor, heap_devnode_nums); |
|---|
| 278 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 272 | + xa_erase(&dma_heap_minors, minor); |
|---|
| 279 | 273 | |
|---|
| 280 | 274 | kfree(heap); |
|---|
| 281 | 275 | } |
|---|
| .. | .. |
|---|
| 320 | 314 | |
|---|
| 321 | 315 | struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) |
|---|
| 322 | 316 | { |
|---|
| 323 | | - struct dma_heap *heap, *err_ret; |
|---|
| 317 | + struct dma_heap *heap, *h, *err_ret; |
|---|
| 324 | 318 | unsigned int minor; |
|---|
| 325 | 319 | int ret; |
|---|
| 326 | 320 | |
|---|
| .. | .. |
|---|
| 334 | 328 | return ERR_PTR(-EINVAL); |
|---|
| 335 | 329 | } |
|---|
| 336 | 330 | |
|---|
| 337 | | - /* check the name is unique */ |
|---|
| 338 | | - heap = dma_heap_find(exp_info->name); |
|---|
| 339 | | - if (heap) { |
|---|
| 340 | | - pr_err("dma_heap: Already registered heap named %s\n", |
|---|
| 341 | | - exp_info->name); |
|---|
| 342 | | - dma_heap_put(heap); |
|---|
| 343 | | - return ERR_PTR(-EINVAL); |
|---|
| 344 | | - } |
|---|
| 345 | | - |
|---|
| 346 | 331 | heap = kzalloc(sizeof(*heap), GFP_KERNEL); |
|---|
| 347 | 332 | if (!heap) |
|---|
| 348 | 333 | return ERR_PTR(-ENOMEM); |
|---|
| .. | .. |
|---|
| 352 | 337 | heap->ops = exp_info->ops; |
|---|
| 353 | 338 | heap->priv = exp_info->priv; |
|---|
| 354 | 339 | |
|---|
| 355 | | - /* Part 1: Find a free minor number */ |
|---|
| 356 | | - |
|---|
| 357 | | - mutex_lock(&heap_devnode_lock); |
|---|
| 358 | | - minor = find_next_zero_bit(heap_devnode_nums, NUM_HEAP_MINORS, 0); |
|---|
| 359 | | - if (minor == NUM_HEAP_MINORS) { |
|---|
| 360 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 340 | + /* Find unused minor number */ |
|---|
| 341 | + ret = xa_alloc(&dma_heap_minors, &minor, heap, |
|---|
| 342 | + XA_LIMIT(0, NUM_HEAP_MINORS - 1), GFP_KERNEL); |
|---|
| 343 | + if (ret < 0) { |
|---|
| 361 | 344 | pr_err("dma_heap: Unable to get minor number for heap\n"); |
|---|
| 362 | | - err_ret = ERR_PTR(-ENFILE); |
|---|
| 345 | + err_ret = ERR_PTR(ret); |
|---|
| 363 | 346 | goto err0; |
|---|
| 364 | 347 | } |
|---|
| 365 | | - set_bit(minor, heap_devnode_nums); |
|---|
| 366 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 367 | 348 | |
|---|
| 368 | 349 | /* Create device */ |
|---|
| 369 | 350 | heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), minor); |
|---|
| .. | .. |
|---|
| 390 | 371 | /* Make sure it doesn't disappear on us */ |
|---|
| 391 | 372 | heap->heap_dev = get_device(heap->heap_dev); |
|---|
| 392 | 373 | |
|---|
| 393 | | - /* Add heap to the list */ |
|---|
| 394 | 374 | mutex_lock(&heap_list_lock); |
|---|
| 375 | + /* check the name is unique */ |
|---|
| 376 | + list_for_each_entry(h, &heap_list, list) { |
|---|
| 377 | + if (!strcmp(h->name, exp_info->name)) { |
|---|
| 378 | + mutex_unlock(&heap_list_lock); |
|---|
| 379 | + pr_err("dma_heap: Already registered heap named %s\n", |
|---|
| 380 | + exp_info->name); |
|---|
| 381 | + err_ret = ERR_PTR(-EINVAL); |
|---|
| 382 | + put_device(heap->heap_dev); |
|---|
| 383 | + goto err3; |
|---|
| 384 | + } |
|---|
| 385 | + } |
|---|
| 386 | + |
|---|
| 387 | + /* Add heap to the list */ |
|---|
| 395 | 388 | list_add(&heap->list, &heap_list); |
|---|
| 396 | 389 | mutex_unlock(&heap_list_lock); |
|---|
| 397 | 390 | |
|---|
| 398 | 391 | return heap; |
|---|
| 399 | 392 | |
|---|
| 393 | +err3: |
|---|
| 394 | + device_destroy(dma_heap_class, heap->heap_devt); |
|---|
| 400 | 395 | err2: |
|---|
| 401 | 396 | cdev_del(&heap->heap_cdev); |
|---|
| 402 | 397 | err1: |
|---|
| 403 | | - mutex_lock(&heap_devnode_lock); |
|---|
| 404 | | - clear_bit(minor, heap_devnode_nums); |
|---|
| 405 | | - mutex_unlock(&heap_devnode_lock); |
|---|
| 398 | + xa_erase(&dma_heap_minors, minor); |
|---|
| 406 | 399 | err0: |
|---|
| 407 | 400 | kfree(heap); |
|---|
| 408 | 401 | return err_ret; |
|---|