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 "KernelRequestHandler.h"
#include "PortReleaser.h" #include "PortReleaser.h"
#include "RequestAllocator.h" #include "RequestAllocator.h"
#include "RequestPort.h"
#include "Requests.h" #include "Requests.h"
#include "Settings.h" #include "Settings.h"
#include "SingleReplyRequestHandler.h" #include "SingleReplyRequestHandler.h"
@ -25,34 +24,32 @@ struct FileSystem::SelectSyncMap
}; };
// constructor // constructor
FileSystem::FileSystem(const char* name, RequestPort* initPort, status_t* error) FileSystem::FileSystem()
: LazyInitializable(), : fVolumes(),
Referencable(),
fVolumes(),
fVolumeLock(), fVolumeLock(),
fName(name), fName(),
fInitPort(initPort),
fNotificationPort(NULL), fNotificationPort(NULL),
fNotificationThread(-1), fNotificationThread(-1),
fPortPool(), fPortPool(),
fSelectSyncs(NULL), fSelectSyncs(NULL),
fSettings(NULL), fSettings(NULL),
fUserlandServerTeam(-1), fUserlandServerTeam(-1),
fInitialized(false),
fTerminating(false) fTerminating(false)
{ {
if (error)
*error = (fName.GetLength() == 0 ? B_NO_MEMORY : B_OK);
} }
// destructor // destructor
FileSystem::~FileSystem() FileSystem::~FileSystem()
{ {
fTerminating = true; fTerminating = true;
// wait for the notification thread to terminate // wait for the notification thread to terminate
if (fNotificationThread >= 0) { if (fNotificationThread >= 0) {
int32 result; int32 result;
wait_for_thread(fNotificationThread, &result); wait_for_thread(fNotificationThread, &result);
} }
// delete our data structures // delete our data structures
if (fSelectSyncs) { if (fSelectSyncs) {
for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator(); for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
@ -65,6 +62,96 @@ FileSystem::~FileSystem()
delete fSettings; 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 // GetName
const char* const char*
FileSystem::GetName() const FileSystem::GetName() const
@ -85,9 +172,7 @@ FileSystem::Mount(mount_id id, const char* device, uint32 flags,
const char* parameters, Volume** _volume) const char* parameters, Volume** _volume)
{ {
// check initialization and parameters // check initialization and parameters
if (InitCheck() != B_OK) if (!fInitialized || !_volume)
return InitCheck();
if (!_volume)
return B_BAD_VALUE; return B_BAD_VALUE;
// create volume // create volume
@ -232,107 +317,6 @@ FileSystem::IsUserlandServerThread() const
return (info.team == fUserlandServerTeam); 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 // _NotificationThreadEntry
int32 int32
FileSystem::_NotificationThreadEntry(void* data) FileSystem::_NotificationThreadEntry(void* data)

View File

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

View File

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

View File

@ -1,15 +1,17 @@
// UserlandFS.cpp // UserlandFS.cpp
#include "UserlandFS.h"
#include <KernelExport.h> #include <KernelExport.h>
#include "Compatibility.h" #include "Compatibility.h"
#include "Debug.h" #include "Debug.h"
#include "DispatcherDefs.h" #include "DispatcherDefs.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "FileSystemInitializer.h"
#include "KernelDebug.h" #include "KernelDebug.h"
#include "RequestPort.h" #include "RequestPort.h"
#include "Requests.h" #include "Requests.h"
#include "UserlandFS.h"
UserlandFS* UserlandFS::sUserlandFS = NULL; UserlandFS* UserlandFS::sUserlandFS = NULL;
@ -90,34 +92,34 @@ UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem)
return B_BAD_VALUE; return B_BAD_VALUE;
// check, if we do already know this file system, and create it, if not // check, if we do already know this file system, and create it, if not
FileSystem* fileSystem; FileSystemInitializer* fileSystemInitializer;
{ {
FileSystemLocker _(fFileSystems); FileSystemLocker _(fFileSystems);
fileSystem = fFileSystems->Get(name); fileSystemInitializer = fFileSystems->Get(name);
if (fileSystem) { if (fileSystemInitializer) {
fileSystem->AddReference(); fileSystemInitializer->AddReference();
} else { } else {
status_t error; fileSystemInitializer = new(nothrow) FileSystemInitializer(name,
fileSystem = new(nothrow) FileSystem(name, fPort, &error); fPort);
if (!fileSystem) if (!fileSystemInitializer)
return B_NO_MEMORY; return B_NO_MEMORY;
if (error == B_OK)
error = fFileSystems->Put(name, fileSystem); status_t error = fFileSystems->Put(name, fileSystemInitializer);
if (error != B_OK) { if (error != B_OK) {
delete fileSystem; delete fileSystemInitializer;
return error; return error;
} }
} }
} }
// prepare the file system // prepare the file system
status_t error = fileSystem->Access(); status_t error = fileSystemInitializer->Access();
if (error != B_OK) { if (error != B_OK) {
UnregisterFileSystem(fileSystem); _UnregisterFileSystem(name);
return error; return error;
} }
*_fileSystem = fileSystem; *_fileSystem = fileSystemInitializer->GetFileSystem();
return error; return error;
} }
@ -128,22 +130,7 @@ UserlandFS::UnregisterFileSystem(FileSystem* fileSystem)
if (!fileSystem) if (!fileSystem)
return B_BAD_VALUE; return B_BAD_VALUE;
// find the FS and decrement its reference counter return _UnregisterFileSystem(fileSystem->GetName());
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;
} }
// CountFileSystems // CountFileSystems
@ -205,3 +192,29 @@ UserlandFS::_Init()
RETURN_ERROR(error); 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; using UserlandFSUtil::RequestPort;
class FileSystem; class FileSystem;
class FileSystemInitializer;
class UserlandFS { class UserlandFS {
private: private:
@ -35,14 +36,17 @@ public:
int32 CountFileSystems() const; int32 CountFileSystems() const;
private:
status_t _Init();
private: private:
friend class KernelDebug; friend class KernelDebug;
typedef SynchronizedHashMap<String, FileSystem*> FileSystemMap; typedef SynchronizedHashMap<String, FileSystemInitializer*>
FileSystemMap;
typedef AutoLocker<UserlandFS::FileSystemMap> FileSystemLocker; typedef AutoLocker<UserlandFS::FileSystemMap> FileSystemLocker;
private:
status_t _Init();
status_t _UnregisterFileSystem(const char* name);
private:
static UserlandFS* sUserlandFS; static UserlandFS* sUserlandFS;
RequestPort* fPort; RequestPort* fPort;