diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/IORequestInfo.h b/src/add-ons/kernel/file_systems/userlandfs/server/IORequestInfo.h new file mode 100644 index 0000000000..588c162f7d --- /dev/null +++ b/src/add-ons/kernel/file_systems/userlandfs/server/IORequestInfo.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef USERLAND_FS_IO_REQUEST_INFO_H +#define USERLAND_FS_IO_REQUEST_INFO_H + +#include + + +namespace UserlandFS { + +struct IORequestInfo : HashTableLink { + int32 id; + bool isWrite; + + IORequestInfo(int32 id, bool isWrite) + : + id(id), + isWrite(isWrite) + { + } +}; + +} // namespace UserlandFS + + +using UserlandFS::IORequestInfo; + + +#endif // USERLAND_FS_IO_REQUEST_INFO_H diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp index dfb6068f5e..1128c86f76 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp @@ -6,6 +6,7 @@ #include "Compatibility.h" #include "Debug.h" #include "FileSystem.h" +#include "IORequestInfo.h" #include "RequestPort.h" #include "Requests.h" #include "RequestThread.h" @@ -69,6 +70,12 @@ UserlandRequestHandler::HandleRequest(Request* request) case FS_REMOVE_VNODE_REQUEST: return _HandleRequest((FSRemoveVNodeRequest*)request); + // asynchronous I/O + case DO_IO_REQUEST: + return _HandleRequest((DoIORequest*)request); + case CANCEL_IO_REQUEST: + return _HandleRequest((CancelIORequest*)request); + // nodes case IOCTL_REQUEST: return _HandleRequest((IOCtlRequest*)request); @@ -531,6 +538,67 @@ UserlandRequestHandler::_HandleRequest(FSRemoveVNodeRequest* request) } +// #pragma mark - asynchronous I/O + + +status_t +UserlandRequestHandler::_HandleRequest(DoIORequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + if (result == B_OK) { + RequestThreadContext context(volume); + IORequestInfo requestInfo(request->ioRequest, request->isWrite); + result = volume->DoIO(request->node, request->fileCookie, &requestInfo); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + DoIOReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + + // send the reply + return _SendReply(allocator, false); +} + + +status_t +UserlandRequestHandler::_HandleRequest(CancelIORequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + if (result == B_OK) { + RequestThreadContext context(volume); + result = volume->CancelIO(request->node, request->fileCookie, + request->ioRequest); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + CancelIOReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + + // send the reply + return _SendReply(allocator, false); +} + + // #pragma mark - nodes diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h index bc0675f16f..4d320531f2 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h @@ -19,6 +19,9 @@ class GetVNodeNameRequest; class ReadVNodeRequest; class WriteVNodeRequest; class FSRemoveVNodeRequest; +// asynchronous I/O +class DoIORequest; +class CancelIORequest; // nodes class IOCtlRequest; class SetFlagsRequest; @@ -115,6 +118,10 @@ private: status_t _HandleRequest(WriteVNodeRequest* request); status_t _HandleRequest(FSRemoveVNodeRequest* request); + // asynchronous I/O + status_t _HandleRequest(DoIORequest* request); + status_t _HandleRequest(CancelIORequest* request); + // nodes status_t _HandleRequest(IOCtlRequest* request); status_t _HandleRequest(SetFlagsRequest* request); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp index 9b351d11af..0c031cb991 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp @@ -189,6 +189,23 @@ Volume::RemoveVNode(void* node, bool reenter) } +// #pragma mark - asynchronous I/O + + +status_t +Volume::DoIO(void* node, void* cookie, IORequestInfo* requestInfo) +{ + return B_BAD_VALUE; +} + + +status_t +Volume::CancelIO(void* node, void* cookie, int32 ioRequestID) +{ + return B_BAD_VALUE; +} + + // #pragma mark - nodes diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h index 7c18a9227c..c652ca2267 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h @@ -14,6 +14,7 @@ namespace UserlandFS { class FileSystem; +class IORequestInfo; using UserlandFSUtil::FSVolumeCapabilities; @@ -52,6 +53,12 @@ public: virtual status_t WriteVNode(void* node, bool reenter); virtual status_t RemoveVNode(void* node, bool reenter); + // asynchronous I/O + virtual status_t DoIO(void* node, void* cookie, + IORequestInfo* requestInfo); + virtual status_t CancelIO(void* node, void* cookie, + int32 ioRequestID); + // nodes virtual status_t IOCtl(void* node, void* cookie, uint32 command, void* buffer, size_t size); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp index 5c6cc1b5bd..29ccbf8a35 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp @@ -12,6 +12,7 @@ #include "Debug.h" #include "HashMap.h" +#include "../IORequestInfo.h" #include "../kernel_emu.h" #include "HaikuKernelNode.h" @@ -23,13 +24,36 @@ class HaikuKernelVolume::NodeMap }; +// IORequestHashDefinition +struct HaikuKernelVolume::IORequestHashDefinition { + typedef int32 KeyType; + typedef IORequestInfo ValueType; + + size_t HashKey(int32 key) const + { return key; } + size_t Hash(const IORequestInfo* value) const + { return value->id; } + bool Compare(int32 key, const IORequestInfo* value) const + { return value->id == key; } + HashTableLink* GetLink(IORequestInfo* value) const + { return value; } +}; + + +// IORequestTable +struct HaikuKernelVolume::IORequestTable + : public OpenHashTable { +}; + + // constructor HaikuKernelVolume::HaikuKernelVolume(FileSystem* fileSystem, dev_t id, file_system_module_info* fsModule) : Volume(fileSystem, id), fFSModule(fsModule), - fNodes(NULL) + fNodes(NULL), + fIORequests(NULL) { fVolume.id = id; fVolume.partition = -1; @@ -46,6 +70,8 @@ HaikuKernelVolume::HaikuKernelVolume(FileSystem* fileSystem, dev_t id, // destructor HaikuKernelVolume::~HaikuKernelVolume() { + delete fNodes; + delete fIORequests; } @@ -56,8 +82,14 @@ HaikuKernelVolume::Init() fNodes = new(std::nothrow) NodeMap; if (fNodes == NULL) return B_NO_MEMORY; + status_t error = fNodes->InitCheck(); + if (error != B_OK) + return error; - return fNodes->InitCheck(); + fIORequests = new(std::nothrow) IORequestTable; + if (fIORequests == NULL) + return B_NO_MEMORY; + return fIORequests->Init(); } @@ -152,6 +184,14 @@ HaikuKernelVolume::NodeWithID(ino_t vnodeID) const } +IORequestInfo* +HaikuKernelVolume::IORequestInfoWithID(int32 id) const +{ + AutoLocker locker(fNodes); + return fIORequests->Lookup(id); +} + + // #pragma mark - // #pragma mark ----- FS ----- @@ -330,6 +370,50 @@ HaikuKernelVolume::RemoveVNode(void* _node, bool reenter) } +// #pragma mark - asynchronous I/O + + +status_t +HaikuKernelVolume::DoIO(void* _node, void* cookie, IORequestInfo* requestInfo) +{ + HaikuKernelNode* node = (HaikuKernelNode*)_node; + + if (!node->ops->io) + return B_BAD_VALUE; + + // add the info to the table + AutoLocker locker(fNodes); + if (fIORequests->Lookup(requestInfo->id)) + RETURN_ERROR(B_BAD_VALUE); + + fIORequests->Insert(requestInfo); + locker.Unlock(); + + // call the hook + status_t error = node->ops->io(&fVolume, node, cookie, + (io_request*)(addr_t)requestInfo->id); + + // remove the info from the table + locker.Lock(); + fIORequests->Remove(requestInfo); + + return error; +} + + +status_t +HaikuKernelVolume::CancelIO(void* _node, void* cookie, int32 ioRequestID) +{ + HaikuKernelNode* node = (HaikuKernelNode*)_node; + + if (!node->ops->cancel_io) + return B_BAD_VALUE; + + return node->ops->cancel_io(&fVolume, node, cookie, + (io_request*)(addr_t)ioRequestID); +} + + // #pragma mark - nodes diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h index 149301a474..ad2f1bbc5a 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h @@ -34,6 +34,7 @@ public: void UndoPublishVNode(HaikuKernelNode* node); HaikuKernelNode* NodeWithID(ino_t vnodeID) const; + IORequestInfo* IORequestInfoWithID(int32 id) const; // FS virtual status_t Mount(const char* device, uint32 flags, @@ -59,6 +60,12 @@ public: virtual status_t WriteVNode(void* node, bool reenter); virtual status_t RemoveVNode(void* node, bool reenter); + // asynchronous I/O + virtual status_t DoIO(void* node, void* cookie, + IORequestInfo* requestInfo); + virtual status_t CancelIO(void* node, void* cookie, + int32 ioRequestID); + // nodes virtual status_t IOCtl(void* node, void* cookie, uint32 command, void* buffer, size_t size); @@ -178,6 +185,8 @@ private: }; class NodeMap; + class IORequestHashDefinition; + class IORequestTable; private: void _InitCapabilities(); @@ -186,6 +195,7 @@ private: file_system_module_info* fFSModule; FSVolume fVolume; NodeMap* fNodes; + IORequestTable* fIORequests; }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp index 6d6f030dcf..fb0be0c57c 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp @@ -17,7 +17,9 @@ #include "Debug.h" #include "../FileSystem.h" +#include "../IORequestInfo.h" #include "../kernel_emu.h" +#include "../RequestThread.h" #include "HaikuKernelNode.h" #include "HaikuKernelVolume.h" @@ -282,8 +284,19 @@ do_iterative_fd_io(int fd, io_request *request, iterative_io_get_vecs getVecs, bool io_request_is_write(const io_request* request) { - // TODO: Implement! - return false; + // get the volume + RequestThread* thread = RequestThread::GetCurrentThread(); + if (thread == NULL || thread->GetContext() == NULL) + return false; + + HaikuKernelVolume* volume = dynamic_cast( + thread->GetContext()->GetVolume()); + if (volume == NULL) + return false; + + // get the request info + IORequestInfo* info = volume->IORequestInfoWithID((int32)(addr_t)request); + return info != NULL && info->isWrite; }