.. | .. |
---|
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; |
---|