Added a level of indirection in the FileSystem management

(FileSystemInitializer). This will allow for subclassing FileSystem
later.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20328 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-03-04 23:11:02 +00:00
parent fd7339329f
commit 5a5aacca23
8 changed files with 284 additions and 171 deletions

View File

@ -8,7 +8,6 @@
#include "KernelRequestHandler.h"
#include "PortReleaser.h"
#include "RequestAllocator.h"
#include "RequestPort.h"
#include "Requests.h"
#include "Settings.h"
#include "SingleReplyRequestHandler.h"
@ -25,34 +24,32 @@ struct FileSystem::SelectSyncMap
};
// constructor
FileSystem::FileSystem(const char* name, RequestPort* initPort, status_t* error)
: LazyInitializable(),
Referencable(),
fVolumes(),
FileSystem::FileSystem()
: fVolumes(),
fVolumeLock(),
fName(name),
fInitPort(initPort),
fName(),
fNotificationPort(NULL),
fNotificationThread(-1),
fPortPool(),
fSelectSyncs(NULL),
fSettings(NULL),
fUserlandServerTeam(-1),
fInitialized(false),
fTerminating(false)
{
if (error)
*error = (fName.GetLength() == 0 ? B_NO_MEMORY : B_OK);
}
// destructor
FileSystem::~FileSystem()
{
fTerminating = true;
// wait for the notification thread to terminate
if (fNotificationThread >= 0) {
int32 result;
wait_for_thread(fNotificationThread, &result);
}
// delete our data structures
if (fSelectSyncs) {
for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
@ -65,6 +62,96 @@ FileSystem::~FileSystem()
delete fSettings;
}
// Init
status_t
FileSystem::Init(const char* name, Port::Info* infos, int32 count)
{
PRINT(("FileSystem::Init(\"%s\", %p, %ld)\n", name, infos, infoCount));
// check parameters
if (!name || !infos || count < 2)
RETURN_ERROR(B_BAD_VALUE);
// set the name
if (!fName.SetTo(name))
return B_NO_MEMORY;
// create the select sync entry map
fSelectSyncs = new(nothrow) SelectSyncMap;
if (!fSelectSyncs)
return B_NO_MEMORY;
// create the request ports
// the notification port
fNotificationPort = new(nothrow) RequestPort(infos);
if (!fNotificationPort)
RETURN_ERROR(B_NO_MEMORY);
status_t error = fNotificationPort->InitCheck();
if (error != B_OK)
return error;
// the other request ports
for (int32 i = 1; i < count; i++) {
RequestPort* port = new(nothrow) RequestPort(infos + i);
if (!port)
RETURN_ERROR(B_NO_MEMORY);
error = port->InitCheck();
if (error == B_OK)
error = fPortPool.AddPort(port);
if (error != B_OK) {
delete port;
RETURN_ERROR(error);
}
}
// get the userland team
port_info portInfo;
error = get_port_info(infos[0].owner_port, &portInfo);
if (error != B_OK)
RETURN_ERROR(error);
fUserlandServerTeam = portInfo.team;
// print some info about the userland team
D(
PRINT((" userland team is: %ld\n", fUserlandServerTeam));
int32 cookie = 0;
thread_info threadInfo;
while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo)
== B_OK) {
PRINT((" userland thread: %ld: `%s'\n", threadInfo.thread,
threadInfo.name));
}
);
// load the settings
fSettings = new(nothrow) Settings;
if (fSettings) {
status_t settingsError = fSettings->SetTo(fName.GetString());
if (settingsError != B_OK) {
PRINT(("Failed to load settings: %s\n", strerror(settingsError)));
delete fSettings;
fSettings = NULL;
} else
fSettings->Dump();
} else
ERROR(("Failed to allocate settings.\n"));
// spawn the notification thread
#if USER
fNotificationThread = spawn_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#else
fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#endif
if (fNotificationThread < 0)
RETURN_ERROR(fNotificationThread);
resume_thread(fNotificationThread);
fInitialized = (error == B_OK);
RETURN_ERROR(error);
}
// GetName
const char*
FileSystem::GetName() const
@ -85,9 +172,7 @@ FileSystem::Mount(mount_id id, const char* device, uint32 flags,
const char* parameters, Volume** _volume)
{
// check initialization and parameters
if (InitCheck() != B_OK)
return InitCheck();
if (!_volume)
if (!fInitialized || !_volume)
return B_BAD_VALUE;
// create volume
@ -232,107 +317,6 @@ FileSystem::IsUserlandServerThread() const
return (info.team == fUserlandServerTeam);
}
// FirstTimeInit
status_t
FileSystem::FirstTimeInit()
{
if (fName.GetLength() == 0)
RETURN_ERROR(B_NO_MEMORY);
PRINT(("FileSystem::FirstTimeInit(): %s\n", fName.GetString()));
// create the select sync entry map
fSelectSyncs = new(nothrow) SelectSyncMap;
if (!fSelectSyncs)
return B_NO_MEMORY;
// prepare the request
RequestAllocator allocator(fInitPort->GetPort());
FSConnectRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
RETURN_ERROR(error);
error = allocator.AllocateString(request->fsName, fName.GetString());
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 the request ports
// the notification port
fNotificationPort = new(nothrow) RequestPort(infos);
if (!fNotificationPort)
RETURN_ERROR(B_NO_MEMORY);
error = fNotificationPort->InitCheck();
if (error != B_OK)
return error;
// the other request ports
for (int32 i = 1; i < count; i++) {
RequestPort* port = new(nothrow) RequestPort(infos + i);
if (!port)
RETURN_ERROR(B_NO_MEMORY);
error = port->InitCheck();
if (error == B_OK)
error = fPortPool.AddPort(port);
if (error != B_OK) {
delete port;
RETURN_ERROR(error);
}
}
// get the userland team
port_info portInfo;
error = get_port_info(infos[0].owner_port, &portInfo);
if (error != B_OK)
RETURN_ERROR(error);
fUserlandServerTeam = portInfo.team;
// print some info about the userland team
D(
PRINT((" userland team is: %ld\n", fUserlandServerTeam));
int32 cookie = 0;
thread_info threadInfo;
while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo)
== B_OK) {
PRINT((" userland thread: %ld: `%s'\n", threadInfo.thread,
threadInfo.name));
}
);
// load the settings
fSettings = new(nothrow) Settings;
if (fSettings) {
status_t settingsError = fSettings->SetTo(fName.GetString());
if (settingsError != B_OK) {
PRINT(("Failed to load settings: %s\n", strerror(settingsError)));
delete fSettings;
fSettings = NULL;
} else
fSettings->Dump();
} else
ERROR(("Failed to allocate settings.\n"));
// spawn the notification thread
#if USER
fNotificationThread = spawn_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#else
fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#endif
if (fNotificationThread < 0)
RETURN_ERROR(fNotificationThread);
resume_thread(fNotificationThread);
RETURN_ERROR(error);
}
// _NotificationThreadEntry
int32
FileSystem::_NotificationThreadEntry(void* data)

