diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-28 22:43:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-28 22:43:13 -0500 |
commit | 5e04f4b4290e03deb91b074087ae8d7c169d947d (patch) | |
tree | 07802848a6afce236de7c3185be06db8567b38f0 | |
parent | b6669737d3db7df79fad07180837c23dbe581db5 (diff) | |
parent | 495c10cc1c0c359871d5bef32dd173252fc17995 (diff) |
Merge tag 'tag-for-linus-3.9' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf
Pull dma-buf framework updates from Sumit Semwal:
"Refcounting implemented for vmap in core dma-buf"
* tag 'tag-for-linus-3.9' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf:
CHROMIUM: dma-buf: restore args on failure of dma_buf_mmap
dma-buf: implement vmap refcounting in the interface logic
-rw-r--r-- | Documentation/dma-buf-sharing.txt | 6 | ||||
-rw-r--r-- | drivers/base/dma-buf.c | 66 | ||||
-rw-r--r-- | include/linux/dma-buf.h | 4 |
3 files changed, 63 insertions, 13 deletions
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index 0188903bc9e1..4966b1be42ac 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt | |||
@@ -302,7 +302,11 @@ Access to a dma_buf from the kernel context involves three steps: | |||
302 | void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | 302 | void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) |
303 | 303 | ||
304 | The vmap call can fail if there is no vmap support in the exporter, or if it | 304 | The vmap call can fail if there is no vmap support in the exporter, or if it |
305 | runs out of vmalloc space. Fallback to kmap should be implemented. | 305 | runs out of vmalloc space. Fallback to kmap should be implemented. Note that |
306 | the dma-buf layer keeps a reference count for all vmap access and calls down | ||
307 | into the exporter's vmap function only when no vmapping exists, and only | ||
308 | unmaps it once. Protection against concurrent vmap/vunmap calls is provided | ||
309 | by taking the dma_buf->lock mutex. | ||
306 | 310 | ||
307 | 3. Finish access | 311 | 3. Finish access |
308 | 312 | ||
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index ff5b745c4705..2a7cb0df176b 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c | |||
@@ -39,6 +39,8 @@ static int dma_buf_release(struct inode *inode, struct file *file) | |||
39 | 39 | ||
40 | dmabuf = file->private_data; | 40 | dmabuf = file->private_data; |
41 | 41 | ||
42 | BUG_ON(dmabuf->vmapping_counter); | ||
43 | |||
42 | dmabuf->ops->release(dmabuf); | 44 | dmabuf->ops->release(dmabuf); |
43 | kfree(dmabuf); | 45 | kfree(dmabuf); |
44 | return 0; | 46 | return 0; |
@@ -445,6 +447,9 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap); | |||
445 | int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, | 447 | int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, |
446 | unsigned long pgoff) | 448 | unsigned long pgoff) |
447 | { | 449 | { |
450 | struct file *oldfile; | ||
451 | int ret; | ||
452 | |||
448 | if (WARN_ON(!dmabuf || !vma)) | 453 | if (WARN_ON(!dmabuf || !vma)) |
449 | return -EINVAL; | 454 | return -EINVAL; |
450 | 455 | ||
@@ -458,14 +463,22 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, | |||
458 | return -EINVAL; | 463 | return -EINVAL; |
459 | 464 | ||
460 | /* readjust the vma */ | 465 | /* readjust the vma */ |
461 | if (vma->vm_file) | 466 | get_file(dmabuf->file); |
462 | fput(vma->vm_file); | 467 | oldfile = vma->vm_file; |
463 | 468 | vma->vm_file = dmabuf->file; | |
464 | vma->vm_file = get_file(dmabuf->file); | ||
465 | |||
466 | vma->vm_pgoff = pgoff; | 469 | vma->vm_pgoff = pgoff; |
467 | 470 | ||
468 | return dmabuf->ops->mmap(dmabuf, vma); | 471 | ret = dmabuf->ops->mmap(dmabuf, vma); |
472 | if (ret) { | ||
473 | /* restore old parameters on failure */ | ||
474 | vma->vm_file = oldfile; | ||
475 | fput(dmabuf->file); | ||
476 | } else { | ||
477 | if (oldfile) | ||
478 | fput(oldfile); | ||
479 | } | ||
480 | return ret; | ||
481 | |||
469 | } | 482 | } |
470 | EXPORT_SYMBOL_GPL(dma_buf_mmap); | 483 | EXPORT_SYMBOL_GPL(dma_buf_mmap); |
471 | 484 | ||
@@ -481,12 +494,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap); | |||
481 | */ | 494 | */ |
482 | void *dma_buf_vmap(struct dma_buf *dmabuf) | 495 | void *dma_buf_vmap(struct dma_buf *dmabuf) |
483 | { | 496 | { |
497 | void *ptr; | ||
498 | |||
484 | if (WARN_ON(!dmabuf)) | 499 | if (WARN_ON(!dmabuf)) |
485 | return NULL; | 500 | return NULL; |
486 | 501 | ||
487 | if (dmabuf->ops->vmap) | 502 | if (!dmabuf->ops->vmap) |
488 | return dmabuf->ops->vmap(dmabuf); | 503 | return NULL; |
489 | return NULL; | 504 | |
505 | mutex_lock(&dmabuf->lock); | ||
506 | if (dmabuf->vmapping_counter) { | ||
507 | dmabuf->vmapping_counter++; | ||
508 | BUG_ON(!dmabuf->vmap_ptr); | ||
509 | ptr = dmabuf->vmap_ptr; | ||
510 | goto out_unlock; | ||
511 | } | ||
512 | |||
513 | BUG_ON(dmabuf->vmap_ptr); | ||
514 | |||
515 | ptr = dmabuf->ops->vmap(dmabuf); | ||
516 | if (IS_ERR_OR_NULL(ptr)) | ||
517 | goto out_unlock; | ||
518 | |||
519 | dmabuf->vmap_ptr = ptr; | ||
520 | dmabuf->vmapping_counter = 1; | ||
521 | |||
522 | out_unlock: | ||
523 | mutex_unlock(&dmabuf->lock); | ||
524 | return ptr; | ||
490 | } | 525 | } |
491 | EXPORT_SYMBOL_GPL(dma_buf_vmap); | 526 | EXPORT_SYMBOL_GPL(dma_buf_vmap); |
492 | 527 | ||
@@ -500,7 +535,16 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | |||
500 | if (WARN_ON(!dmabuf)) | 535 | if (WARN_ON(!dmabuf)) |
501 | return; | 536 | return; |
502 | 537 | ||
503 | if (dmabuf->ops->vunmap) | 538 | BUG_ON(!dmabuf->vmap_ptr); |
504 | dmabuf->ops->vunmap(dmabuf, vaddr); | 539 | BUG_ON(dmabuf->vmapping_counter == 0); |
540 | BUG_ON(dmabuf->vmap_ptr != vaddr); | ||
541 | |||
542 | mutex_lock(&dmabuf->lock); | ||
543 | if (--dmabuf->vmapping_counter == 0) { | ||
544 | if (dmabuf->ops->vunmap) | ||
545 | dmabuf->ops->vunmap(dmabuf, vaddr); | ||
546 | dmabuf->vmap_ptr = NULL; | ||
547 | } | ||
548 | mutex_unlock(&dmabuf->lock); | ||
505 | } | 549 | } |
506 | EXPORT_SYMBOL_GPL(dma_buf_vunmap); | 550 | EXPORT_SYMBOL_GPL(dma_buf_vunmap); |
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 3d754a394e92..9978b614a1aa 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h | |||
@@ -119,8 +119,10 @@ struct dma_buf { | |||
119 | struct file *file; | 119 | struct file *file; |
120 | struct list_head attachments; | 120 | struct list_head attachments; |
121 | const struct dma_buf_ops *ops; | 121 | const struct dma_buf_ops *ops; |
122 | /* mutex to serialize list manipulation and attach/detach */ | 122 | /* mutex to serialize list manipulation, attach/detach and vmap/unmap */ |
123 | struct mutex lock; | 123 | struct mutex lock; |
124 | unsigned vmapping_counter; | ||
125 | void *vmap_ptr; | ||
124 | void *priv; | 126 | void *priv; |
125 | }; | 127 | }; |
126 | 128 | ||