diff --git a/src/add-ons/kernel/drivers/disk/nvme/nvme_disk.cpp b/src/add-ons/kernel/drivers/disk/nvme/nvme_disk.cpp index dca857e91b..b39e0fe207 100644 --- a/src/add-ons/kernel/drivers/disk/nvme/nvme_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/nvme/nvme_disk.cpp @@ -570,7 +570,6 @@ nvme_disk_bounced_io(nvme_disk_handle* handle, io_request* request) if (status != B_OK) break; - size_t transferredBytes = 0; do { TRACE("%p: IOO offset: %" B_PRIdOFF ", length: %" B_PRIuGENADDR ", write: %s\n", request, operation.Offset(), @@ -583,10 +582,9 @@ nvme_disk_bounced_io(nvme_disk_handle* handle, io_request* request) nvme_request.iovec_count = operation.VecCount(); status = do_nvme_io_request(handle->info, &nvme_request); - if (status == B_OK && nvme_request.write == request->IsWrite()) - transferredBytes += operation.OriginalLength(); - operation.SetStatus(status); + operation.SetStatus(status, + status == B_OK ? operation.Length() : 0); } while (status == B_OK && !operation.Finish()); if (status == B_OK && operation.Status() != B_OK) { @@ -594,9 +592,7 @@ nvme_disk_bounced_io(nvme_disk_handle* handle, io_request* request) status = operation.Status(); } - operation.SetTransferredBytes(transferredBytes); - request->OperationFinished(&operation, status, status != B_OK, - operation.OriginalOffset() + transferredBytes); + request->OperationFinished(&operation); handle->info->dma_resource.RecycleBuffer(operation.Buffer()); diff --git a/src/system/kernel/device_manager/IOCache.cpp b/src/system/kernel/device_manager/IOCache.cpp index e62f489785..a18ff384c7 100644 --- a/src/system/kernel/device_manager/IOCache.cpp +++ b/src/system/kernel/device_manager/IOCache.cpp @@ -203,6 +203,8 @@ void IOCache::OperationCompleted(IOOperation* operation, status_t status, generic_size_t transferredBytes) { + operation->SetStatus(status, transferredBytes); + if (status == B_OK) { // always fail in case of partial transfers ((Operation*)operation)->finishedCondition.NotifyAll( @@ -466,8 +468,7 @@ IOCache::_TransferRequestLineUncached(IORequest* request, off_t lineOffset, error = _DoOperation(operation); - request->OperationFinished(&operation, error, false, - error == B_OK ? operation.OriginalLength() : 0); + request->OperationFinished(&operation); request->SetUnfinished(); // Keep the request in unfinished state. ScheduleRequest() will set // the final status and notify. diff --git a/src/system/kernel/device_manager/IORequest.cpp b/src/system/kernel/device_manager/IORequest.cpp index eb93c1c5c8..2c44253ad1 100644 --- a/src/system/kernel/device_manager/IORequest.cpp +++ b/src/system/kernel/device_manager/IORequest.cpp @@ -291,10 +291,33 @@ IOBuffer::Dump() const // #pragma mark - +void +IOOperation::SetStatus(status_t status, generic_size_t completedLength) +{ + IORequestChunk::SetStatus(status); + if (IsWrite() == fParent->IsWrite()) { + // Determine how many bytes we actually read or wrote, + // relative to the original range, not the translated range. + const generic_size_t partialBegin = (fOriginalOffset - fOffset); + generic_size_t originalTransferredBytes = completedLength; + if (originalTransferredBytes < partialBegin) + originalTransferredBytes = 0; + else + originalTransferredBytes -= partialBegin; + + if (originalTransferredBytes > fOriginalLength) + originalTransferredBytes = fOriginalLength; + + fTransferredBytes += originalTransferredBytes; + } +} + + bool IOOperation::Finish() { TRACE("IOOperation::Finish()\n"); + if (fStatus == B_OK) { if (fParent->IsWrite()) { TRACE(" is write\n"); @@ -318,7 +341,7 @@ IOOperation::Finish() return false; } - SetStatus(error); + IORequestChunk::SetStatus(error); } else if (fPhase == PHASE_READ_END) { TRACE(" phase read end\n"); // repair phase adjusted vec @@ -338,7 +361,7 @@ IOOperation::Finish() return false; } - SetStatus(error); + IORequestChunk::SetStatus(error); } } } @@ -402,7 +425,7 @@ IOOperation::Finish() } if (error != B_OK) - SetStatus(error); + IORequestChunk::SetStatus(error); } return true; @@ -1012,8 +1035,7 @@ IORequest::SetStatusAndNotify(status_t status) void -IORequest::OperationFinished(IOOperation* operation, status_t status, - bool partialTransfer, generic_size_t transferEndOffset) +IORequest::OperationFinished(IOOperation* operation) { TRACE("IORequest::OperationFinished(%p, %#" B_PRIx32 "): request: %p\n", operation, status, this); @@ -1023,6 +1045,12 @@ IORequest::OperationFinished(IOOperation* operation, status_t status, fChildren.Remove(operation); operation->SetParent(NULL); + const status_t status = operation->Status(); + const bool partialTransfer = + (operation->TransferredBytes() < operation->OriginalLength()); + const generic_size_t transferEndOffset = + (operation->OriginalOffset() + operation->TransferredBytes()); + if (status != B_OK || partialTransfer) { if (fTransferSize > transferEndOffset) fTransferSize = transferEndOffset; diff --git a/src/system/kernel/device_manager/IORequest.h b/src/system/kernel/device_manager/IORequest.h index 1e754b8c12..8b262967e9 100644 --- a/src/system/kernel/device_manager/IORequest.h +++ b/src/system/kernel/device_manager/IORequest.h @@ -127,6 +127,9 @@ struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl { public: bool Finish(); // returns true, if it can be recycled + // otherwise, there is more to be done + + void SetStatus(status_t status, generic_size_t completedLength); status_t Prepare(IORequest* request); void SetOriginalRange(off_t offset, @@ -134,11 +137,9 @@ public: // also sets range void SetRange(off_t offset, generic_size_t length); - void SetStatus(status_t status) - { IORequestChunk::SetStatus(status); } - off_t Offset() const; generic_size_t Length() const; + off_t OriginalOffset() const { return fOriginalOffset; } generic_size_t OriginalLength() const @@ -146,8 +147,6 @@ public: generic_size_t TransferredBytes() const { return fTransferredBytes; } - void SetTransferredBytes(generic_size_t bytes) - { fTransferredBytes = bytes; } generic_io_vec* Vecs() const; uint32 VecCount() const; @@ -256,9 +255,7 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl { bool HasCallbacks() const; void SetStatusAndNotify(status_t status); - void OperationFinished(IOOperation* operation, - status_t status, bool partialTransfer, - generic_size_t transferEndOffset); + void OperationFinished(IOOperation* operation); void SubRequestFinished(IORequest* request, status_t status, bool partialTransfer, generic_size_t transferEndOffset); diff --git a/src/system/kernel/device_manager/IOSchedulerSimple.cpp b/src/system/kernel/device_manager/IOSchedulerSimple.cpp index 001bfee9e5..c1daa0ae22 100644 --- a/src/system/kernel/device_manager/IOSchedulerSimple.cpp +++ b/src/system/kernel/device_manager/IOSchedulerSimple.cpp @@ -291,13 +291,7 @@ IOSchedulerSimple::OperationCompleted(IOOperation* operation, status_t status, if (operation->Status() <= 0) return; - operation->SetStatus(status); - - // set the bytes transferred (of the net data) - generic_size_t partialBegin - = operation->OriginalOffset() - operation->Offset(); - operation->SetTransferredBytes( - transferredBytes > partialBegin ? transferredBytes - partialBegin : 0); + operation->SetStatus(status, transferredBytes); fCompletedOperations.Add(operation); fFinishedOperationCondition.NotifyAll(); @@ -344,7 +338,6 @@ IOSchedulerSimple::_Finisher() if (!operationFinished) { TRACE(" operation: %p not finished yet\n", operation); MutexLocker _(fLock); - operation->SetTransferredBytes(0); operation->Parent()->Owner()->operations.Add(operation); fPendingOperations--; continue; @@ -353,13 +346,7 @@ IOSchedulerSimple::_Finisher() // notify request and remove operation IORequest* request = operation->Parent(); - generic_size_t operationOffset - = operation->OriginalOffset() - request->Offset(); - request->OperationFinished(operation, operation->Status(), - operation->TransferredBytes() < operation->OriginalLength(), - operation->Status() == B_OK - ? operationOffset + operation->OriginalLength() - : operationOffset); + request->OperationFinished(operation); // recycle the operation MutexLocker _(fLock);