Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+63 -13
+5 -1
Documentation/dma-buf-sharing.txt
··· 302 302 void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) 303 303 304 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 311 3. Finish access 308 312
+55 -11
drivers/base/dma-buf.c
··· 39 39 40 40 dmabuf = file->private_data; 41 41 42 + BUG_ON(dmabuf->vmapping_counter); 43 + 42 44 dmabuf->ops->release(dmabuf); 43 45 kfree(dmabuf); 44 46 return 0; ··· 447 445 int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, 448 446 unsigned long pgoff) 449 447 { 448 + struct file *oldfile; 449 + int ret; 450 + 450 451 if (WARN_ON(!dmabuf || !vma)) 451 452 return -EINVAL; 452 453 ··· 463 458 return -EINVAL; 464 459 465 460 /* readjust the vma */ 466 - if (vma->vm_file) 467 - fput(vma->vm_file); 468 - 469 - vma->vm_file = get_file(dmabuf->file); 470 - 461 + get_file(dmabuf->file); 462 + oldfile = vma->vm_file; 463 + vma->vm_file = dmabuf->file; 471 464 vma->vm_pgoff = pgoff; 472 465 473 - return dmabuf->ops->mmap(dmabuf, vma); 466 + ret = dmabuf->ops->mmap(dmabuf, vma); 467 + if (ret) { 468 + /* restore old parameters on failure */ 469 + vma->vm_file = oldfile; 470 + fput(dmabuf->file); 471 + } else { 472 + if (oldfile) 473 + fput(oldfile); 474 + } 475 + return ret; 476 + 474 477 } 475 478 EXPORT_SYMBOL_GPL(dma_buf_mmap); 476 479 ··· 494 481 */ 495 482 void *dma_buf_vmap(struct dma_buf *dmabuf) 496 483 { 484 + void *ptr; 485 + 497 486 if (WARN_ON(!dmabuf)) 498 487 return NULL; 499 488 500 - if (dmabuf->ops->vmap) 501 - return dmabuf->ops->vmap(dmabuf); 502 - return NULL; 489 + if (!dmabuf->ops->vmap) 490 + return NULL; 491 + 492 + mutex_lock(&dmabuf->lock); 493 + if (dmabuf->vmapping_counter) { 494 + dmabuf->vmapping_counter++; 495 + BUG_ON(!dmabuf->vmap_ptr); 496 + ptr = dmabuf->vmap_ptr; 497 + goto out_unlock; 498 + } 499 + 500 + BUG_ON(dmabuf->vmap_ptr); 501 + 502 + ptr = dmabuf->ops->vmap(dmabuf); 503 + if (IS_ERR_OR_NULL(ptr)) 504 + goto out_unlock; 505 + 506 + dmabuf->vmap_ptr = ptr; 507 + dmabuf->vmapping_counter = 1; 508 + 509 + out_unlock: 510 + mutex_unlock(&dmabuf->lock); 511 + return ptr; 503 512 } 504 513 EXPORT_SYMBOL_GPL(dma_buf_vmap); 505 514 ··· 535 500 if (WARN_ON(!dmabuf)) 536 501 return; 537 502 538 - if (dmabuf->ops->vunmap) 539 - dmabuf->ops->vunmap(dmabuf, vaddr); 503 + BUG_ON(!dmabuf->vmap_ptr); 504 + BUG_ON(dmabuf->vmapping_counter == 0); 505 + BUG_ON(dmabuf->vmap_ptr != vaddr); 506 + 507 + mutex_lock(&dmabuf->lock); 508 + if (--dmabuf->vmapping_counter == 0) { 509 + if (dmabuf->ops->vunmap) 510 + dmabuf->ops->vunmap(dmabuf, vaddr); 511 + dmabuf->vmap_ptr = NULL; 512 + } 513 + mutex_unlock(&dmabuf->lock); 540 514 } 541 515 EXPORT_SYMBOL_GPL(dma_buf_vunmap);
+3 -1
include/linux/dma-buf.h
··· 119 119 struct file *file; 120 120 struct list_head attachments; 121 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 123 struct mutex lock; 124 + unsigned vmapping_counter; 125 + void *vmap_ptr; 124 126 void *priv; 125 127 }; 126 128