summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@linux-foundation.org>2009-01-06 14:43:08 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-06 15:59:30 -0800
commit0bef3c2dc7d0c8238330785c8f4504761b0e370b (patch)
treef43e7c7e49f5e67823e7e077c821e8f8d2571e48
parent8375d4909aee4c18798f373ecf24a79f040f75fc (diff)
dma_alloc_from_coherent(): fix fallback to generic memory
If bitmap_find_free_region() fails and DMA_MEMORY_EXCLUSIVE is not set, the function will fail to write anything to *ret and will return 1. This will cause dma_alloc_coherent() to return an uninitialised value, crashing the kernel, perhaps via DMA to a random address. Fix that by changing it to return zero in this case, so the caller will proceed to allocate the memory from the generic memory allocator. Cc: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> Cc: Dmitry Baryshkov <dbaryshkov@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/dma-coherent.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/dma-coherent.c b/kernel/dma-coherent.c
index f013a0c2e111..4bdcea822b45 100644
--- a/kernel/dma-coherent.c
+++ b/kernel/dma-coherent.c
@@ -116,11 +116,25 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
int page = bitmap_find_free_region(mem->bitmap, mem->size,
order);
if (page >= 0) {
+ /*
+ * Memory was found in the per-device arena.
+ */
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
*ret = mem->virt_base + (page << PAGE_SHIFT);
memset(*ret, 0, size);
- } else if (mem->flags & DMA_MEMORY_EXCLUSIVE)
+ } else if (mem->flags & DMA_MEMORY_EXCLUSIVE) {
+ /*
+ * The per-device arena is exhausted and we are not
+ * permitted to fall back to generic memory.
+ */
*ret = NULL;
+ } else {
+ /*
+ * The per-device arena is exhausted and we are
+ * permitted to fall back to generic memory.
+ */
+ return 0;
+ }
}
return (mem != NULL);
}