* Renamed UserlandFSServer to userlandfs_server. It is expected to live in

/system/servers, now.
* Got rid of the dispatcher application. It was the entity the kernel module
  talked to when mounting a yet unknown FS. It started the client FS server
  applications. Now the kernel module starts them directly. They use
  respectively named ports, so the kernel module can find them when already
  running.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29377 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-03-02 00:37:14 +00:00
parent 2f8d0984b4
commit 2f1f4f54d6
12 changed files with 208 additions and 194 deletions
@@ -3,15 +3,27 @@
#ifndef USERLAND_FS_DISPATCHER_DEFS_H #ifndef USERLAND_FS_DISPATCHER_DEFS_H
#define USERLAND_FS_DISPATCHER_DEFS_H #define USERLAND_FS_DISPATCHER_DEFS_H
#include "FSCapabilities.h"
#include "Port.h"
namespace UserlandFSUtil { namespace UserlandFSUtil {
extern const char* kUserlandFSDispatcherPortName; extern const char* kUserlandFSDispatcherPortName;
extern const char* kUserlandFSDispatcherReplyPortName; extern const char* kUserlandFSDispatcherReplyPortName;
struct fs_init_info {
FSCapabilities capabilities;
client_fs_type clientFSType;
int32 portInfoCount;
Port::Info portInfos[0];
};
} // namespace UserlandFSUtil } // namespace UserlandFSUtil
using UserlandFSUtil::kUserlandFSDispatcherPortName; using UserlandFSUtil::kUserlandFSDispatcherPortName;
using UserlandFSUtil::kUserlandFSDispatcherReplyPortName; using UserlandFSUtil::kUserlandFSDispatcherReplyPortName;
using UserlandFSUtil::fs_init_info;
enum { enum {
UFS_DISPATCHER_CONNECT = 'cnct', UFS_DISPATCHER_CONNECT = 'cnct',
@@ -1,76 +1,136 @@
// FileSystemInitializer.cpp /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "FileSystemInitializer.h" #include "FileSystemInitializer.h"
#include <new> #include <new>
#include <image.h>
#include <OS.h>
#include <port.h>
#include <team.h>
#include "AutoDeleter.h"
#include "DispatcherDefs.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "RequestAllocator.h" #include "RequestAllocator.h"
#include "RequestPort.h" #include "RequestPort.h"
#include "Requests.h" #include "Requests.h"
#include "SingleReplyRequestHandler.h" #include "SingleReplyRequestHandler.h"
using std::nothrow;
// constructor // constructor
FileSystemInitializer::FileSystemInitializer(const char* name, FileSystemInitializer::FileSystemInitializer(const char* name)
RequestPort* initPort) :
: fName(name), fName(name),
fInitPort(initPort), fFileSystem(NULL)
fFileSystem(NULL)
{ {
// Note: We don't copy the name. It's only needed in FirstTimeInit() and // Note: We don't copy the name. It's only needed in FirstTimeInit() and
// the UserlandFS makes sure it is valid until then. // the UserlandFS makes sure it is valid until then.
} }
// destructor // destructor
FileSystemInitializer::~FileSystemInitializer() FileSystemInitializer::~FileSystemInitializer()
{ {
delete fFileSystem; delete fFileSystem;
} }
// FirstTimeInit // FirstTimeInit
status_t status_t
FileSystemInitializer::FirstTimeInit() FileSystemInitializer::FirstTimeInit()
{ {
// prepare the request // First check whether a server for this FS is already loaded. Look for a
RequestAllocator allocator(fInitPort->GetPort()); // port with the respective name.
FSConnectRequest* request; char portName[B_OS_NAME_LENGTH];
status_t error = AllocateRequest(allocator, &request); snprintf(portName, sizeof(portName), "_userlandfs_%s", fName);
if (error != B_OK)
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); 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; return B_OK;
} }
@@ -1,5 +1,7 @@
// FileSystemInitializer.h /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_FILE_SYSTEM_INITIALIZER_H #ifndef USERLAND_FS_FILE_SYSTEM_INITIALIZER_H
#define 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 { class FileSystemInitializer : public LazyInitializable, public Referencable {
public: public:
FileSystemInitializer(const char* name, FileSystemInitializer(const char* name);
RequestPort* initPort);
~FileSystemInitializer(); ~FileSystemInitializer();
inline FileSystem* GetFileSystem() { return fFileSystem; } inline FileSystem* GetFileSystem() { return fFileSystem; }
@@ -28,9 +29,11 @@ public:
protected: protected:
virtual status_t FirstTimeInit(); virtual status_t FirstTimeInit();
private:
status_t _Init(port_id port);
private: private:
const char* fName; // valid only until FirstTimeInit() const char* fName; // valid only until FirstTimeInit()
RequestPort* fInitPort;
FileSystem* fFileSystem; FileSystem* fFileSystem;
}; };
@@ -4,6 +4,7 @@ local userlandFSTop = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems
userlandfs ] ; userlandfs ] ;
local userlandFSIncludes = [ PrivateHeaders userlandfs ] ; local userlandFSIncludes = [ PrivateHeaders userlandfs ] ;
UsePrivateKernelHeaders ;
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ; SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ; SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
@@ -1,4 +1,7 @@
// UserlandFS.cpp /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "UserlandFS.h" #include "UserlandFS.h"
@@ -18,9 +21,9 @@ UserlandFS* UserlandFS::sUserlandFS = NULL;
// constructor // constructor
UserlandFS::UserlandFS() UserlandFS::UserlandFS()
: fPort(NULL), :
fFileSystems(NULL), fFileSystems(NULL),
fDebuggerCommandsAdded(false) fDebuggerCommandsAdded(false)
{ {
} }
@@ -28,19 +31,6 @@ UserlandFS::UserlandFS()
UserlandFS::~UserlandFS() UserlandFS::~UserlandFS()
{ {
PRINT(("UserlandFS::~UserlandFS()\n")) 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; delete fFileSystems;
if (fDebuggerCommandsAdded) if (fDebuggerCommandsAdded)
KernelDebug::RemoveDebuggerCommands(); KernelDebug::RemoveDebuggerCommands();
@@ -99,8 +89,8 @@ UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem)
if (fileSystemInitializer) { if (fileSystemInitializer) {
fileSystemInitializer->AddReference(); fileSystemInitializer->AddReference();
} else { } else {
fileSystemInitializer = new(nothrow) FileSystemInitializer(name, fileSystemInitializer = new(nothrow) FileSystemInitializer(name/*,
fPort); fPort*/);
if (!fileSystemInitializer) if (!fileSystemInitializer)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -156,40 +146,7 @@ UserlandFS::_Init()
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// find the dispatcher ports return B_OK;
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);
} }
// _UnregisterFileSystem // _UnregisterFileSystem
@@ -1,5 +1,7 @@
// UserlandFS.h /*
* Copyright 2001-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_H #ifndef USERLAND_FS_H
#define USERLAND_FS_H #define USERLAND_FS_H
@@ -49,7 +51,6 @@ private:
private: private:
static UserlandFS* sUserlandFS; static UserlandFS* sUserlandFS;
RequestPort* fPort;
FileSystemMap* fFileSystems; FileSystemMap* fFileSystems;
bool fDebuggerCommandsAdded; bool fDebuggerCommandsAdded;
}; };
@@ -13,10 +13,10 @@ SEARCH_SOURCE += [ FDirName $(userlandFSTop) private ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) shared ] ; SEARCH_SOURCE += [ FDirName $(userlandFSTop) shared ] ;
DEFINES += USER=1 ; DEFINES += USER=1 ;
DEFINES += DEBUG_APP="\\\"UserlandFSServer\\\"" ; DEFINES += DEBUG_APP="\\\"userlandfs_server\\\"" ;
DEFINES += BUILDING_USERLAND_FS_SERVER=1 ; DEFINES += BUILDING_USERLAND_FS_SERVER=1 ;
Application UserlandFSServer Application userlandfs_server
: :
AreaSupport.cpp AreaSupport.cpp
Debug.cpp Debug.cpp
@@ -41,7 +41,7 @@ Application UserlandFSServer
main.cpp main.cpp
RequestThread.cpp RequestThread.cpp
ServerDefs.cpp ServerDefs.cpp
UserlandFSDispatcher.cpp # UserlandFSDispatcher.cpp
UserlandFSServer.cpp UserlandFSServer.cpp
UserlandRequestHandler.cpp UserlandRequestHandler.cpp
Volume.cpp Volume.cpp
@@ -39,6 +39,7 @@ UserlandFSServer::UserlandFSServer(const char* signature)
{ {
} }
// destructor // destructor
UserlandFSServer::~UserlandFSServer() UserlandFSServer::~UserlandFSServer()
{ {
@@ -55,9 +56,10 @@ UserlandFSServer::~UserlandFSServer()
unload_add_on(fAddOnImage); unload_add_on(fAddOnImage);
} }
// Init // Init
status_t status_t
UserlandFSServer::Init(const char* fileSystem) UserlandFSServer::Init(const char* fileSystem, port_id port)
{ {
// get the add-on path // get the add-on path
BPath addOnPath; BPath addOnPath;
@@ -118,11 +120,12 @@ UserlandFSServer::Init(const char* fileSystem)
if (gServerSettings.ShallEnterDebugger()) if (gServerSettings.ShallEnterDebugger())
debugger("File system ready to use."); debugger("File system ready to use.");
// finally register with the dispatcher // finally announce our existence
error = _RegisterWithDispatcher(fileSystem); error = _Announce(fileSystem, port);
RETURN_ERROR(error); RETURN_ERROR(error);
} }
// GetNotificationRequestPort // GetNotificationRequestPort
RequestPort* RequestPort*
UserlandFSServer::GetNotificationRequestPort() UserlandFSServer::GetNotificationRequestPort()
@@ -132,6 +135,7 @@ UserlandFSServer::GetNotificationRequestPort()
return NULL; return NULL;
} }
// GetFileSystem // GetFileSystem
FileSystem* FileSystem*
UserlandFSServer::GetFileSystem() UserlandFSServer::GetFileSystem()
@@ -141,62 +145,37 @@ UserlandFSServer::GetFileSystem()
return NULL; return NULL;
} }
// _RegisterWithDispatcher
// _Announce
status_t status_t
UserlandFSServer::_RegisterWithDispatcher(const char* fsName) UserlandFSServer::_Announce(const char* fsName, port_id port)
{ {
// get the dispatcher messenger from the clipboard // if not given, create a port
BMessenger messenger; if (port < 0) {
BClipboard clipboard(kUserlandFSDispatcherClipboardName); char portName[B_OS_NAME_LENGTH];
if (AutoLocker<BClipboard> locker = clipboard) { snprintf(portName, sizeof(portName), "_userlandfs_%s", fsName);
status_t error = B_OK;
if (BMessage* data = clipboard.Data()) { port = create_port(1, portName);
error = data->FindMessenger("messenger", &messenger); if (port < 0)
if (error != B_OK) { RETURN_ERROR(port);
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;
} }
// 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 // get the port infos
Port::Info infos[kRequestThreadCount + 1]; info->portInfoCount = kRequestThreadCount + 1;
infos[0] = *fNotificationRequestPort->GetPortInfo(); info->portInfos[0] = *fNotificationRequestPort->GetPortInfo();
for (int32 i = 0; i < kRequestThreadCount; i++) for (int32 i = 0; i < kRequestThreadCount; i++)
infos[i + 1] = *fRequestThreads[i].GetPortInfo(); info->portInfos[i + 1] = *fRequestThreads[i].GetPortInfo();
// FS capabilities // FS capabilities
FSCapabilities capabilities; fFileSystem->GetCapabilities(info->capabilities);
fFileSystem->GetCapabilities(capabilities); info->clientFSType = fFileSystem->GetClientFSType();
// init an FS info // send the info to our port
FSInfo info; RETURN_ERROR(write_port(port, 0, buffer, bufferSize));
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;
} }
@@ -21,13 +21,13 @@ public:
UserlandFSServer(const char* signature); UserlandFSServer(const char* signature);
virtual ~UserlandFSServer(); virtual ~UserlandFSServer();
status_t Init(const char* fileSystem); status_t Init(const char* fileSystem, port_id port);
static RequestPort* GetNotificationRequestPort(); static RequestPort* GetNotificationRequestPort();
static FileSystem* GetFileSystem(); static FileSystem* GetFileSystem();
private: private:
status_t _RegisterWithDispatcher(const char* fsName); status_t _Announce(const char* fsName, port_id port);
private: private:
image_id fAddOnImage; image_id fAddOnImage;
@@ -26,5 +26,5 @@ SharedLibrary libuserlandfs_beos_kernel.so
BeOSKernelVolume.cpp BeOSKernelVolume.cpp
: :
<nogrist>UserlandFSServer <nogrist>userlandfs_server
; ;
@@ -34,5 +34,5 @@ SharedLibrary libuserlandfs_haiku_kernel.so
HaikuKernelVolume.cpp HaikuKernelVolume.cpp
: :
<nogrist>UserlandFSServer <nogrist>userlandfs_server
; ;
@@ -1,11 +1,13 @@
// main.cpp // main.cpp
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <new>
#include "Debug.h" #include "Debug.h"
#include "ServerDefs.h" #include "ServerDefs.h"
#include "UserlandFSDispatcher.h"
#include "UserlandFSServer.h" #include "UserlandFSServer.h"
// server signature // server signature
@@ -14,19 +16,19 @@ static const char* kServerSignature
// usage // usage
static const char* kUsage = static const char* kUsage =
"Usage: %s <options>\n" "Usage: %s <options> <file system> [ <port> ]\n"
" %s <options> <file system>\n"
"\n" "\n"
"The first version runs the server as the dispatcher, i.e. as the singleton\n" "Runs the userlandfs server for a given file system. Typically this is done\n"
"app the kernel add-on contacts when it is looking for a file system.\n" "automatically by the kernel module when a volume is requested to be mounted,\n"
"The dispatcher uses the second version to start a server for a specific file\n" "but running the server manually can be useful for debugging purposes. The\n"
"system.\n" "<file system> argument specifies the name of the file system to be loaded.\n"
"<port> should not be given when starting the server manually; it is used by\n"
"the kernel module only.\n"
"\n" "\n"
"Options:\n" "Options:\n"
" --debug - the file system server enters the debugger after the\n" " --debug - the file system server enters the debugger after the\n"
" userland file system add-on has been loaded and is\n" " userland file system add-on has been loaded and is\n"
" ready to be used. If specified for the dispatcher, it\n" " ready to be used.\n"
" passes the flag to all file system servers it starts.\n"
" -h, --help - print this text\n" " -h, --help - print this text\n"
; ;
@@ -80,37 +82,36 @@ main(int argc, char** argv)
fileSystem = argv[argi++]; fileSystem = argv[argi++];
dispatcher = false; 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) { if (argi < argc) {
print_usage(); print_usage();
return 1; return 1;
} }
// create and init the application // create and init the application
BApplication* app = NULL;
status_t error = B_OK; status_t error = B_OK;
if (dispatcher) { UserlandFSServer* server
UserlandFSDispatcher* dispatcher = new(std::nothrow) UserlandFSServer(kServerSignature);
= new(nothrow) UserlandFSDispatcher(kServerSignature); if (!server) {
if (!dispatcher) { fprintf(stderr, "Failed to create server.\n");
fprintf(stderr, "Failed to create dispatcher.\n"); return 1;
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;
} }
error = server->Init(fileSystem, port);
// run it, if everything went fine // run it, if everything went fine
if (error == B_OK) if (error == B_OK)
app->Run(); server->Run();
delete app;
delete server;
return 0; return 0;
} }