* 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

View File

@ -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',

View File

@ -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 <new>
#include <image.h>
#include <OS.h>
#include <port.h>
#include <team.h>
#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;
}

View File

@ -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;
};

View File

@ -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 ] ;

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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<BClipboard> 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));
}

View File

@ -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;

View File

@ -26,5 +26,5 @@ SharedLibrary libuserlandfs_beos_kernel.so
BeOSKernelVolume.cpp
:
<nogrist>UserlandFSServer
<nogrist>userlandfs_server
;

View File

@ -34,5 +34,5 @@ SharedLibrary libuserlandfs_haiku_kernel.so
HaikuKernelVolume.cpp
:
<nogrist>UserlandFSServer
<nogrist>userlandfs_server
;

View File

@ -1,11 +1,13 @@
// main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#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 <options>\n"
" %s <options> <file system>\n"
"Usage: %s <options> <file system> [ <port> ]\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"
"<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"
"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;
}