3.9: dma-buf updates

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJRLdoIAAoJEAG+/NWsLn5b1bAQAOTPfhn3e7BuhzPrKADk0hfo
 GjMXy62wreou/Zl5FanouQOXoPKkIMX4M1wfUjljdLOTkAbWxnElOqvWaoG64L1S
 +PmZ9YvR8uPn8zA8vTUjCgmbjcqNymHRIKKKsOSfPnbe/s0X39zcZIYWSI0rZVnq
 7s4FpWtyU6ltTPn63VvkDeaKWyYI4EW5erM1gnQ3aiBmW19UlgEQ3/quzk13lZnn
 hkIdkiA2eA9N81mC7uzt+nl5fQ+AzvcWIKEKw7GJBo5oweMwD9QTu569Dfuo/wBV
 pHQnbyifRnYLM4k1lpL5upg7Bt+D/dGX40XyW7MJysqlrWIvt8p3ahs1ZHcGzvO8
 Pv43Dg/68Y3H1F9qxulNQmlmr4c7pJszdTARqRiBTEzUwEQ678Qgzw4jNPxVU5Cn
 YYUXDI0J0rnA7NQWbZI+xZShLO4q3gr09SaxRmIXjdvNxI6epFioo3RGm+UE3inJ
 EgDvGdkolBzcoQ9Mfp8Sf2ACcwAhigr+U+KesIB5Q9uSSZ4rP89N+OCtmP+Ul+Ct
 xI/eqrQX6zI2sJfCSRhXaomsbgiufWmUCqN8rhC5ZaOYiC56t6QRu4v6KrY7ryGv
 8BQfP8FW8uDqGiv9pbK2YT+MB8dQuuGvZv5kU7O0fuPu8HoGIgzJ+KZzqjfGdhkL
 zfTZDHW9KSn2mz+otaYz
 =9Fzb
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2013-02-28 19:43:13 -08:00
commit 5e04f4b429
3 changed files with 63 additions and 13 deletions

View File

@ -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) 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 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 3. Finish access

View File

@ -39,6 +39,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)
dmabuf = file->private_data; dmabuf = file->private_data;
BUG_ON(dmabuf->vmapping_counter);
dmabuf->ops->release(dmabuf); dmabuf->ops->release(dmabuf);
kfree(dmabuf); kfree(dmabuf);
return 0; return 0;
@ -445,6 +447,9 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap);
int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
unsigned long pgoff) unsigned long pgoff)
{ {
struct file *oldfile;
int ret;
if (WARN_ON(!dmabuf || !vma)) if (WARN_ON(!dmabuf || !vma))
return -EINVAL; return -EINVAL;
@ -458,14 +463,22 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
return -EINVAL; return -EINVAL;
/* readjust the vma */ /* readjust the vma */
if (vma->vm_file) get_file(dmabuf->file);
fput(vma->vm_file); oldfile = vma->vm_file;
vma->vm_file = dmabuf->file;
vma->vm_file = get_file(dmabuf->file);
vma->vm_pgoff = pgoff; 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); EXPORT_SYMBOL_GPL(dma_buf_mmap);
@ -481,12 +494,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
*/ */
void *dma_buf_vmap(struct dma_buf *dmabuf) void *dma_buf_vmap(struct dma_buf *dmabuf)
{ {
void *ptr;
if (WARN_ON(!dmabuf)) if (WARN_ON(!dmabuf))
return NULL; return NULL;
if (dmabuf->ops->vmap) if (!dmabuf->ops->vmap)
return dmabuf->ops->vmap(dmabuf); return NULL;
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); EXPORT_SYMBOL_GPL(dma_buf_vmap);
@ -500,7 +535,16 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
if (WARN_ON(!dmabuf)) if (WARN_ON(!dmabuf))
return; return;
if (dmabuf->ops->vunmap) BUG_ON(!dmabuf->vmap_ptr);
dmabuf->ops->vunmap(dmabuf, vaddr); 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); EXPORT_SYMBOL_GPL(dma_buf_vunmap);

View File

@ -119,8 +119,10 @@ struct dma_buf {
struct file *file; struct file *file;
struct list_head attachments; struct list_head attachments;
const struct dma_buf_ops *ops; 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; struct mutex lock;
unsigned vmapping_counter;
void *vmap_ptr;
void *priv; void *priv;
}; };