View File

@ -8,29 +8,24 @@
#include "LazyInitializable.h"
#include "Locker.h"
#include "Referencable.h"
#include "RequestPort.h"
#include "RequestPortPool.h"
#include "String.h"
#include "Vector.h"
namespace UserlandFSUtil {
class RequestPort;
}
using UserlandFSUtil::RequestPort;
struct IOCtlInfo;
class Settings;
class Volume;
class FileSystem : public LazyInitializable, public Referencable {
class FileSystem {
public:
FileSystem(const char* name,
RequestPort* initPort,
status_t* error);
FileSystem();
~FileSystem();
status_t Init(const char* name, Port::Info* infos,
int32 infoCount);
const char* GetName() const;
RequestPortPool* GetPortPool();
@ -52,9 +47,6 @@ public:
bool IsUserlandServerThread() const;
protected:
virtual status_t FirstTimeInit();
private:
static int32 _NotificationThreadEntry(void* data);
int32 _NotificationThread();
@ -67,13 +59,13 @@ private:
Vector<Volume*> fVolumes;
Locker fVolumeLock;
String fName;
RequestPort* fInitPort;
RequestPort* fNotificationPort;
thread_id fNotificationThread;
RequestPortPool fPortPool;
SelectSyncMap* fSelectSyncs;
Settings* fSettings;
team_id fUserlandServerTeam;
bool fInitialized;
volatile bool fTerminating;
};

View File

@ -0,0 +1,76 @@
// FileSystemInitializer.cpp
#include "FileSystemInitializer.h"
#include <new>
#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)
{
// 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)
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);
if (error != B_OK)
return B_ERROR;
return B_OK;
}

