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 {
|
class DoIO {
|
||||||
public:
|
public:
|
||||||
DoIO(bool write, bool isPhysical)
|
DoIO(bool write)
|
||||||
:
|
:
|
||||||
fWrite(write),
|
fWrite(write)
|
||||||
fIsPhysical(isPhysical)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,88 +79,27 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t IO(off_t offset, void* _buffer, size_t* _length)
|
virtual status_t IO(off_t offset, void* buffer, size_t* length) = 0;
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool fWrite;
|
bool fWrite;
|
||||||
bool fIsPhysical;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CallbackIO : public DoIO {
|
class CallbackIO : public DoIO {
|
||||||
public:
|
public:
|
||||||
CallbackIO(bool write, bool isPhysical,
|
CallbackIO(bool write,
|
||||||
status_t (*doIO)(void* cookie, off_t offset, void* buffer,
|
status_t (*doIO)(void* cookie, off_t offset, void* buffer,
|
||||||
size_t* length),
|
size_t* length),
|
||||||
void* cookie)
|
void* cookie)
|
||||||
:
|
:
|
||||||
DoIO(write, isPhysical),
|
DoIO(write),
|
||||||
fDoIO(doIO),
|
fDoIO(doIO),
|
||||||
fCookie(cookie)
|
fCookie(cookie)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
virtual status_t IO(off_t offset, void* buffer, size_t* length)
|
||||||
virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
|
|
||||||
{
|
{
|
||||||
return fDoIO(fCookie, offset, buffer, length);
|
return fDoIO(fCookie, offset, buffer, length);
|
||||||
}
|
}
|
||||||
@@ -174,16 +112,15 @@ private:
|
|||||||
|
|
||||||
class VnodeIO : public DoIO {
|
class VnodeIO : public DoIO {
|
||||||
public:
|
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),
|
fVnode(vnode),
|
||||||
fCookie(cookie)
|
fCookie(cookie)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
virtual status_t IO(off_t offset, void* buffer, size_t* length)
|
||||||
virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
|
|
||||||
{
|
{
|
||||||
iovec vec;
|
iovec vec;
|
||||||
vec.iov_base = buffer;
|
vec.iov_base = buffer;
|
||||||
@@ -324,18 +261,19 @@ do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
|
|||||||
iterative_io_finished finished, void* cookie)
|
iterative_io_finished finished, void* cookie)
|
||||||
{
|
{
|
||||||
IOBuffer* buffer = request->Buffer();
|
IOBuffer* buffer = request->Buffer();
|
||||||
VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, openCookie);
|
VnodeIO io(request->IsWrite(), vnode, openCookie);
|
||||||
|
|
||||||
iovec* vecs = buffer->Vecs();
|
iovec vector;
|
||||||
int32 vecCount = buffer->VecCount();
|
void* virtualVecCookie = NULL;
|
||||||
off_t offset = request->Offset();
|
off_t offset = request->Offset();
|
||||||
size_t length = request->Length();
|
size_t length = request->Length();
|
||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
for (int32 i = 0; error == B_OK && length > 0 && i < vecCount; i++) {
|
for (; error == B_OK && length > 0
|
||||||
uint8* vecBase = (uint8*)vecs[i].iov_base;
|
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
||||||
size_t vecLength = min_c(vecs[i].iov_len, length);
|
uint8* vecBase = (uint8*)vector.iov_base;
|
||||||
|
size_t vecLength = min_c(vector.iov_len, length);
|
||||||
|
|
||||||
while (error == B_OK && vecLength > 0) {
|
while (error == B_OK && vecLength > 0) {
|
||||||
file_io_vec fileVecs[8];
|
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)
|
if (error != B_OK || fileVecCount == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (uint32 k = 0; k < fileVecCount; k++) {
|
for (uint32 i = 0; i < fileVecCount; i++) {
|
||||||
const file_io_vec& fileVec = fileVecs[i];
|
const file_io_vec& fileVec = fileVecs[i];
|
||||||
size_t toTransfer = min_c(fileVec.length, length);
|
size_t toTransfer = min_c(fileVec.length, length);
|
||||||
size_t transferred = toTransfer;
|
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;
|
bool partial = length > 0;
|
||||||
size_t bytesTransferred = request->Length() - length;
|
size_t bytesTransferred = request->Length() - length;
|
||||||
request->SetTransferredBytes(partial, bytesTransferred);
|
request->SetTransferredBytes(partial, bytesTransferred);
|
||||||
@@ -381,14 +321,15 @@ synchronous_io(io_request* request, DoIO& io)
|
|||||||
|
|
||||||
IOBuffer* buffer = request->Buffer();
|
IOBuffer* buffer = request->Buffer();
|
||||||
|
|
||||||
iovec* vecs = buffer->Vecs();
|
iovec vector;
|
||||||
int32 vecCount = buffer->VecCount();
|
void* virtualVecCookie = NULL;
|
||||||
off_t offset = request->Offset();
|
off_t offset = request->Offset();
|
||||||
size_t length = request->Length();
|
size_t length = request->Length();
|
||||||
|
|
||||||
for (int32 i = 0; length > 0 && i < vecCount; i++) {
|
for (; length > 0
|
||||||
void* vecBase = vecs[i].iov_base;
|
&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
|
||||||
size_t vecLength = min_c(vecs[i].iov_len, length);
|
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",
|
TRACE_RIO("[%ld] I/O: offset: %lld, vecBase: %p, length: %lu\n",
|
||||||
find_thread(NULL), offset, vecBase, vecLength);
|
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);
|
status_t error = io.IO(offset, vecBase, &transferred);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
TRACE_RIO("[%ld] I/O failed: %#lx\n", find_thread(NULL), error);
|
TRACE_RIO("[%ld] I/O failed: %#lx\n", find_thread(NULL), error);
|
||||||
|
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||||
request->SetStatusAndNotify(error);
|
request->SetStatusAndNotify(error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -410,6 +352,7 @@ synchronous_io(io_request* request, DoIO& io)
|
|||||||
|
|
||||||
TRACE_RIO("[%ld] synchronous_io() succeeded\n", find_thread(NULL));
|
TRACE_RIO("[%ld] synchronous_io() succeeded\n", find_thread(NULL));
|
||||||
|
|
||||||
|
buffer->FreeVirtualVecCookie(virtualVecCookie);
|
||||||
request->SetTransferredBytes(length > 0, request->Length() - length);
|
request->SetTransferredBytes(length > 0, request->Length() - length);
|
||||||
request->SetStatusAndNotify(B_OK);
|
request->SetStatusAndNotify(B_OK);
|
||||||
return 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)
|
if (!HAS_FS_CALL(vnode, io)
|
||||||
|| (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) {
|
|| (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) {
|
||||||
// no io() call -- fall back to synchronous I/O
|
// no io() call -- fall back to synchronous I/O
|
||||||
IOBuffer* buffer = request->Buffer();
|
VnodeIO io(request->IsWrite(), vnode, cookie);
|
||||||
VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, cookie);
|
|
||||||
return synchronous_io(request, io);
|
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),
|
status_t (*doIO)(void* cookie, off_t offset, void* buffer, size_t* length),
|
||||||
void* cookie)
|
void* cookie)
|
||||||
{
|
{
|
||||||
IOBuffer* buffer = request->Buffer();
|
CallbackIO io(request->IsWrite(), doIO, cookie);
|
||||||
CallbackIO io(request->IsWrite(), buffer->IsPhysical(), doIO, cookie);
|
|
||||||
|
|
||||||
return synchronous_io(request, io);
|
return synchronous_io(request, io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user