Files
haiku-beta6/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp
T
Ingo Weinhold 4e0e80ed6c We analyze a client FS's capabilities -- i.e. which hooks it provides or
can be emulated -- and pass this info to the kernel add-on. Thus we can
avoid passing requests to the userland that can't be serviced anyway.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20331 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-03-05 05:16:08 +00:00

219 lines
5.4 KiB
C++

// UserlandFSServer.cpp
#include "UserlandFSServer.h"
#include <new>
#include <stdio.h>
#include <string.h>
#include <Application.h>
#include <Clipboard.h>
#include <FindDirectory.h>
#include <fs_interface.h>
#include <image.h>
#include <Locker.h>
#include <Path.h>
#include "AutoLocker.h"
#include "beos_fs_cache.h"
#include "beos_fs_interface.h"
#include "BeOSKernelFileSystem.h"
#include "Compatibility.h"
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FileSystem.h"
#include "FSInfo.h"
#include "RequestThread.h"
#include "ServerDefs.h"
static const int32 kRequestThreadCount = 10;
static const int32 kMaxBlockCacheBlocks = 16384;
// constructor
UserlandFSServer::UserlandFSServer(const char* signature)
: BApplication(signature),
fAddOnImage(-1),
fFileSystem(NULL),
fNotificationRequestPort(NULL),
fRequestThreads(NULL),
fBlockCacheInitialized(false)
{
}
// destructor
UserlandFSServer::~UserlandFSServer()
{
if (fRequestThreads) {
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].PrepareTermination();
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].Terminate();
delete[] fRequestThreads;
}
delete fNotificationRequestPort;
delete fFileSystem;
if (fBlockCacheInitialized)
beos_shutdown_block_cache();
if (fAddOnImage >= 0)
unload_add_on(fAddOnImage);
}
// Init
status_t
UserlandFSServer::Init(const char* fileSystem)
{
// get the add-on path
BPath addOnPath;
status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath);
if (error != B_OK)
RETURN_ERROR(error);
error = addOnPath.Append("userlandfs");
if (error != B_OK)
RETURN_ERROR(error);
error = addOnPath.Append(fileSystem);
if (error != B_OK)
RETURN_ERROR(error);
// load the add-on
fAddOnImage = load_add_on(addOnPath.Path());
if (fAddOnImage < 0)
RETURN_ERROR(fAddOnImage);
// get the symbols "fs_entry" and "api_version"
beos_vnode_ops* fsOps;
error = get_image_symbol(fAddOnImage, "fs_entry", B_SYMBOL_TYPE_DATA,
(void**)&fsOps);
if (error != B_OK)
RETURN_ERROR(error);
int32* apiVersion;
error = get_image_symbol(fAddOnImage, "api_version", B_SYMBOL_TYPE_DATA,
(void**)&apiVersion);
if (error != B_OK)
RETURN_ERROR(error);
// check api version
if (*apiVersion != BEOS_FS_API_VERSION)
RETURN_ERROR(B_ERROR);
// create the file system
fFileSystem = new(nothrow) BeOSKernelFileSystem(fsOps);
if (!fileSystem)
RETURN_ERROR(B_NO_MEMORY);
// init the block cache
error = beos_init_block_cache(kMaxBlockCacheBlocks, 0);
if (error != B_OK)
RETURN_ERROR(error);
fBlockCacheInitialized = true;
// create the notification request port
fNotificationRequestPort = new(nothrow) RequestPort(kRequestPortSize);
if (!fNotificationRequestPort)
RETURN_ERROR(B_NO_MEMORY);
error = fNotificationRequestPort->InitCheck();
if (error != B_OK)
RETURN_ERROR(error);
// now create the request threads
fRequestThreads = new(nothrow) RequestThread[kRequestThreadCount];
if (!fRequestThreads)
RETURN_ERROR(B_NO_MEMORY);
for (int32 i = 0; i < kRequestThreadCount; i++) {
error = fRequestThreads[i].Init(fFileSystem);
if (error != B_OK)
RETURN_ERROR(error);
}
// run the threads
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].Run();
// enter the debugger here, if desired
if (gServerSettings.ShallEnterDebugger())
debugger("File system ready to use.");
// finally register with the dispatcher
error = _RegisterWithDispatcher(fileSystem);
RETURN_ERROR(error);
}
// GetNotificationRequestPort
RequestPort*
UserlandFSServer::GetNotificationRequestPort()
{
if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
return server->fNotificationRequestPort;
return NULL;
}
// GetFileSystem
FileSystem*
UserlandFSServer::GetFileSystem()
{
if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
return server->fFileSystem;
return NULL;
}
// _RegisterWithDispatcher
status_t
UserlandFSServer::_RegisterWithDispatcher(const char* fsName)
{
// 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;
}
// get the port infos
Port::Info infos[kRequestThreadCount + 1];
infos[0] = *fNotificationRequestPort->GetPortInfo();
for (int32 i = 0; i < kRequestThreadCount; i++)
infos[i + 1] = *fRequestThreads[i].GetPortInfo();
// FS capabilities
FSCapabilities capabilities;
fFileSystem->GetCapabilities(capabilities);
// init an FS info
FSInfo info;
status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1,
capabilities);
// 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;
}