aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-28 22:43:13 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-28 22:43:13 -0500
commit5e04f4b4290e03deb91b074087ae8d7c169d947d (patch)
tree07802848a6afce236de7c3185be06db8567b38f0
parentb6669737d3db7df79fad07180837c23dbe581db5 (diff)
parent495c10cc1c0c359871d5bef32dd173252fc17995 (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.txt6
-rw-r--r--drivers/base/dma-buf.c66
-rw-r--r--include/linux/dma-buf.h4
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
3073. Finish access 3113. 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);
445int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, 447int 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}
470EXPORT_SYMBOL_GPL(dma_buf_mmap); 483EXPORT_SYMBOL_GPL(dma_buf_mmap);
471 484
@@ -481,12 +494,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
481 */ 494 */
482void *dma_buf_vmap(struct dma_buf *dmabuf) 495void *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
522out_unlock:
523 mutex_unlock(&dmabuf->lock);
524 return ptr;
490} 525}
491EXPORT_SYMBOL_GPL(dma_buf_vmap); 526EXPORT_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}
506EXPORT_SYMBOL_GPL(dma_buf_vunmap); 550EXPORT_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