diff --git a/headers/private/userlandfs/private/DispatcherDefs.h b/headers/private/userlandfs/private/DispatcherDefs.h index 1694462ad8..1d56a4279a 100644 --- a/headers/private/userlandfs/private/DispatcherDefs.h +++ b/headers/private/userlandfs/private/DispatcherDefs.h @@ -3,15 +3,27 @@ #ifndef USERLAND_FS_DISPATCHER_DEFS_H #define USERLAND_FS_DISPATCHER_DEFS_H +#include "FSCapabilities.h" +#include "Port.h" + + namespace UserlandFSUtil { extern const char* kUserlandFSDispatcherPortName; extern const char* kUserlandFSDispatcherReplyPortName; +struct fs_init_info { + FSCapabilities capabilities; + client_fs_type clientFSType; + int32 portInfoCount; + Port::Info portInfos[0]; +}; + } // namespace UserlandFSUtil using UserlandFSUtil::kUserlandFSDispatcherPortName; using UserlandFSUtil::kUserlandFSDispatcherReplyPortName; +using UserlandFSUtil::fs_init_info; enum { UFS_DISPATCHER_CONNECT = 'cnct', diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp index 387010ce72..fafb38284f 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp @@ -1,76 +1,136 @@ -// FileSystemInitializer.cpp +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #include "FileSystemInitializer.h" #include +#include +#include + +#include +#include + +#include "AutoDeleter.h" + +#include "DispatcherDefs.h" #include "FileSystem.h" #include "RequestAllocator.h" #include "RequestPort.h" #include "Requests.h" #include "SingleReplyRequestHandler.h" -using std::nothrow; // constructor -FileSystemInitializer::FileSystemInitializer(const char* name, - RequestPort* initPort) - : fName(name), - fInitPort(initPort), - fFileSystem(NULL) +FileSystemInitializer::FileSystemInitializer(const char* name) + : + fName(name), + fFileSystem(NULL) { // Note: We don't copy the name. It's only needed in FirstTimeInit() and // the UserlandFS makes sure it is valid until then. } + // destructor FileSystemInitializer::~FileSystemInitializer() { delete fFileSystem; } + // FirstTimeInit status_t FileSystemInitializer::FirstTimeInit() { - // prepare the request - RequestAllocator allocator(fInitPort->GetPort()); - FSConnectRequest* request; - status_t error = AllocateRequest(allocator, &request); - if (error != B_OK) + // First check whether a server for this FS is already loaded. Look for a + // port with the respective name. + char portName[B_OS_NAME_LENGTH]; + snprintf(portName, sizeof(portName), "_userlandfs_%s", fName); + + port_id port = find_port(portName); + if (port >= 0) + return _Init(port); + + // We have to start the server ourselves. First create the port we're going + // to use. + port = create_port(1, portName); + if (port < 0) + RETURN_ERROR(port); + + // prepare the command line arguments + char portID[16]; + snprintf(portID, sizeof(portID), "%ld", port); + + const char* args[4] = { + "/system/servers/userlandfs_server", + fName, + portID, + NULL + }; + + // start the server + thread_id thread = load_image_etc(3, args, NULL, B_NORMAL_PRIORITY, + B_SYSTEM_TEAM, 0); + if (thread < 0) { + delete_port(port); + RETURN_ERROR(thread); + } + + // let it own the port and start the team + status_t error = set_port_owner(port, thread); + if (error == B_OK) + resume_thread(thread); + + // and do the initialization + if (error == B_OK) + error = _Init(port); + + if (error != B_OK) { + kill_team(thread); + delete_port(port); + RETURN_ERROR(error); + } + + return B_OK; +} + + +status_t +FileSystemInitializer::_Init(port_id port) +{ + // allocate a buffer for the FS info + const size_t bufferSize = 1024; + fs_init_info* info = (fs_init_info*)malloc(bufferSize); + MemoryDeleter _(info); + + // Read the info -- we peek only, so it won't go away and we can do the + // initialization again, in case we get completely unloaded are reloaded + // later. + ssize_t bytesRead = read_port_etc(port, NULL, info, bufferSize, + B_PEEK_PORT_MESSAGE | B_CAN_INTERRUPT, 0); + if (bytesRead < 0) + RETURN_ERROR(bytesRead); + + // sanity check + if ((size_t)bytesRead < sizeof(fs_init_info) + || info->portInfoCount < 2 + || (size_t)bytesRead < sizeof(fs_init_info) + + info->portInfoCount * sizeof(Port::Info)) { + RETURN_ERROR(B_BAD_DATA); + } + + // create and init the FileSystem + fFileSystem = new(std::nothrow) FileSystem; + if (!fFileSystem) + return B_NO_MEMORY; + + status_t error = fFileSystem->Init(fName, info->portInfos, + info->portInfoCount, info->capabilities); + if (error != B_OK) RETURN_ERROR(error); - error = allocator.AllocateString(request->fsName, fName); - if (error != B_OK) - RETURN_ERROR(error); - - // send the request - SingleReplyRequestHandler handler(FS_CONNECT_REPLY); - FSConnectReply* reply; - error = fInitPort->SendRequest(&allocator, &handler, (Request**)&reply); - if (error != B_OK) - RETURN_ERROR(error); - RequestReleaser requestReleaser(fInitPort, reply); - - // process the reply - if (reply->error != B_OK) - RETURN_ERROR(reply->error); - - // get the port infos - int32 count = reply->portInfoCount; - if (count < 2) - RETURN_ERROR(B_BAD_DATA); - if (reply->portInfos.GetSize() != count * (int32)sizeof(Port::Info)) - RETURN_ERROR(B_BAD_DATA); - Port::Info* infos = (Port::Info*)reply->portInfos.GetData(); - - // create and init the FileSystem - fFileSystem = new(nothrow) FileSystem(); - if (!fFileSystem) - return B_NO_MEMORY; - - error = fFileSystem->Init(fName, infos, count, reply->capabilities); - if (error != B_OK) - return B_ERROR; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h index 9a177ca7da..73a108743f 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h @@ -1,5 +1,7 @@ -// FileSystemInitializer.h - +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #ifndef USERLAND_FS_FILE_SYSTEM_INITIALIZER_H #define USERLAND_FS_FILE_SYSTEM_INITIALIZER_H @@ -19,8 +21,7 @@ class FileSystem; class FileSystemInitializer : public LazyInitializable, public Referencable { public: - FileSystemInitializer(const char* name, - RequestPort* initPort); + FileSystemInitializer(const char* name); ~FileSystemInitializer(); inline FileSystem* GetFileSystem() { return fFileSystem; } @@ -28,9 +29,11 @@ public: protected: virtual status_t FirstTimeInit(); +private: + status_t _Init(port_id port); + private: const char* fName; // valid only until FirstTimeInit() - RequestPort* fInitPort; FileSystem* fFileSystem; }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile index 251a8bec6b..bbddaa6bfc 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile @@ -4,6 +4,7 @@ local userlandFSTop = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems userlandfs ] ; local userlandFSIncludes = [ PrivateHeaders userlandfs ] ; +UsePrivateKernelHeaders ; SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ; SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp index 94b94b70ca..4a62337269 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp @@ -1,4 +1,7 @@ -// UserlandFS.cpp +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #include "UserlandFS.h" @@ -18,9 +21,9 @@ UserlandFS* UserlandFS::sUserlandFS = NULL; // constructor UserlandFS::UserlandFS() - : fPort(NULL), - fFileSystems(NULL), - fDebuggerCommandsAdded(false) + : + fFileSystems(NULL), + fDebuggerCommandsAdded(false) { } @@ -28,19 +31,6 @@ UserlandFS::UserlandFS() UserlandFS::~UserlandFS() { PRINT(("UserlandFS::~UserlandFS()\n")) - if (fPort) { - // send a disconnect request - RequestAllocator allocator(fPort->GetPort()); - UFSDisconnectRequest* request; - if (AllocateRequest(allocator, &request) == B_OK) { - if (fPort->SendRequest(&allocator) != B_OK) - PRINT((" failed to send disconnect request\n")); - } else - PRINT((" failed to allocate disconnect request\n")); - delete fPort; - } else - PRINT((" no port\n")); - delete fFileSystems; if (fDebuggerCommandsAdded) KernelDebug::RemoveDebuggerCommands(); @@ -99,8 +89,8 @@ UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem) if (fileSystemInitializer) { fileSystemInitializer->AddReference(); } else { - fileSystemInitializer = new(nothrow) FileSystemInitializer(name, - fPort); + fileSystemInitializer = new(nothrow) FileSystemInitializer(name/*, + fPort*/); if (!fileSystemInitializer) return B_NO_MEMORY; @@ -156,40 +146,7 @@ UserlandFS::_Init() if (error != B_OK) RETURN_ERROR(error); - // find the dispatcher ports - port_id port = find_port(kUserlandFSDispatcherPortName); - if (port < 0) - RETURN_ERROR(B_ERROR); - port_id replyPort = find_port(kUserlandFSDispatcherReplyPortName); - if (replyPort < 0) - RETURN_ERROR(B_ERROR); - - // create a reply port - // send a connection request - error = write_port(port, UFS_DISPATCHER_CONNECT, NULL, 0); - if (error != B_OK) - RETURN_ERROR(error); - - // receive the reply - int32 replyCode; - Port::Info portInfo; - ssize_t bytesRead = read_port(replyPort, &replyCode, &portInfo, - sizeof(Port::Info)); - if (bytesRead < 0) - RETURN_ERROR(bytesRead); - if (replyCode != UFS_DISPATCHER_CONNECT_ACK) - RETURN_ERROR(B_BAD_DATA); - if (bytesRead != sizeof(Port::Info)) - RETURN_ERROR(B_BAD_DATA); - - // create a request port - fPort = new(nothrow) RequestPort(&portInfo); - if (!fPort) - RETURN_ERROR(B_NO_MEMORY); - if ((error = fPort->InitCheck()) != B_OK) - RETURN_ERROR(error); - - RETURN_ERROR(error); + return B_OK; } // _UnregisterFileSystem diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h index 1c249e048d..0754f23564 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h @@ -1,5 +1,7 @@ -// UserlandFS.h - +/* + * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #ifndef USERLAND_FS_H #define USERLAND_FS_H @@ -49,7 +51,6 @@ private: private: static UserlandFS* sUserlandFS; - RequestPort* fPort; FileSystemMap* fFileSystems; bool fDebuggerCommandsAdded; }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/server/Jamfile index 920c93e829..bb1fca7ae4 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Jamfile @@ -13,10 +13,10 @@ SEARCH_SOURCE += [ FDirName $(userlandFSTop) private ] ; SEARCH_SOURCE += [ FDirName $(userlandFSTop) shared ] ; DEFINES += USER=1 ; -DEFINES += DEBUG_APP="\\\"UserlandFSServer\\\"" ; +DEFINES += DEBUG_APP="\\\"userlandfs_server\\\"" ; DEFINES += BUILDING_USERLAND_FS_SERVER=1 ; -Application UserlandFSServer +Application userlandfs_server : AreaSupport.cpp Debug.cpp @@ -41,7 +41,7 @@ Application UserlandFSServer main.cpp RequestThread.cpp ServerDefs.cpp - UserlandFSDispatcher.cpp +# UserlandFSDispatcher.cpp UserlandFSServer.cpp UserlandRequestHandler.cpp Volume.cpp diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp index 6c06aea0ee..4b40651eb8 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp @@ -39,6 +39,7 @@ UserlandFSServer::UserlandFSServer(const char* signature) { } + // destructor UserlandFSServer::~UserlandFSServer() { @@ -55,9 +56,10 @@ UserlandFSServer::~UserlandFSServer() unload_add_on(fAddOnImage); } + // Init status_t -UserlandFSServer::Init(const char* fileSystem) +UserlandFSServer::Init(const char* fileSystem, port_id port) { // get the add-on path BPath addOnPath; @@ -118,11 +120,12 @@ UserlandFSServer::Init(const char* fileSystem) if (gServerSettings.ShallEnterDebugger()) debugger("File system ready to use."); - // finally register with the dispatcher - error = _RegisterWithDispatcher(fileSystem); + // finally announce our existence + error = _Announce(fileSystem, port); RETURN_ERROR(error); } + // GetNotificationRequestPort RequestPort* UserlandFSServer::GetNotificationRequestPort() @@ -132,6 +135,7 @@ UserlandFSServer::GetNotificationRequestPort() return NULL; } + // GetFileSystem FileSystem* UserlandFSServer::GetFileSystem() @@ -141,62 +145,37 @@ UserlandFSServer::GetFileSystem() return NULL; } -// _RegisterWithDispatcher + +// _Announce status_t -UserlandFSServer::_RegisterWithDispatcher(const char* fsName) +UserlandFSServer::_Announce(const char* fsName, port_id port) { - // get the dispatcher messenger from the clipboard - BMessenger messenger; - BClipboard clipboard(kUserlandFSDispatcherClipboardName); - if (AutoLocker locker = clipboard) { - status_t error = B_OK; - if (BMessage* data = clipboard.Data()) { - error = data->FindMessenger("messenger", &messenger); - if (error != B_OK) { - ERROR(("No dispatcher messenger in clipboard.\n")); - return error; - } - if (!messenger.IsValid()) { - ERROR(("Found dispatcher messenger not valid.\n")); - return B_ERROR; - } - } else { - ERROR(("Failed to get clipboard data container\n")); - return B_ERROR; - } - } else { - ERROR(("Failed to lock the clipboard.\n")); - return B_ERROR; + // if not given, create a port + if (port < 0) { + char portName[B_OS_NAME_LENGTH]; + snprintf(portName, sizeof(portName), "_userlandfs_%s", fsName); + + port = create_port(1, portName); + if (port < 0) + RETURN_ERROR(port); } + // allocate stack space for the FS initialization info + const size_t bufferSize = sizeof(fs_init_info) + + sizeof(Port::Info) * (kRequestThreadCount + 1); + char buffer[bufferSize]; + fs_init_info* info = (fs_init_info*)buffer; + // get the port infos - Port::Info infos[kRequestThreadCount + 1]; - infos[0] = *fNotificationRequestPort->GetPortInfo(); + info->portInfoCount = kRequestThreadCount + 1; + info->portInfos[0] = *fNotificationRequestPort->GetPortInfo(); for (int32 i = 0; i < kRequestThreadCount; i++) - infos[i + 1] = *fRequestThreads[i].GetPortInfo(); + info->portInfos[i + 1] = *fRequestThreads[i].GetPortInfo(); // FS capabilities - FSCapabilities capabilities; - fFileSystem->GetCapabilities(capabilities); + fFileSystem->GetCapabilities(info->capabilities); + info->clientFSType = fFileSystem->GetClientFSType(); - // init an FS info - FSInfo info; - status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1, - capabilities, fFileSystem->GetClientFSType()); - - // prepare the message - BMessage message(UFS_REGISTER_FS); - if (error == B_OK) - error = message.AddInt32("team", Team()); - if (error == B_OK) - error = info.Archive(&message); - - // send the message - BMessage reply; - error = messenger.SendMessage(&message, &reply); - if (error == B_OK && reply.what != UFS_REGISTER_FS_ACK) { - ERROR(("FS registration failed.\n")); - error = B_ERROR; - } - return error; + // send the info to our port + RETURN_ERROR(write_port(port, 0, buffer, bufferSize)); } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.h b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.h index 8dd7089c30..c360556eef 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.h @@ -21,13 +21,13 @@ public: UserlandFSServer(const char* signature); virtual ~UserlandFSServer(); - status_t Init(const char* fileSystem); + status_t Init(const char* fileSystem, port_id port); static RequestPort* GetNotificationRequestPort(); static FileSystem* GetFileSystem(); private: - status_t _RegisterWithDispatcher(const char* fsName); + status_t _Announce(const char* fsName, port_id port); private: image_id fAddOnImage; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/beos/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/server/beos/Jamfile index 75c975d18e..bc49178f14 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/beos/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/server/beos/Jamfile @@ -26,5 +26,5 @@ SharedLibrary libuserlandfs_beos_kernel.so BeOSKernelVolume.cpp : - UserlandFSServer + userlandfs_server ; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile index 662753bbc7..f33aa174f9 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile @@ -34,5 +34,5 @@ SharedLibrary libuserlandfs_haiku_kernel.so HaikuKernelVolume.cpp : - UserlandFSServer + userlandfs_server ; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/main.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/main.cpp index 5fe831e124..941e30dc4a 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/main.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/main.cpp @@ -1,11 +1,13 @@ // main.cpp #include +#include #include +#include + #include "Debug.h" #include "ServerDefs.h" -#include "UserlandFSDispatcher.h" #include "UserlandFSServer.h" // server signature @@ -14,19 +16,19 @@ static const char* kServerSignature // usage static const char* kUsage = -"Usage: %s \n" -" %s \n" +"Usage: %s [ ]\n" "\n" -"The first version runs the server as the dispatcher, i.e. as the singleton\n" -"app the kernel add-on contacts when it is looking for a file system.\n" -"The dispatcher uses the second version to start a server for a specific file\n" -"system.\n" +"Runs the userlandfs server for a given file system. Typically this is done\n" +"automatically by the kernel module when a volume is requested to be mounted,\n" +"but running the server manually can be useful for debugging purposes. The\n" +" argument specifies the name of the file system to be loaded.\n" +" should not be given when starting the server manually; it is used by\n" +"the kernel module only.\n" "\n" "Options:\n" " --debug - the file system server enters the debugger after the\n" " userland file system add-on has been loaded and is\n" -" ready to be used. If specified for the dispatcher, it\n" -" passes the flag to all file system servers it starts.\n" +" ready to be used.\n" " -h, --help - print this text\n" ; @@ -80,37 +82,36 @@ main(int argc, char** argv) fileSystem = argv[argi++]; dispatcher = false; } + + // get the port, if any + int32 port = -1; + if (argi < argc) { + port = atol(argv[argi++]); + if (port <= 0) { + print_usage(); + return 1; + } + } + if (argi < argc) { print_usage(); return 1; } // create and init the application - BApplication* app = NULL; status_t error = B_OK; - if (dispatcher) { - UserlandFSDispatcher* dispatcher - = new(nothrow) UserlandFSDispatcher(kServerSignature); - if (!dispatcher) { - fprintf(stderr, "Failed to create dispatcher.\n"); - return 1; - } - error = dispatcher->Init(); - app = dispatcher; - } else { - UserlandFSServer* server - = new(nothrow) UserlandFSServer(kServerSignature); - if (!server) { - fprintf(stderr, "Failed to create server.\n"); - return 1; - } - error = server->Init(fileSystem); - app = server; + UserlandFSServer* server + = new(std::nothrow) UserlandFSServer(kServerSignature); + if (!server) { + fprintf(stderr, "Failed to create server.\n"); + return 1; } + error = server->Init(fileSystem, port); // run it, if everything went fine if (error == B_OK) - app->Run(); - delete app; + server->Run(); + + delete server; return 0; }