* Forward the io() and cancel_io() hooks. Implemented the missing kernel

part.
* Implemented a good part of the kernel part for the support of
  do_iterative_fd_io(). The forwarding of the callbacks are missing yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29540 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-03-15 02:49:05 +00:00
parent fa1b5a713c
commit 687e02f945
11 changed files with 548 additions and 60 deletions
@@ -1753,6 +1753,7 @@ public:
DoIterativeFDIORequest() : Request(DO_ITERATIVE_FD_IO_REQUEST) {}
status_t GetAddressInfos(AddressInfo* infos, int32* count);
dev_t nsid;
int fd;
int32 request;
void* cookie;
@@ -100,6 +100,9 @@ KernelRequestHandler::HandleRequest(Request* request)
return _HandleRequest((FileCacheReadRequest*)request);
case FILE_CACHE_WRITE_REQUEST:
return _HandleRequest((FileCacheWriteRequest*)request);
// I/O
case DO_ITERATIVE_FD_IO_REQUEST:
return _HandleRequest((DoIterativeFDIORequest*)request);
}
PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
request->GetType()));
@@ -704,6 +707,40 @@ KernelRequestHandler::_HandleRequest(FileCacheWriteRequest* request)
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(DoIterativeFDIORequest* request)
{
// check and execute the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
const file_io_vec* vecs = (const file_io_vec*)request->vecs.GetData();
size_t vecsSize = request->vecs.GetSize();
uint32 vecCount = request->vecCount;
if (result == B_OK && vecsSize / sizeof(file_io_vec) < vecCount)
result = B_BAD_VALUE;
if (result == B_OK) {
result = volume->DoIterativeFDIO(request->fd, request->request,
request->cookie, vecs, vecCount);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
DoIterativeFDIOReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _GetVolume
status_t
KernelRequestHandler::_GetVolume(dev_t id, Volume** volume)
@@ -73,6 +73,8 @@ private:
status_t _HandleRequest(FileCacheSyncRequest* request);
status_t _HandleRequest(FileCacheReadRequest* request);
status_t _HandleRequest(FileCacheWriteRequest* request);
// I/O
status_t _HandleRequest(DoIterativeFDIORequest* request);
status_t _GetVolume(dev_t id, Volume** volume);
@@ -15,6 +15,8 @@
#include <util/AutoLock.h>
#include <util/OpenHashTable.h>
#include <fs/fd.h> // kernel private
#include "Compatibility.h"
#include "Debug.h"
#include "FileSystem.h"
@@ -75,7 +77,7 @@ struct Volume::VNodeHashDefinition {
{ return (uint32)key ^ (uint32)(key >> 32); }
size_t Hash(const VNode* value) const
{ return HashKey(value->id); }
bool Compare(ino_t key, VNode* value) const
bool Compare(ino_t key, const VNode* value) const
{ return value->id == key; }
HashTableLink<VNode>* GetLink(VNode* value) const
{ return value; }
@@ -88,6 +90,90 @@ struct Volume::VNodeMap
};
// IORequestInfo
struct Volume::IORequestInfo {
io_request* request;
int32 id;
HashTableLink<IORequestInfo> idLink;
HashTableLink<IORequestInfo> structLink;
IORequestInfo(io_request* request, int32 id)
:
request(request),
id(id)
{
}
};
// IORequestIDHashDefinition
struct Volume::IORequestIDHashDefinition {
typedef int32 KeyType;
typedef IORequestInfo ValueType;
size_t HashKey(int32 key) const
{ return key; }
size_t Hash(const IORequestInfo* value) const
{ return HashKey(value->id); }
bool Compare(int32 key, const IORequestInfo* value) const
{ return value->id == key; }
HashTableLink<IORequestInfo>* GetLink(IORequestInfo* value) const
{ return &value->idLink; }
};
// IORequestStructHashDefinition
struct Volume::IORequestStructHashDefinition {
typedef io_request* KeyType;
typedef IORequestInfo ValueType;
size_t HashKey(io_request* key) const
{ return (size_t)(addr_t)key; }
size_t Hash(const IORequestInfo* value) const
{ return HashKey(value->request); }
bool Compare(io_request* key, const IORequestInfo* value) const
{ return value->request == key; }
HashTableLink<IORequestInfo>* GetLink(IORequestInfo* value) const
{ return &value->structLink; }
};
// IORequestIDMap
struct Volume::IORequestIDMap
: public OpenHashTable<IORequestIDHashDefinition> {
};
// IORequestStructMap
struct Volume::IORequestStructMap
: public OpenHashTable<IORequestStructHashDefinition> {
};
// IterativeFDIOCookie
struct Volume::IterativeFDIOCookie : public Referenceable {
Volume* volume;
int fd;
int32 requestID;
void* clientCookie;
const file_io_vec* vecs;
uint32 vecCount;
IterativeFDIOCookie(Volume* volume, int fd, int32 requestID,
void* clientCookie, const file_io_vec* vecs, uint32 vecCount)
:
volume(volume),
fd(fd),
requestID(requestID),
clientCookie(clientCookie),
vecs(vecs),
vecCount(vecCount)
{
}
};
// AutoIncrementer
class Volume::AutoIncrementer {
public:
@@ -113,34 +199,70 @@ private:
vint32* fVariable;
};
// IORequestRemover
class Volume::IORequestRemover {
public:
IORequestRemover(Volume* volume, int32 requestID)
:
fVolume(volume),
fRequestID(requestID)
{
}
~IORequestRemover()
{
if (fVolume != NULL)
fVolume->_UnregisterIORequest(fRequestID);
}
void Detach()
{
fVolume = NULL;
}
private:
Volume* fVolume;
int32 fRequestID;
};
// constructor
Volume::Volume(FileSystem* fileSystem, fs_volume* fsVolume)
: Referenceable(true),
fFileSystem(fileSystem),
fFSVolume(fsVolume),
fUserlandVolume(NULL),
fRootID(0),
fRootNode(NULL),
fOpenFiles(0),
fOpenDirectories(0),
fOpenAttributeDirectories(0),
fOpenAttributes(0),
fOpenIndexDirectories(0),
fOpenQueries(0),
fVNodes(NULL),
fVNodeCountingEnabled(false)
:
Referenceable(true),
fFileSystem(fileSystem),
fFSVolume(fsVolume),
fUserlandVolume(NULL),
fRootID(0),
fRootNode(NULL),
fOpenFiles(0),
fOpenDirectories(0),
fOpenAttributeDirectories(0),
fOpenAttributes(0),
fOpenIndexDirectories(0),
fOpenQueries(0),
fVNodes(NULL),
fIORequestInfosByID(NULL),
fIORequestInfosByStruct(NULL),
fLastIORequestID(0),
fVNodeCountingEnabled(false)
{
mutex_init(&fLock, "userlandfs volume");
}
// destructor
Volume::~Volume()
{
mutex_destroy(&fLock);
delete fIORequestInfosByID;
delete fIORequestInfosByStruct;
delete fVNodes;
}
// GetFileSystem
FileSystem*
Volume::GetFileSystem() const
@@ -481,6 +603,48 @@ Volume::WriteFileCache(ino_t vnodeID, void* cookie,
}
// DoIterativeFDIO
status_t
Volume::DoIterativeFDIO(int fd, int32 requestID, void* clientCookie,
const file_io_vec* vecs, uint32 vecCount)
{
// get the request
io_request* request;
status_t error = _FindIORequest(requestID, &request);
if (error != B_OK)
RETURN_ERROR(error);
// copy the FD into the kernel
fd = dup_foreign_fd(fFileSystem->GetTeam(), fd, true);
if (fd < 0)
RETURN_ERROR(fd);
// create a cookie
IterativeFDIOCookie* cookie = new(std::nothrow) IterativeFDIOCookie(
this, fd, requestID, clientCookie, vecs, vecCount);
if (cookie == NULL) {
close(fd);
RETURN_ERROR(B_NO_MEMORY);
}
// we need another reference, so we can still access the cookie below
cookie->AddReference();
// call the kernel function
error = do_iterative_fd_io(fd, request, &_IterativeFDIOGetVecs,
&_IterativeFDIOFinished, cookie);
// unset the vecs -- they are on the stack an will become invalid when we
// return
MutexLocker _(fLock);
cookie->vecs = NULL;
cookie->vecCount = 0;
cookie->RemoveReference();
return error;
}
// #pragma mark - FS
@@ -488,20 +652,27 @@ Volume::WriteFileCache(ino_t vnodeID, void* cookie,
status_t
Volume::Mount(const char* device, uint32 flags, const char* parameters)
{
// create the vnode map
// create the maps
fVNodes = new(std::nothrow) VNodeMap;
if (fVNodes == NULL)
return B_NO_MEMORY;
fIORequestInfosByID = new(std::nothrow) IORequestIDMap;
fIORequestInfosByStruct = new(std::nothrow) IORequestStructMap;
status_t error = fVNodes->Init();
if (error != B_OK)
return error;
if (fVNodes == NULL || fIORequestInfosByID == NULL
|| fIORequestInfosByStruct == NULL
|| fVNodes->Init() != B_OK
|| fIORequestInfosByID->Init() != B_OK
|| fIORequestInfosByStruct->Init() != B_OK) {
return B_NO_MEMORY;
}
// enable vnode counting
fVNodeCountingEnabled = true;
// init IORequest ID's
fLastIORequestID = 0;
// mount
error = _Mount(device, flags, parameters);
status_t error = _Mount(device, flags, parameters);
if (error == B_OK) {
MutexLocker locker(fLock);
@@ -533,17 +704,38 @@ Volume::Unmount()
{
status_t error = _Unmount();
// free the memory associated with the vnode map
if (fVNodes != NULL) {
// free the memory associated with the maps
{
// vnodes
MutexLocker _(fLock);
VNode* node = fVNodes->Clear();
while (node != NULL) {
VNode* nextNode = node->fNext;
delete node;
node = nextNode;
if (fVNodes != NULL) {
VNode* node = fVNodes->Clear(true);
while (node != NULL) {
VNode* nextNode = node->fNext;
delete node;
node = nextNode;
}
delete fVNodes;
fVNodes = NULL;
}
// io request infos
if (fIORequestInfosByID != NULL) {
fIORequestInfosByID->Clear();
delete fIORequestInfosByID;
fIORequestInfosByID = NULL;
}
if (fIORequestInfosByStruct != NULL) {
IORequestInfo* info = fIORequestInfosByStruct->Clear(true);
while (info != NULL) {
IORequestInfo* nextInfo = info->structLink.fNext;
delete info;
info = nextInfo;
}
delete fIORequestInfosByStruct;
fIORequestInfosByStruct = NULL;
}
delete fVNodes;
fVNodes = NULL;
}
fFileSystem->VolumeUnmounted(this);
@@ -837,6 +1029,119 @@ Volume::RemoveVNode(void* _node, bool reenter)
}
// #pragma mark - asynchronous I/O
// DoIO
status_t
Volume::DoIO(void* _node, void* cookie, io_request* ioRequest)
{
VNode* vnode = (VNode*)_node;
// check capability
if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IO))
return B_BAD_VALUE;
// register the IO request
int32 requestID;
status_t error = _RegisterIORequest(ioRequest, &requestID);
if (error != B_OK)
return error;
IORequestRemover requestRemover(this, requestID);
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
// prepare the request
RequestAllocator allocator(port->GetPort());
DoIORequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = vnode->clientNode;
request->fileCookie = cookie;
request->request = requestID;
// send the request
KernelRequestHandler handler(this, DO_IO_REPLY);
DoIOReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
requestRemover.Detach();
return B_OK;
}
// CancelIO
status_t
Volume::CancelIO(void* _node, void* cookie, io_request* ioRequest)
{
VNode* vnode = (VNode*)_node;
// check capability
if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CANCEL_IO))
return B_BAD_VALUE;
// find the request
int32 requestID;
status_t error = _FindIORequest(ioRequest, &requestID);
if (error != B_OK)
return error;
IORequestRemover requestRemover(this, requestID);
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
// prepare the request
RequestAllocator allocator(port->GetPort());
CancelIORequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = vnode->clientNode;
request->fileCookie = cookie;
request->request = requestID;
// send the request
KernelRequestHandler handler(this, CANCEL_IO_REPLY);
CancelIOReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK) {
_UnregisterIORequest(requestID);
return error;
}
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK) {
_UnregisterIORequest(requestID);
return reply->error;
}
return B_OK;
}
// #pragma mark - nodes
@@ -4026,3 +4331,93 @@ PRINT(("Volume::_PutAllPendingVNodes()\n"));
return B_OK;
}
// _RegisterIORequest
status_t
Volume::_RegisterIORequest(io_request* request, int32* requestID)
{
MutexLocker _(fLock);
// get the next free ID
while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) {
}
// allocate the info
IORequestInfo* info = new(std::nothrow) IORequestInfo(request,
++fLastIORequestID);
if (info == NULL)
return B_NO_MEMORY;
// add the info to the maps
fIORequestInfosByID->Insert(info);
fIORequestInfosByStruct->Insert(info);
*requestID = info->id;
return B_OK;
}
// _UnregisterIORequest
status_t
Volume::_UnregisterIORequest(int32 requestID)
{
MutexLocker _(fLock);
if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
fIORequestInfosByID->Remove(info);
fIORequestInfosByStruct->Remove(info);
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
// _FindIORequest
status_t
Volume::_FindIORequest(int32 requestID, io_request** request)
{
MutexLocker _(fLock);
if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
*request = info->request;
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
// _FindIORequest
status_t
Volume::_FindIORequest(io_request* request, int32* requestID)
{
MutexLocker _(fLock);
if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) {
*requestID = info->id;
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
/*static*/ status_t
Volume::_IterativeFDIOGetVecs(void* cookie, io_request* request, off_t offset,
size_t size, struct file_io_vec* vecs, size_t* _count)
{
// TODO: Implement!
return B_UNSUPPORTED;
}
/*static*/ status_t
Volume::_IterativeFDIOFinished(void* cookie, io_request* request,
status_t status, bool partialTransfer, size_t bytesTransferred)
{
// TODO: Implement!
return B_UNSUPPORTED;
}
@@ -69,6 +69,10 @@ public:
off_t offset, const void* buffer,
size_t* _size);
status_t DoIterativeFDIO(int fd, int32 requestID,
void* cookie, const file_io_vec* vecs,
uint32 vecCount);
// FS
status_t Mount(const char* device, uint32 flags,
const char* parameters);
@@ -88,6 +92,12 @@ public:
status_t WriteVNode(void* node, bool reenter);
status_t RemoveVNode(void* node, bool reenter);
// asynchronous I/O
status_t DoIO(void* node, void* cookie,
io_request* ioRequest);
status_t CancelIO(void* node, void* cookie,
io_request* ioRequest);
// nodes
status_t IOCtl(void* node, void* cookie,
uint32 command, void *buffer, size_t size);
@@ -205,8 +215,16 @@ private:
struct VNode;
struct VNodeHashDefinition;
struct VNodeMap;
struct IORequestInfo;
struct IORequestIDHashDefinition;
struct IORequestStructHashDefinition;
struct IORequestIDMap;
struct IORequestStructMap;
struct IterativeFDIOCookie;
class AutoIncrementer;
class IORequestRemover;
friend class IORequestRemover;
private:
status_t _Mount(const char* device, uint32 flags,
@@ -245,6 +263,23 @@ private:
status_t _PutAllPendingVNodes();
status_t _RegisterIORequest(io_request* request,
int32* requestID);
status_t _UnregisterIORequest(int32 requestID);
status_t _FindIORequest(io_request* request,
int32* requestID);
status_t _FindIORequest(int32 requestID,
io_request** request);
static status_t _IterativeFDIOGetVecs(void* cookie,
io_request* request, off_t offset,
size_t size, struct file_io_vec* vecs,
size_t* _count);
static status_t _IterativeFDIOFinished(void* cookie,
io_request* request, status_t status,
bool partialTransfer,
size_t bytesTransferred);
inline bool HasVNodeCapability(VNode* vnode,
int capability) const;
@@ -263,6 +298,9 @@ private:
vint32 fOpenIndexDirectories;
vint32 fOpenQueries;
VNodeMap* fVNodes;
IORequestIDMap* fIORequestInfosByID;
IORequestStructMap* fIORequestInfosByStruct;
int32 fLastIORequestID;
volatile bool fVNodeCountingEnabled;
};
@@ -248,25 +248,35 @@ userlandfs_remove_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
}
// #pragma mark - VM file access
// TODO: userlandfs_can_page()
// TODO: userlandfs_read_pages()
// TODO: userlandfs_write_pages()
// #pragma mark - asynchronous I/O
// TODO: userlandfs_io()
// TODO: userlandfs_cancel_io()
// userlandfs_io
status_t
userlandfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
io_request* request)
{
Volume* volume = (Volume*)fsVolume->private_volume;
PRINT(("userlandfs_io(%p, %p, %p, %p)\n", volume, fsNode->private_node,
cookie, request));
status_t error = volume->DoIO(fsNode->private_node, cookie, request);
PRINT(("userlandfs_io() done: (%lx)\n", error));
return error;
}
// #pragma mark - cache file access
// TODO: userlandfs_get_file_map()
// userlandfs_cancel_io
status_t
userlandfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void *cookie,
io_request *request)
{
Volume* volume = (Volume*)fsVolume->private_volume;
PRINT(("userlandfs_cancel_io(%p, %p, %p, %p)\n", volume,
fsNode->private_node, cookie, request));
status_t error = volume->CancelIO(fsNode->private_node, cookie, request);
PRINT(("userlandfs_cancel_io() done: (%lx)\n", error));
return error;
}
// #pragma mark - common
@@ -1169,16 +1179,16 @@ fs_vnode_ops gUserlandFSVnodeOps = {
&userlandfs_remove_vnode,
// VM file access
NULL, // &userlandfs_can_page,
NULL, // &userlandfs_read_pages,
NULL, // &userlandfs_write_pages,
NULL, // can_page() -- obsolete
NULL, // read_pages() -- obsolete
NULL, // write_pages() -- obsolete
// asynchronous I/O
NULL, // &userlandfs_io
NULL, // &userlandfs_cancel_io
&userlandfs_io,
&userlandfs_cancel_io,
// cache file access
NULL, // &userlandfs_get_file_map
NULL, // get_file_map() -- not needed
// common operations
&userlandfs_ioctl,
@@ -14,14 +14,18 @@
namespace UserlandFS {
class HaikuKernelVolume;
struct HaikuKernelIORequest : HashTableLink<HaikuKernelIORequest>,
IORequestInfo {
int32 refCount;
HaikuKernelVolume* volume;
int32 refCount;
HaikuKernelIORequest(const IORequestInfo& info)
HaikuKernelIORequest(HaikuKernelVolume* volume, const IORequestInfo& info)
:
IORequestInfo(info),
volume(volume),
refCount(1)
{
}
@@ -355,7 +355,7 @@ HaikuKernelVolume::DoIO(void* _node, void* cookie,
// create a request object
HaikuKernelIORequest* request
= new(std::nothrow) HaikuKernelIORequest(requestInfo);
= new(std::nothrow) HaikuKernelIORequest(this, requestInfo);
if (request == NULL)
RETURN_ERROR(B_NO_MEMORY);
@@ -296,8 +296,8 @@ do_iterative_fd_io(int fd, io_request *_request, iterative_io_get_vecs getVecs,
}
// send the request
status_t error = UserlandFS::KernelEmu::do_iterative_fd_io(fd, request->id,
cookie, NULL, 0);
status_t error = UserlandFS::KernelEmu::do_iterative_fd_io(
request->volume->GetID(), fd, request->id, cookie, NULL, 0);
if (error != B_OK) {
delete cookie;
return error;
@@ -841,8 +841,8 @@ UserlandFS::KernelEmu::file_cache_write(dev_t mountID, ino_t vnodeID,
status_t
UserlandFS::KernelEmu::do_iterative_fd_io(int fd, int32 requestID, void* cookie,
const file_io_vec* vecs, uint32 vecCount)
UserlandFS::KernelEmu::do_iterative_fd_io(dev_t volumeID, int fd,
int32 requestID, void* cookie, const file_io_vec* vecs, uint32 vecCount)
{
// get the request port and the file system
RequestPort* port;
@@ -858,6 +858,7 @@ UserlandFS::KernelEmu::do_iterative_fd_io(int fd, int32 requestID, void* cookie,
if (error != B_OK)
return error;
request->nsid = volumeID;
request->fd = fd;
request->request = requestID;
request->cookie = cookie;
@@ -43,8 +43,8 @@ status_t file_cache_read(dev_t mountID, ino_t vnodeID, void *cookie,
status_t file_cache_write(dev_t mountID, ino_t vnodeID, void *cookie,
off_t offset, const void *buffer, size_t *_size);
status_t do_iterative_fd_io(int fd, int32 requestID, void* cookie,
const file_io_vec* vecs, uint32 vecCount);
status_t do_iterative_fd_io(dev_t volumeID, int fd, int32 requestID,
void* cookie, const file_io_vec* vecs, uint32 vecCount);
void kernel_debugger(const char *message);
void vpanic(const char *format, va_list args);