diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp index a5e453a7d9..21d2a22645 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp @@ -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) diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h index cda97242fe..697bda55c4 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h @@ -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 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; }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp new file mode 100644 index 0000000000..adf78984f2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp @@ -0,0 +1,76 @@ +// FileSystemInitializer.cpp + +#include "FileSystemInitializer.h" + +#include + +#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; +} diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h new file mode 100644 index 0000000000..9a177ca7da --- /dev/null +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile index 0588ba819b..0865b1f651 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile @@ -32,6 +32,7 @@ KernelAddon userlandfs userlandfs_ioctl.cpp FileSystem.cpp + FileSystemInitializer.cpp kernel_interface.cpp KernelDebug.cpp KernelRequestHandler.cpp diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelDebug.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelDebug.cpp index ae443549ce..20217cb339 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelDebug.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelDebug.cpp @@ -1,10 +1,12 @@ // KernelDebug.cpp +#include "KernelDebug.h" + #include #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 KDebugFSMap; + typedef HashMap 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; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp index 03eac5ba0b..94b94b70ca 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.cpp @@ -1,15 +1,17 @@ // UserlandFS.cpp +#include "UserlandFS.h" + #include #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; +} diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h index 9a48f96341..1c249e048d 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/UserlandFS.h @@ -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 FileSystemMap; + typedef SynchronizedHashMap + FileSystemMap; typedef AutoLocker FileSystemLocker; +private: + status_t _Init(); + status_t _UnregisterFileSystem(const char* name); + +private: static UserlandFS* sUserlandFS; RequestPort* fPort;