Skip to content

Commit

Permalink
Merge tag 'tag-for-linus-3.9' of git://git.linaro.org/people/sumitsem…
Browse files Browse the repository at this point in the history
…wal/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
  • Loading branch information
Linus Torvalds committed Mar 1, 2013
2 parents b666973 + 495c10c commit 5e04f4b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 13 deletions.
6 changes: 5 additions & 1 deletion Documentation/dma-buf-sharing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,11 @@ Access to a dma_buf from the kernel context involves three steps:
void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)

The vmap call can fail if there is no vmap support in the exporter, or if it
runs out of vmalloc space. Fallback to kmap should be implemented.
runs out of vmalloc space. Fallback to kmap should be implemented. Note that
the dma-buf layer keeps a reference count for all vmap access and calls down
into the exporter's vmap function only when no vmapping exists, and only
unmaps it once. Protection against concurrent vmap/vunmap calls is provided
by taking the dma_buf->lock mutex.

3. Finish access

Expand Down
66 changes: 55 additions & 11 deletions drivers/base/dma-buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)

dmabuf = file->private_data;

BUG_ON(dmabuf->vmapping_counter);

dmabuf->ops->release(dmabuf);
kfree(dmabuf);
return 0;
Expand Down Expand Up @@ -445,6 +447,9 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap);
int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
unsigned long pgoff)
{
struct file *oldfile;
int ret;

if (WARN_ON(!dmabuf || !vma))
return -EINVAL;

Expand All @@ -458,14 +463,22 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
return -EINVAL;

/* readjust the vma */
if (vma->vm_file)
fput(vma->vm_file);

vma->vm_file = get_file(dmabuf->file);

get_file(dmabuf->file);
oldfile = vma->vm_file;
vma->vm_file = dmabuf->file;
vma->vm_pgoff = pgoff;

return dmabuf->ops->mmap(dmabuf, vma);
ret = dmabuf->ops->mmap(dmabuf, vma);
if (ret) {
/* restore old parameters on failure */
vma->vm_file = oldfile;
fput(dmabuf->file);
} else {
if (oldfile)
fput(oldfile);
}
return ret;

}
EXPORT_SYMBOL_GPL(dma_buf_mmap);

Expand All @@ -481,12 +494,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
*/
void *dma_buf_vmap(struct dma_buf *dmabuf)
{
void *ptr;

if (WARN_ON(!dmabuf))
return NULL;

if (dmabuf->ops->vmap)
return dmabuf->ops->vmap(dmabuf);
return NULL;
if (!dmabuf->ops->vmap)
return NULL;

mutex_lock(&dmabuf->lock);
if (dmabuf->vmapping_counter) {
dmabuf->vmapping_counter++;
BUG_ON(!dmabuf->vmap_ptr);
ptr = dmabuf->vmap_ptr;
goto out_unlock;
}

BUG_ON(dmabuf->vmap_ptr);

ptr = dmabuf->ops->vmap(dmabuf);
if (IS_ERR_OR_NULL(ptr))
goto out_unlock;

dmabuf->vmap_ptr = ptr;
dmabuf->vmapping_counter = 1;

out_unlock:
mutex_unlock(&dmabuf->lock);
return ptr;
}
EXPORT_SYMBOL_GPL(dma_buf_vmap);

Expand All @@ -500,7 +535,16 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
if (WARN_ON(!dmabuf))
return;

if (dmabuf->ops->vunmap)
dmabuf->ops->vunmap(dmabuf, vaddr);
BUG_ON(!dmabuf->vmap_ptr);
BUG_ON(dmabuf->vmapping_counter == 0);
BUG_ON(dmabuf->vmap_ptr != vaddr);

mutex_lock(&dmabuf->lock);
if (--dmabuf->vmapping_counter == 0) {
if (dmabuf->ops->vunmap)
dmabuf->ops->vunmap(dmabuf, vaddr);
dmabuf->vmap_ptr = NULL;
}
mutex_unlock(&dmabuf->lock);
}
EXPORT_SYMBOL_GPL(dma_buf_vunmap);
4 changes: 3 additions & 1 deletion include/linux/dma-buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ struct dma_buf {
struct file *file;
struct list_head attachments;
const struct dma_buf_ops *ops;
/* mutex to serialize list manipulation and attach/detach */
/* mutex to serialize list manipulation, attach/detach and vmap/unmap */
struct mutex lock;
unsigned vmapping_counter;
void *vmap_ptr;
void *priv;
};

Expand Down

0 comments on commit 5e04f4b

Please sign in to comment.