Virtualize the buffers using IOBuffer::GetNextVirtualVec(). This removes the
need for the IO -> InternalIO indirection as it is always fed virtual buffers, which simplifies things a bit. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33525 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -69,10 +69,9 @@ struct iterative_io_cookie {
|
||||
|
||||
class DoIO {
|
||||
public:
|
||||
DoIO(bool write, bool isPhysical)
|
||||
DoIO(bool write)
|
||||
:
|
||||
fWrite(write),
|
||||
fIsPhysical(isPhysical)
|
||||
fWrite(write)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -80,88 +79,27 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
status_t IO(off_t offset, void* _buffer, size_t* _length)
|
||||
{
|
||||
if (!fIsPhysical)
|
||||
return InternalIO(offset, _buffer, _length);
|
||||
|
||||
// buffer points to physical address -- map pages
|
||||
addr_t buffer = (addr_t)_buffer;
|
||||
size_t length = *_length;
|
||||
|
||||
if (length > B_PAGE_SIZE) {
|
||||
// try to not split up the request if possible
|
||||
// TODO: map with less overhead! pre-reserved address space
|
||||
// could be used as a scratch space for example, directly mapping
|
||||
// pages into that instead of creating new areas for each request
|
||||
void* virtualAddress;
|
||||
area_id mapArea = map_physical_memory("physical io request map",
|
||||
(void*)buffer, length, B_ANY_ADDRESS, B_KERNEL_READ_AREA
|
||||
| B_KERNEL_WRITE_AREA, &virtualAddress);
|
||||
if (mapArea >= 0) {
|
||||
status_t result = InternalIO(offset, virtualAddress, _length);
|
||||
delete_area(mapArea);
|
||||
return result;
|
||||
}
|
||||
|
||||
// otherwise we fall back to page wise mapping
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
addr_t pageOffset = buffer % B_PAGE_SIZE;
|
||||
addr_t virtualAddress;
|
||||
void* handle;
|
||||
status_t error = vm_get_physical_page(buffer - pageOffset,
|
||||
&virtualAddress, &handle);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
size_t toTransfer = min_c(length, B_PAGE_SIZE - pageOffset);
|
||||
size_t transferred = toTransfer;
|
||||
error = InternalIO(offset, (void*)(virtualAddress + pageOffset),
|
||||
&transferred);
|
||||
|
||||
vm_put_physical_page(virtualAddress, handle);
|
||||
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
offset += transferred;
|
||||
buffer += transferred;
|
||||
length -= transferred;
|
||||
|
||||
if (transferred != toTransfer)
|
||||
break;
|
||||
}
|
||||
|
||||
*_length -= length;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual status_t InternalIO(off_t offset, void* buffer, size_t* length) = 0;
|
||||
virtual status_t IO(off_t offset, void* buffer, size_t* length) = 0;
|
||||
|
||||
protected:
|
||||
bool fWrite;
|
||||
bool fIsPhysical;
|
||||
};
|
||||
|
||||
|
||||
class CallbackIO : public DoIO {
|
||||
public:
|
||||
CallbackIO(bool write, bool isPhysical,
|
||||
CallbackIO(bool write,
|
||||
status_t (*doIO)(void* cookie, off_t offset, void* buffer,
|
||||
size_t* length),
|
||||
void* cookie)
|
||||
:
|
||||
DoIO(write, isPhysical),
|
||||
DoIO(write),
|
||||
fDoIO(doIO),
|
||||
fCookie(cookie)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
|
||||
virtual status_t IO(off_t offset, void* buffer, size_t* length)
|
||||
{
|
||||
return fDoIO(fCookie, offset, buffer, length);
|
||||
}
|
||||
@@ -174,16 +112,15 @@ private:
|
||||
|
||||
class VnodeIO : public DoIO {
|
||||
public:
|
||||
VnodeIO(bool write, bool isPhysical, struct vnode* vnode, void* cookie)
|
||||
VnodeIO(bool writen, struct vnode* vnode, void* cookie)
|
||||
:
|
||||
DoIO(write, isPhysical),
|
||||
DoIO(write),
|
||||
fVnode(vnode),
|
||||
fCookie(cookie)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
|
||||
virtual status_t IO(off_t offset, void* buffer, size_t* length)
|
||||
{
|
||||
iovec vec;
|
||||
vec.iov_base = buffer;
|
||||
@@ -324,18 +261,19 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
||||
iterative_io_finished finished, void* cookie)
|
||||
{
|
||||
IOBuffer* buffer = request->Buffer();
|
||||
VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, openCookie);
|
||||
VnodeIO io(request->IsWrite(), vnode, openCookie);
|
||||
|
||||
iovec* vecs = buffer->Vecs();
|
||||
int32 vecCount = buffer->VecCount();
|
||||
iovec vector;
|
||||
void* virtualVecCookie = NULL;
|
||||
off_t offset = request->Offset();
|
||||
size_t length = request->Length();
|
||||
|
||||
status_t error = B_OK;
|
||||
|
||||
for (int32 i = 0; error == B_OK && length > 0 && i < vecCount; i++) {
|
||||
uint8* vecBase = (uint8*)vecs[i].iov_base;
|
||||
size_t vecLength = min_c(vecs[i].iov_len, length);
|
||||
for (; error == B_OK && length > 0
|
||||
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
||||
uint8* vecBase = (uint8*)vector.iov_base;
|
||||
size_t vecLength = min_c(vector.iov_len, length);
|
||||
|
||||
while (error == B_OK && vecLength > 0) {
|
||||
file_io_vec fileVecs[8];
|
||||
@@ -345,7 +283,7 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
||||
if (error != B_OK || fileVecCount == 0)
|
||||
break;
|
||||
|
||||
for (uint32 k = 0; k < fileVecCount; k++) {
|
||||
for (uint32 i = 0; i < fileVecCount; i++) {
|
||||
const file_io_vec& fileVec = fileVecs[i];
|
||||
size_t toTransfer = min_c(fileVec.length, length);
|
||||
size_t transferred = toTransfer;
|
||||
@@ -364,6 +302,8 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
||||
}
|
||||
}
|
||||
|
||||
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||
|
||||
bool partial = length > 0;
|
||||
size_t bytesTransferred = request->Length() - length;
|
||||
request->SetTransferredBytes(partial, bytesTransferred);
|
||||
@@ -381,14 +321,15 @@ synchronous_io(io_request* request, DoIO& io)
|
||||
|
||||
IOBuffer* buffer = request->Buffer();
|
||||
|
||||
iovec* vecs = buffer->Vecs();
|
||||
int32 vecCount = buffer->VecCount();
|
||||
iovec vector;
|
||||
void* virtualVecCookie = NULL;
|
||||
off_t offset = request->Offset();
|
||||
size_t length = request->Length();
|
||||
|
||||
for (int32 i = 0; length > 0 && i < vecCount; i++) {
|
||||
void* vecBase = vecs[i].iov_base;
|
||||
size_t vecLength = min_c(vecs[i].iov_len, length);
|
||||
for (; length > 0
|
||||
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
||||
void* vecBase = vector.iov_base;
|
||||
size_t vecLength = min_c(vector.iov_len, length);
|
||||
|
||||
TRACE_RIO("[%ld] I/O: offset: %lld, vecBase: %p, length: %lu\n",
|
||||
find_thread(NULL), offset, vecBase, vecLength);
|
||||
@@ -397,6 +338,7 @@ synchronous_io(io_request* request, DoIO& io)
|
||||
status_t error = io.IO(offset, vecBase, &transferred);
|
||||
if (error != B_OK) {
|
||||
TRACE_RIO("[%ld] I/O failed: %#lx\n", find_thread(NULL), error);
|
||||
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||
request->SetStatusAndNotify(error);
|
||||
return error;
|
||||
}
|
||||
@@ -410,6 +352,7 @@ synchronous_io(io_request* request, DoIO& io)
|
||||
|
||||
TRACE_RIO("[%ld] synchronous_io() succeeded\n", find_thread(NULL));
|
||||
|
||||
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||
request->SetTransferredBytes(length > 0, request->Length() - length);
|
||||
request->SetStatusAndNotify(B_OK);
|
||||
return B_OK;
|
||||
@@ -426,8 +369,7 @@ vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request)
|
||||
if (!HAS_FS_CALL(vnode, io)
|
||||
|| (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) {
|
||||
// no io() call -- fall back to synchronous I/O
|
||||
IOBuffer* buffer = request->Buffer();
|
||||
VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, cookie);
|
||||
VnodeIO io(request->IsWrite(), vnode, cookie);
|
||||
return synchronous_io(request, io);
|
||||
}
|
||||
|
||||
@@ -440,9 +382,7 @@ vfs_synchronous_io(io_request* request,
|
||||
status_t (*doIO)(void* cookie, off_t offset, void* buffer, size_t* length),
|
||||
void* cookie)
|
||||
{
|
||||
IOBuffer* buffer = request->Buffer();
|
||||
CallbackIO io(request->IsWrite(), buffer->IsPhysical(), doIO, cookie);
|
||||
|
||||
CallbackIO io(request->IsWrite(), doIO, cookie);
|
||||
return synchronous_io(request, io);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user