1// UserlandFS.cpp 2 3#include <KernelExport.h> 4 5#include "AutoLocker.h" 6#include "Compatibility.h" 7#include "Debug.h" 8#include "DispatcherDefs.h" 9#include "FileSystem.h" 10#include "KernelDebug.h" 11#include "RequestPort.h" 12#include "Requests.h" 13#include "UserlandFS.h" 14 15typedef AutoLocker<UserlandFS::FileSystemMap> FileSystemLocker; 16 17UserlandFS* volatile UserlandFS::sUserlandFS = NULL; 18spinlock UserlandFS::sUserlandFSLock = 0; 19vint32 UserlandFS::sMountedFileSystems = 0; 20 21// constructor 22UserlandFS::UserlandFS() 23 : LazyInitializable(), 24 fPort(NULL), 25 fFileSystems(NULL), 26 fDebuggerCommandsAdded(false) 27{ 28 // beware what you do here: the caller holds a spin lock 29} 30 31// destructor 32UserlandFS::~UserlandFS() 33{ 34PRINT(("UserlandFS::~UserlandFS()\n")) 35 if (fPort) { 36 // send a disconnect request 37 RequestAllocator allocator(fPort->GetPort()); 38 UFSDisconnectRequest* request; 39 if (AllocateRequest(allocator, &request) == B_OK) { 40 if (fPort->SendRequest(&allocator) != B_OK) 41 PRINT((" failed to send disconnect request\n")); 42 } else 43 PRINT((" failed to allocate disconnect request\n")); 44 delete fPort; 45 } else 46 PRINT((" no port\n")); 47 48 delete fFileSystems; 49 if (fDebuggerCommandsAdded) 50 KernelDebug::RemoveDebuggerCommands(); 51} 52 53// RegisterUserlandFS 54status_t 55UserlandFS::RegisterUserlandFS(UserlandFS** _userlandFS) 56{ 57 // first check, if there's already an instance 58 bool create = false; 59 60 cpu_status cpuStatus = disable_interrupts(); 61 acquire_spinlock(&sUserlandFSLock); 62 63 if (sUserlandFS) 64 sMountedFileSystems++; 65 else 66 create = true; 67 68 release_spinlock(&sUserlandFSLock); 69 restore_interrupts(cpuStatus); 70 71 // if there's not, create a new 72 status_t error = B_OK; 73 if (create) { 74 // first create an instance 75 // Note, that we can't even construct a LazyInitializable with a 76 // spinlock being held, since it allocates a semaphore, which may 77 // allocate memory, which will acquire a semaphore. 78 UserlandFS* userlandFS = new(nothrow) UserlandFS; 79 if (userlandFS) { 80 // now set the instance unless someone else beat us to it 81 bool deleteInstance = false; 82 83 cpu_status cpuStatus = disable_interrupts(); 84 acquire_spinlock(&sUserlandFSLock); 85 86 sMountedFileSystems++; 87 if (sUserlandFS) 88 deleteInstance = true; 89 else 90 sUserlandFS = userlandFS; 91 92 release_spinlock(&sUserlandFSLock); 93 restore_interrupts(cpuStatus); 94 95 // delete the new instance, if there was one already 96 if (deleteInstance) 97 delete userlandFS; 98 } else 99 error = B_NO_MEMORY; 100 } 101 if (error != B_OK) 102 return error; 103 104 // init the thing, if necessary 105 error = sUserlandFS->Access(); 106 if (error == B_OK) 107 *_userlandFS = sUserlandFS; 108 else 109 UnregisterUserlandFS(); 110 return error; 111} 112 113// UnregisterUserlandFS 114void 115UserlandFS::UnregisterUserlandFS() 116{ 117 cpu_status cpuStatus = disable_interrupts(); 118 acquire_spinlock(&sUserlandFSLock); 119 120 --sMountedFileSystems; 121 UserlandFS* userlandFS = NULL; 122 if (sMountedFileSystems == 0 && sUserlandFS) { 123 userlandFS = sUserlandFS; 124 sUserlandFS = NULL; 125 } 126 127 release_spinlock(&sUserlandFSLock); 128 restore_interrupts(cpuStatus); 129 130 // delete, if the last FS has been unmounted 131 if (userlandFS) { 132 userlandFS->~UserlandFS(); 133 delete[] (uint8*)userlandFS; 134 } 135} 136 137// GetUserlandFS 138UserlandFS* 139UserlandFS::GetUserlandFS() 140{ 141 return sUserlandFS; 142} 143 144// RegisterFileSystem 145status_t 146UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem) 147{ 148 // check initialization and parameters 149 if (InitCheck() != B_OK) 150 return InitCheck(); 151 if (!name || !_fileSystem) 152 return B_BAD_VALUE; 153 // check, if we do already know this file system, and create it, if not 154 FileSystem* fileSystem; 155 { 156 FileSystemLocker _(fFileSystems); 157 fileSystem = fFileSystems->Get(name); 158 if (fileSystem) { 159 fileSystem->AddReference(); 160 } else { 161 status_t error; 162 fileSystem = new(nothrow) FileSystem(name, fPort, &error); 163 if (!fileSystem) 164 return B_NO_MEMORY; 165 if (error == B_OK) 166 error = fFileSystems->Put(name, fileSystem); 167 if (error != B_OK) { 168 delete fileSystem; 169 return error; 170 } 171 } 172 } 173 // prepare the file system 174 status_t error = fileSystem->Access(); 175 if (error != B_OK) { 176 UnregisterFileSystem(fileSystem); 177 return error; 178 } 179 *_fileSystem = fileSystem; 180 return error; 181} 182 183// UnregisterFileSystem 184status_t 185UserlandFS::UnregisterFileSystem(FileSystem* fileSystem) 186{ 187 if (!fileSystem) 188 return B_BAD_VALUE; 189 // find the FS and decrement its reference counter 190 bool deleteFS = false; 191 { 192 FileSystemLocker _(fFileSystems); 193 fileSystem = fFileSystems->Get(fileSystem->GetName()); 194 if (!fileSystem) 195 return B_BAD_VALUE; 196 deleteFS = fileSystem->RemoveReference(); 197 if (deleteFS) 198 fFileSystems->Remove(fileSystem->GetName()); 199 } 200 // delete the FS, if the last reference has been removed 201 if (deleteFS) 202 delete fileSystem; 203 return B_OK; 204} 205 206// CountFileSystems 207int32 208UserlandFS::CountFileSystems() const 209{ 210 return fFileSystems->Size(); 211} 212 213// FirstTimeInit 214status_t 215UserlandFS::FirstTimeInit() 216{ 217 // add debugger commands 218 KernelDebug::AddDebuggerCommands(); 219 fDebuggerCommandsAdded = true; 220 // create file system map 221 fFileSystems = new(nothrow) FileSystemMap; 222 if (!fFileSystems) 223 RETURN_ERROR(B_NO_MEMORY); 224 status_t error = fFileSystems->InitCheck(); 225 if (error != B_OK) 226 RETURN_ERROR(error); 227 // find the dispatcher ports 228 port_id port = find_port(kUserlandFSDispatcherPortName); 229 if (port < 0) 230 RETURN_ERROR(B_ERROR); 231 port_id replyPort = find_port(kUserlandFSDispatcherReplyPortName); 232 if (replyPort < 0) 233 RETURN_ERROR(B_ERROR); 234 // create a reply port 235 // send a connection request 236 error = write_port(port, UFS_DISPATCHER_CONNECT, NULL, 0); 237 if (error != B_OK) 238 RETURN_ERROR(error); 239 // receive the reply 240 int32 replyCode; 241 Port::Info portInfo; 242 ssize_t bytesRead = read_port(replyPort, &replyCode, &portInfo, 243 sizeof(Port::Info)); 244 if (bytesRead < 0) 245 RETURN_ERROR(bytesRead); 246 if (replyCode != UFS_DISPATCHER_CONNECT_ACK) 247 RETURN_ERROR(B_BAD_DATA); 248 if (bytesRead != sizeof(Port::Info)) 249 RETURN_ERROR(B_BAD_DATA); 250 // create a request port 251 fPort = new(nothrow) RequestPort(&portInfo); 252 if (!fPort) 253 RETURN_ERROR(B_NO_MEMORY); 254 if ((error = fPort->InitCheck()) != B_OK) 255 RETURN_ERROR(error); 256 RETURN_ERROR(error); 257} 258 259