From ff388d5189c5feedae807276e0893cbc7356f21d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 18 Aug 2008 15:32:11 +0000 Subject: [PATCH] DMAResource::TranslateNext(): Fixed several bugs that could cause too many bytes to be read/written, which, among other things, could trigger an assert in the IORequest code: * In case of a partial (i.e. non-block-aligned) begin, transferLeft was not adjusted correctly. * The main loop was lacking a transferLeft check. * Main loop: When finally using a bounce buffer, the unrestricted vec length was used as base length for the bounce buffer. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27042 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/device_manager/dma_resources.cpp | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/system/kernel/device_manager/dma_resources.cpp b/src/system/kernel/device_manager/dma_resources.cpp index f1d396d3bd..fc7e50a6f5 100644 --- a/src/system/kernel/device_manager/dma_resources.cpp +++ b/src/system/kernel/device_manager/dma_resources.cpp @@ -483,13 +483,21 @@ DMAResource::TranslateNext(IORequest* request, IOOperation* operation) dmaLength += length; - vecOffset += length - partialBegin; + size_t transferred = length - partialBegin; + vecOffset += transferred; offset -= partialBegin; + + if (transferLeft > transferred) + transferLeft -= transferred; + else + transferLeft = 0; + TRACE(" partial begin, using bounce buffer: offset: %lld, length: " "%lu\n", offset, length); } - for (uint32 i = vecIndex; i < vecIndex + segmentCount;) { + for (uint32 i = vecIndex; + i < vecIndex + segmentCount && transferLeft > 0;) { if (dmaBuffer->VecCount() >= fRestrictions.max_segment_count) break; @@ -501,9 +509,10 @@ DMAResource::TranslateNext(IORequest* request, IOOperation* operation) } addr_t base = (addr_t)vec.iov_base + vecOffset; - size_t length = vec.iov_len - vecOffset; - if (length > transferLeft) - length = transferLeft; + size_t maxLength = vec.iov_len - vecOffset; + if (maxLength > transferLeft) + maxLength = transferLeft; + size_t length = maxLength; // Cut the vec according to transfer size, segment size, and boundary. @@ -540,7 +549,7 @@ DMAResource::TranslateNext(IORequest* request, IOOperation* operation) // If length is 0, use bounce buffer for complete vec. if (length == 0) { - length = vec.iov_len - vecOffset; + length = maxLength; useBounceBufferSize = length; TRACE(" vec %lu: 0 length, using bounce buffer: %lu\n", i, useBounceBufferSize); @@ -567,7 +576,7 @@ DMAResource::TranslateNext(IORequest* request, IOOperation* operation) dmaLength += length; vecOffset += length; - transferLeft -= length; + transferLeft -= min_c(length, transferLeft); } // If we're writing partially, we always need to have a block sized bounce