1 // FileSystem.cpp 2 3 #include "AutoLocker.h" 4 #include "Compatibility.h" 5 #include "Debug.h" 6 #include "FileSystem.h" 7 #include "HashMap.h" 8 #include "KernelRequestHandler.h" 9 #include "PortReleaser.h" 10 #include "RequestAllocator.h" 11 #include "Requests.h" 12 #include "Settings.h" 13 #include "SingleReplyRequestHandler.h" 14 #include "Volume.h" 15 16 // The time after which the notification thread times out at the port and 17 // restarts the loop. Of interest only when the FS is deleted. It is the 18 // maximal time the destructor has to wait for the thread. 19 static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms 20 21 // SelectSyncMap 22 struct FileSystem::SelectSyncMap 23 : public SynchronizedHashMap<HashKey32<selectsync*>, int32*> { 24 }; 25 26 // constructor 27 FileSystem::FileSystem() 28 : fVolumes(), 29 fVolumeLock(), 30 fName(), 31 fNotificationPort(NULL), 32 fNotificationThread(-1), 33 fPortPool(), 34 fSelectSyncs(NULL), 35 fSettings(NULL), 36 fUserlandServerTeam(-1), 37 fInitialized(false), 38 fTerminating(false) 39 { 40 } 41 42 // destructor 43 FileSystem::~FileSystem() 44 { 45 fTerminating = true; 46 47 // wait for the notification thread to terminate 48 if (fNotificationThread >= 0) { 49 int32 result; 50 wait_for_thread(fNotificationThread, &result); 51 } 52 53 // delete our data structures 54 if (fSelectSyncs) { 55 for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator(); 56 it.HasNext();) { 57 SelectSyncMap::Entry entry = it.Next(); 58 delete entry.value; 59 } 60 delete fSelectSyncs; 61 } 62 delete fSettings; 63 } 64 65 // Init 66 status_t 67 FileSystem::Init(const char* name, Port::Info* infos, int32 count, 68 const FSCapabilities& capabilities) 69 { 70 PRINT(("FileSystem::Init(\"%s\", %p, %ld)\n", name, infos, count)); 71 capabilities.Dump(); 72 73 // check parameters 74 if (!name || !infos || count < 2) 75 RETURN_ERROR(B_BAD_VALUE); 76 77 // set the name 78 if (!fName.SetTo(name)) 79 return B_NO_MEMORY; 80 81 fCapabilities = capabilities; 82 83 // create the select sync entry map 84 fSelectSyncs = new(nothrow) SelectSyncMap; 85 if (!fSelectSyncs) 86 return B_NO_MEMORY; 87 88 // create the request ports 89 // the notification port 90 fNotificationPort = new(nothrow) RequestPort(infos); 91 if (!fNotificationPort) 92 RETURN_ERROR(B_NO_MEMORY); 93 status_t error = fNotificationPort->InitCheck(); 94 if (error != B_OK) 95 return error; 96 97 // the other request ports 98 for (int32 i = 1; i < count; i++) { 99 RequestPort* port = new(nothrow) RequestPort(infos + i); 100 if (!port) 101 RETURN_ERROR(B_NO_MEMORY); 102 error = port->InitCheck(); 103 if (error == B_OK) 104 error = fPortPool.AddPort(port); 105 if (error != B_OK) { 106 delete port; 107 RETURN_ERROR(error); 108 } 109 } 110 111 // get the userland team 112 port_info portInfo; 113 error = get_port_info(infos[0].owner_port, &portInfo); 114 if (error != B_OK) 115 RETURN_ERROR(error); 116 fUserlandServerTeam = portInfo.team; 117 118 // print some info about the userland team 119 D( 120 PRINT((" userland team is: %ld\n", fUserlandServerTeam)); 121 int32 cookie = 0; 122 thread_info threadInfo; 123 while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo) 124 == B_OK) { 125 PRINT((" userland thread: %ld: `%s'\n", threadInfo.thread, 126 threadInfo.name)); 127 } 128 ); 129 130 // load the settings 131 fSettings = new(nothrow) Settings; 132 if (fSettings) { 133 status_t settingsError = fSettings->SetTo(fName.GetString()); 134 if (settingsError != B_OK) { 135 PRINT(("Failed to load settings: %s\n", strerror(settingsError))); 136 delete fSettings; 137 fSettings = NULL; 138 } else 139 fSettings->Dump(); 140 } else 141 ERROR(("Failed to allocate settings.\n")); 142 143 // spawn the notification thread 144 #if USER 145 fNotificationThread = spawn_thread(_NotificationThreadEntry, 146 "UFS notification thread", B_NORMAL_PRIORITY, this); 147 #else 148 fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry, 149 "UFS notification thread", B_NORMAL_PRIORITY, this); 150 #endif 151 if (fNotificationThread < 0) 152 RETURN_ERROR(fNotificationThread); 153 resume_thread(fNotificationThread); 154 155 fInitialized = (error == B_OK); 156 RETURN_ERROR(error); 157 } 158 159 // GetName 160 const char* 161 FileSystem::GetName() const 162 { 163 return fName.GetString(); 164 } 165 166 // GetCapabilities 167 const FSCapabilities& 168 FileSystem::GetCapabilities() const 169 { 170 return fCapabilities; 171 } 172 173 // GetPortPool 174 RequestPortPool* 175 FileSystem::GetPortPool() 176 { 177 return &fPortPool; 178 } 179 180 // Mount 181 status_t 182 FileSystem::Mount(mount_id id, const char* device, uint32 flags, 183 const char* parameters, Volume** _volume) 184 { 185 // check initialization and parameters 186 if (!fInitialized || !_volume) 187 return B_BAD_VALUE; 188 189 // create volume 190 Volume* volume = new(nothrow) Volume(this, id); 191 if (!volume) 192 return B_NO_MEMORY; 193 194 // add volume to the volume list 195 fVolumeLock.Lock(); 196 status_t error = fVolumes.PushBack(volume); 197 fVolumeLock.Unlock(); 198 if (error != B_OK) 199 return error; 200 201 // mount volume 202 error = volume->Mount(device, flags, parameters); 203 if (error != B_OK) { 204 fVolumeLock.Lock(); 205 fVolumes.Remove(volume); 206 fVolumeLock.Unlock(); 207 volume->RemoveReference(); 208 return error; 209 } 210 211 *_volume = volume; 212 return error; 213 } 214 215 // Initialize 216 /*status_t 217 FileSystem::Initialize(const char* deviceName, const char* parameters, 218 size_t len) 219 { 220 // get a free port 221 RequestPort* port = fPortPool.AcquirePort(); 222 if (!port) 223 return B_ERROR; 224 PortReleaser _(&fPortPool, port); 225 // prepare the request 226 RequestAllocator allocator(port->GetPort()); 227 MountVolumeRequest* request; 228 status_t error = AllocateRequest(allocator, &request); 229 if (error != B_OK) 230 return error; 231 error = allocator.AllocateString(request->device, deviceName); 232 if (error == B_OK) 233 error = allocator.AllocateData(request->parameters, parameters, len, 1); 234 if (error != B_OK) 235 return error; 236 // send the request 237 SingleReplyRequestHandler handler(MOUNT_VOLUME_REPLY); 238 InitializeVolumeReply* reply; 239 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 240 if (error != B_OK) 241 return error; 242 RequestReleaser requestReleaser(port, reply); 243 // process the reply 244 if (reply->error != B_OK) 245 return reply->error; 246 return error; 247 }*/ 248 249 // VolumeUnmounted 250 void 251 FileSystem::VolumeUnmounted(Volume* volume) 252 { 253 fVolumeLock.Lock(); 254 fVolumes.Remove(volume); 255 fVolumeLock.Unlock(); 256 } 257 258 // GetVolume 259 Volume* 260 FileSystem::GetVolume(mount_id id) 261 { 262 AutoLocker<Locker> _(fVolumeLock); 263 for (Vector<Volume*>::Iterator it = fVolumes.Begin(); 264 it != fVolumes.End(); 265 it++) { 266 Volume* volume = *it; 267 if (volume->GetID() == id) { 268 volume->AddReference(); 269 return volume; 270 } 271 } 272 return NULL; 273 } 274 275 // GetIOCtlInfo 276 const IOCtlInfo* 277 FileSystem::GetIOCtlInfo(int command) const 278 { 279 return (fSettings ? fSettings->GetIOCtlInfo(command) : NULL); 280 } 281 282 // AddSelectSyncEntry 283 status_t 284 FileSystem::AddSelectSyncEntry(selectsync* sync) 285 { 286 AutoLocker<SelectSyncMap> _(fSelectSyncs); 287 int32* count = fSelectSyncs->Get(sync); 288 if (!count) { 289 count = new(nothrow) int32(0); 290 if (!count) 291 return B_NO_MEMORY; 292 status_t error = fSelectSyncs->Put(sync, count); 293 if (error != B_OK) { 294 delete count; 295 return error; 296 } 297 } 298 (*count)++; 299 return B_OK; 300 } 301 302 // RemoveSelectSyncEntry 303 void 304 FileSystem::RemoveSelectSyncEntry(selectsync* sync) 305 { 306 AutoLocker<SelectSyncMap> _(fSelectSyncs); 307 if (int32* count = fSelectSyncs->Get(sync)) { 308 if (--(*count) <= 0) { 309 fSelectSyncs->Remove(sync); 310 delete count; 311 } 312 } 313 } 314 315 // KnowsSelectSyncEntry 316 bool 317 FileSystem::KnowsSelectSyncEntry(selectsync* sync) 318 { 319 return fSelectSyncs->ContainsKey(sync); 320 } 321 322 // IsUserlandServerThread 323 bool 324 FileSystem::IsUserlandServerThread() const 325 { 326 thread_info info; 327 get_thread_info(find_thread(NULL), &info); 328 return (info.team == fUserlandServerTeam); 329 } 330 331 // _NotificationThreadEntry 332 int32 333 FileSystem::_NotificationThreadEntry(void* data) 334 { 335 return ((FileSystem*)data)->_NotificationThread(); 336 } 337 338 // _NotificationThread 339 int32 340 FileSystem::_NotificationThread() 341 { 342 // process the notification requests until the FS is deleted 343 while (!fTerminating) { 344 if (fNotificationPort->InitCheck() != B_OK) 345 return fNotificationPort->InitCheck(); 346 KernelRequestHandler handler(this, NO_REQUEST); 347 fNotificationPort->HandleRequests(&handler, NULL, 348 kNotificationRequestTimeout); 349 } 350 // We eat all remaining notification requests, so that they aren't 351 // presented to the file system, when it is mounted next time. 352 // TODO: We should probably use a special handler that sends an ack reply, 353 // but ignores the requests otherwise. 354 KernelRequestHandler handler(this, NO_REQUEST); 355 fNotificationPort->HandleRequests(&handler, NULL, 0); 356 return 0; 357 } 358 359