View File

@ -0,0 +1,37 @@
// FileSystemInitializer.h
#ifndef USERLAND_FS_FILE_SYSTEM_INITIALIZER_H
#define USERLAND_FS_FILE_SYSTEM_INITIALIZER_H
#include "LazyInitializable.h"
#include "Referencable.h"
namespace UserlandFSUtil {
class RequestPort;
}
using UserlandFSUtil::RequestPort;
class FileSystem;
class FileSystemInitializer : public LazyInitializable, public Referencable {
public:
FileSystemInitializer(const char* name,
RequestPort* initPort);
~FileSystemInitializer();
inline FileSystem* GetFileSystem() { return fFileSystem; }
protected:
virtual status_t FirstTimeInit();
private:
const char* fName; // valid only until FirstTimeInit()
RequestPort* fInitPort;
FileSystem* fFileSystem;
};
#endif // USERLAND_FS_FILE_SYSTEM_INITIALIZER_H

View File

@ -32,6 +32,7 @@ KernelAddon userlandfs
userlandfs_ioctl.cpp
FileSystem.cpp
FileSystemInitializer.cpp
kernel_interface.cpp
KernelDebug.cpp
KernelRequestHandler.cpp

View File

@ -1,10 +1,12 @@
// KernelDebug.cpp
#include "KernelDebug.h"
#include <KernelExport.h>
#include "Debug.h"
#include "FileSystem.h"
#include "KernelDebug.h"
#include "FileSystemInitializer.h"
#include "RequestPort.h"
#include "RequestPortPool.h"
#include "UserlandFS.h"
@ -16,19 +18,23 @@ static vint32 sCommandsAdded = 0;
int
KernelDebug::DebugUFS(int argc, char** argv)
{
typedef HashMap<String, FileSystem*> KDebugFSMap;
typedef HashMap<String, FileSystemInitializer*> KDebugFSMap;
UserlandFS* userlandFS = UserlandFS::GetUserlandFS();
KDebugFSMap& fileSystems = userlandFS->fFileSystems->GetUnsynchronizedMap();
for (KDebugFSMap::Iterator it = fileSystems.GetIterator();
it.HasNext();) {
KDebugFSMap::Entry entry = it.Next();
FileSystem* fs = entry.value;
kprintf("file system %p: %s\n", fs, fs->GetName());
kprintf(" port pool %p\n", fs->GetPortPool());
int32 volumeCount = fs->fVolumes.Count();
for (int32 i = 0; i < volumeCount; i++) {
Volume* volume = fs->fVolumes.ElementAt(i);
kprintf(" volume %p: %ld\n", volume, volume->GetID());
FileSystemInitializer* fsInitializer = entry.value;
FileSystem* fs = fsInitializer->GetFileSystem();
kprintf("file system %p: %s\n", fs, (fs ? fs->GetName() : NULL));
if (fs) {
kprintf(" port pool %p\n", fs->GetPortPool());
int32 volumeCount = fs->fVolumes.Count();
for (int32 i = 0; i < volumeCount; i++) {
Volume* volume = fs->fVolumes.ElementAt(i);
kprintf(" volume %p: %ld\n", volume, volume->GetID());
}
}
}
return 0;

View File

@ -1,15 +1,17 @@
// UserlandFS.cpp
#include "UserlandFS.h"
#include <KernelExport.h>
#include "Compatibility.h"
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FileSystem.h"
#include "FileSystemInitializer.h"
#include "KernelDebug.h"
#include "RequestPort.h"
#include "Requests.h"
#include "UserlandFS.h"
UserlandFS* UserlandFS::sUserlandFS = NULL;
@ -90,34 +92,34 @@ UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem)
return B_BAD_VALUE;
// check, if we do already know this file system, and create it, if not
FileSystem* fileSystem;
FileSystemInitializer* fileSystemInitializer;
{
FileSystemLocker _(fFileSystems);
fileSystem = fFileSystems->Get(name);
if (fileSystem) {
fileSystem->AddReference();
fileSystemInitializer = fFileSystems->Get(name);
if (fileSystemInitializer) {
fileSystemInitializer->AddReference();
} else {
status_t error;
fileSystem = new(nothrow) FileSystem(name, fPort, &error);
if (!fileSystem)
fileSystemInitializer = new(nothrow) FileSystemInitializer(name,
fPort);
if (!fileSystemInitializer)
return B_NO_MEMORY;
if (error == B_OK)
error = fFileSystems->Put(name, fileSystem);
status_t error = fFileSystems->Put(name, fileSystemInitializer);
if (error != B_OK) {
delete fileSystem;
delete fileSystemInitializer;
return error;
}
}
}
// prepare the file system
status_t error = fileSystem->Access();
status_t error = fileSystemInitializer->Access();
if (error != B_OK) {
UnregisterFileSystem(fileSystem);
_UnregisterFileSystem(name);
return error;
}
*_fileSystem = fileSystem;
*_fileSystem = fileSystemInitializer->GetFileSystem();
return error;
}
@ -128,22 +130,7 @@ UserlandFS::UnregisterFileSystem(FileSystem* fileSystem)
if (!fileSystem)
return B_BAD_VALUE;
// find the FS and decrement its reference counter
bool deleteFS = false;
{
FileSystemLocker _(fFileSystems);
fileSystem = fFileSystems->Get(fileSystem->GetName());
if (!fileSystem)
return B_BAD_VALUE;
deleteFS = fileSystem->RemoveReference();
if (deleteFS)
fFileSystems->Remove(fileSystem->GetName());
}
// delete the FS, if the last reference has been removed
if (deleteFS)
delete fileSystem;
return B_OK;
return _UnregisterFileSystem(fileSystem->GetName());
}
// CountFileSystems
@ -205,3 +192,29 @@ UserlandFS::_Init()
RETURN_ERROR(error);
}
// _UnregisterFileSystem
status_t
UserlandFS::_UnregisterFileSystem(const char* name)
{
if (!name)
return B_BAD_VALUE;
// find the FS and decrement its reference counter
FileSystemInitializer* fileSystemInitializer = NULL;
bool deleteFS = false;
{
FileSystemLocker _(fFileSystems);
fileSystemInitializer = fFileSystems->Get(name);
if (!fileSystemInitializer)
return B_BAD_VALUE;
deleteFS = fileSystemInitializer->RemoveReference();
if (deleteFS)
fFileSystems->Remove(name);
}
// delete the FS, if the last reference has been removed
if (deleteFS)
delete fileSystemInitializer;
return B_OK;
}

View File

@ -18,6 +18,7 @@ class RequestPort;
using UserlandFSUtil::RequestPort;
class FileSystem;
class FileSystemInitializer;
class UserlandFS {
private:
@ -35,14 +36,17 @@ public:
int32 CountFileSystems() const;
private:
status_t _Init();
private:
friend class KernelDebug;
typedef SynchronizedHashMap<String, FileSystem*> FileSystemMap;
typedef SynchronizedHashMap<String, FileSystemInitializer*>
FileSystemMap;
typedef AutoLocker<UserlandFS::FileSystemMap> FileSystemLocker;
private:
status_t _Init();
status_t _UnregisterFileSystem(const char* name);
private:
static UserlandFS* sUserlandFS;
RequestPort* fPort;