mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 07:18:40 +01:00
kernel/fs: Fix handling of partial requests in do_synchronous_iterative_vnode_io.
If get_vecs returns 0 and no vecs, then we need to quit iterating. Otherwise we'll just loop forever and leak memory. Also add an assert in IOBuffer::GetNextVirtualVec that would have caught this problem, and the memory leak it results in.
This commit is contained in:
parent
e829154ffe
commit
5c56d775a9
@ -165,9 +165,10 @@ IOBuffer::GetNextVirtualVec(void*& _cookie, iovec& vector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cookie->vec_index == 0
|
if (cookie->vec_index == 0
|
||||||
&& (fVecCount > 1 || fVecs[0].length > B_PAGE_SIZE)) {
|
&& (fVecCount > 1 || fVecs[0].length > B_PAGE_SIZE)) {
|
||||||
void* mappedAddress;
|
void* mappedAddress;
|
||||||
addr_t mappedSize;
|
addr_t mappedSize;
|
||||||
|
ASSERT(cookie->mapped_area == -1);
|
||||||
|
|
||||||
// TODO: This is a potential violation of the VIP requirement, since
|
// TODO: This is a potential violation of the VIP requirement, since
|
||||||
// vm_map_physical_memory_vecs() allocates memory without special flags!
|
// vm_map_physical_memory_vecs() allocates memory without special flags!
|
||||||
@ -216,9 +217,9 @@ void
|
|||||||
IOBuffer::FreeVirtualVecCookie(void* _cookie)
|
IOBuffer::FreeVirtualVecCookie(void* _cookie)
|
||||||
{
|
{
|
||||||
virtual_vec_cookie* cookie = (virtual_vec_cookie*)_cookie;
|
virtual_vec_cookie* cookie = (virtual_vec_cookie*)_cookie;
|
||||||
|
|
||||||
if (cookie->mapped_area >= 0)
|
if (cookie->mapped_area >= 0)
|
||||||
delete_area(cookie->mapped_area);
|
delete_area(cookie->mapped_area);
|
||||||
|
|
||||||
cookie->PutPhysicalPageIfNeeded();
|
cookie->PutPhysicalPageIfNeeded();
|
||||||
|
|
||||||
free_etc(cookie, fVIP ? HEAP_PRIORITY_VIP : 0);
|
free_etc(cookie, fVIP ? HEAP_PRIORITY_VIP : 0);
|
||||||
|
@ -292,8 +292,9 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
|||||||
generic_size_t length = request->Length();
|
generic_size_t length = request->Length();
|
||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
bool partial = false;
|
||||||
|
|
||||||
for (; error == B_OK && length > 0
|
for (; error == B_OK && length > 0 && !partial
|
||||||
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
||||||
uint8* vecBase = (uint8*)vector.iov_base;
|
uint8* vecBase = (uint8*)vector.iov_base;
|
||||||
generic_size_t vecLength = min_c(vector.iov_len, length);
|
generic_size_t vecLength = min_c(vector.iov_len, length);
|
||||||
@ -309,8 +310,12 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
|||||||
fileVecs[0].length = vecLength;
|
fileVecs[0].length = vecLength;
|
||||||
fileVecCount = 1;
|
fileVecCount = 1;
|
||||||
}
|
}
|
||||||
if (error != B_OK || fileVecCount == 0)
|
if (error != B_OK)
|
||||||
break;
|
break;
|
||||||
|
if (fileVecCount == 0) {
|
||||||
|
partial = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < fileVecCount; i++) {
|
for (size_t i = 0; i < fileVecCount; i++) {
|
||||||
const file_io_vec& fileVec = fileVecs[i];
|
const file_io_vec& fileVec = fileVecs[i];
|
||||||
@ -325,15 +330,17 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
|||||||
vecBase += transferred;
|
vecBase += transferred;
|
||||||
vecLength -= transferred;
|
vecLength -= transferred;
|
||||||
|
|
||||||
if (transferred != toTransfer)
|
if (transferred != toTransfer) {
|
||||||
|
partial = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||||
|
|
||||||
bool partial = length > 0;
|
partial = (partial || length > 0);
|
||||||
size_t bytesTransferred = request->Length() - length;
|
size_t bytesTransferred = request->Length() - length;
|
||||||
request->SetTransferredBytes(partial, bytesTransferred);
|
request->SetTransferredBytes(partial, bytesTransferred);
|
||||||
if (finished != NULL)
|
if (finished != NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user