1 // VolumeManager.cpp 2 3 #include <HashMap.h> 4 #include <HashSet.h> 5 #include <util/DoublyLinkedList.h> 6 7 #include "DebugSupport.h" 8 #include "QueryManager.h" 9 #include "RootVolume.h" 10 #include "VolumeEvent.h" 11 #include "VolumeManager.h" 12 13 // VolumeSet 14 #ifdef B_HAIKU_64_BIT 15 struct VolumeManager::VolumeSet : HashSet<HashKey64<Volume*> > { 16 }; 17 #else 18 struct VolumeManager::VolumeSet : HashSet<HashKey32<Volume*> > { 19 }; 20 #endif 21 22 // NodeIDVolumeMap 23 struct VolumeManager::NodeIDVolumeMap : HashMap<HashKey64<vnode_id>, Volume*> { 24 }; 25 26 // VolumeEventQueue 27 class VolumeManager::VolumeEventQueue { 28 public: 29 VolumeEventQueue() 30 : fLock("volume event queue"), 31 fCounterSem(-1) 32 { 33 fCounterSem = create_sem(0, "volume event count"); 34 #if !USER 35 if (fCounterSem >= 0) 36 set_sem_owner(fCounterSem, B_SYSTEM_TEAM); 37 #endif 38 } 39 40 ~VolumeEventQueue() 41 { 42 Close(); 43 } 44 45 status_t InitCheck() const 46 { 47 if (fCounterSem < 0) 48 return fCounterSem; 49 return B_OK; 50 } 51 52 void Close() 53 { 54 AutoLocker<Locker> _(fLock); 55 if (fCounterSem >= 0) { 56 delete_sem(fCounterSem); 57 fCounterSem = -1; 58 } 59 60 while (VolumeEvent* event = fEvents.First()) { 61 fEvents.Remove(event); 62 event->ReleaseReference(); 63 } 64 } 65 66 void Push(VolumeEvent* event) 67 { 68 if (!event) 69 return; 70 71 AutoLocker<Locker> _(fLock); 72 if (fCounterSem < 0) 73 return; 74 fEvents.Insert(event); 75 event->AcquireReference(); 76 release_sem(fCounterSem); 77 } 78 79 VolumeEvent* Pop() 80 { 81 status_t error; 82 do { 83 error = acquire_sem(fCounterSem); 84 } while (error == B_INTERRUPTED); 85 if (error != B_OK) 86 return NULL; 87 88 AutoLocker<Locker> _(fLock); 89 if (VolumeEvent* event = fEvents.First()) { 90 fEvents.Remove(event); 91 return event; 92 } 93 94 return NULL; 95 } 96 97 private: 98 Locker fLock; 99 sem_id fCounterSem; 100 DoublyLinkedList<VolumeEvent> fEvents; 101 }; 102 103 104 // constructor 105 VolumeManager::VolumeManager(nspace_id id, uint32 flags) 106 : Locker("volume manager"), 107 fID(id), 108 fMountFlags(flags), 109 fMountUID(0), 110 fMountGID(0), 111 fRootID(-1), 112 fNextNodeID(2), 113 fQueryManager(NULL), 114 fVolumes(NULL), 115 fNodeIDs2Volumes(NULL), 116 fVolumeEvents(NULL), 117 fEventDeliverer(-1) 118 { 119 } 120 121 // destructor 122 VolumeManager::~VolumeManager() 123 { 124 if (fVolumeEvents) 125 fVolumeEvents->Close(); 126 if (fEventDeliverer >= 0) { 127 int32 result; 128 wait_for_thread(fEventDeliverer, &result); 129 } 130 delete fVolumeEvents; 131 delete fVolumes; 132 delete fNodeIDs2Volumes; 133 delete fQueryManager; 134 } 135 136 // MountRootVolume 137 status_t 138 VolumeManager::MountRootVolume(const char* device, 139 const char* parameters, int32 len, Volume** volume) 140 { 141 // Store the uid/gid of the mounting user -- when running in userland 142 // this is always the owner of the UserlandFS server, but we can't help 143 // that. 144 fMountUID = geteuid(); 145 fMountGID = getegid(); 146 147 // create the query manager 148 fQueryManager = new(std::nothrow) QueryManager(this); 149 if (!fQueryManager) 150 return B_NO_MEMORY; 151 status_t error = fQueryManager->Init(); 152 if (error != B_OK) 153 return error; 154 155 // create volumes set 156 fVolumes = new(std::nothrow) VolumeSet; 157 if (!fVolumes) 158 return B_NO_MEMORY; 159 error = fVolumes->InitCheck(); 160 if (error != B_OK) 161 return error; 162 163 // create node ID to volumes map 164 fNodeIDs2Volumes = new(std::nothrow) NodeIDVolumeMap; 165 if (!fNodeIDs2Volumes) 166 return B_NO_MEMORY; 167 error = fNodeIDs2Volumes->InitCheck(); 168 if (error != B_OK) 169 return error; 170 171 // create the volume event queue 172 fVolumeEvents = new VolumeEventQueue; 173 if (!fVolumeEvents) 174 return B_NO_MEMORY; 175 error = fVolumeEvents->InitCheck(); 176 if (error != B_OK) 177 return error; 178 179 // spawn the event deliverer 180 #if USER 181 fEventDeliverer = spawn_thread(&_EventDelivererEntry, 182 "volume event deliverer", B_NORMAL_PRIORITY, this); 183 #else 184 fEventDeliverer = spawn_kernel_thread(&_EventDelivererEntry, 185 "volume event deliverer", B_NORMAL_PRIORITY, this); 186 #endif 187 if (fEventDeliverer < 0) 188 return fEventDeliverer; 189 190 // create the root volume 191 RootVolume* rootVolume = new(std::nothrow) RootVolume(this); 192 if (!rootVolume) 193 return B_NO_MEMORY; 194 error = rootVolume->Init(); 195 if (error != B_OK) { 196 delete rootVolume; 197 return error; 198 } 199 fRootID = rootVolume->GetRootID(); 200 201 // add the root volume 202 error = AddVolume(rootVolume); 203 if (error != B_OK) { 204 delete rootVolume; 205 return error; 206 } 207 208 // mount the root volume 209 error = rootVolume->Mount(device, fMountFlags, (const char*)parameters, 210 len); 211 if (error != B_OK) { 212 rootVolume->SetUnmounting(true); 213 PutVolume(rootVolume); 214 return error; 215 } 216 rootVolume->AcquireReference(); 217 *volume = rootVolume; 218 219 // run the event deliverer 220 resume_thread(fEventDeliverer); 221 222 return B_OK; 223 } 224 225 // UnmountRootVolume 226 void 227 VolumeManager::UnmountRootVolume() 228 { 229 if (Volume* rootVolume = GetRootVolume()) { 230 rootVolume->SetUnmounting(true); 231 PutVolume(rootVolume); 232 } else { 233 ERROR(("VolumeManager::UnmountRootVolume(): ERROR: Couldn't get " 234 "root volume!\n")); 235 } 236 } 237 238 // GetQueryManager 239 QueryManager* 240 VolumeManager::GetQueryManager() const 241 { 242 return fQueryManager; 243 } 244 245 // GetRootVolume 246 Volume* 247 VolumeManager::GetRootVolume() 248 { 249 return GetVolume(fRootID); 250 } 251 252 // AddVolume 253 // 254 // The caller must have a reference to the volume and retains it. 255 status_t 256 VolumeManager::AddVolume(Volume* volume) 257 { 258 if (!volume) 259 return B_BAD_VALUE; 260 261 // check, if it already exists 262 AutoLocker<Locker> _(this); 263 if (fVolumes->Contains(volume)) 264 return B_BAD_VALUE; 265 266 // add the volume 267 return fVolumes->Add(volume); 268 } 269 270 // GetVolume 271 Volume* 272 VolumeManager::GetVolume(vnode_id nodeID) 273 { 274 AutoLocker<Locker> _(this); 275 Volume* volume = fNodeIDs2Volumes->Get(nodeID); 276 if (volume && GetVolume(volume)) 277 return volume; 278 return NULL; 279 } 280 281 // GetVolume 282 Volume* 283 VolumeManager::GetVolume(Volume* volume) 284 { 285 if (!volume) 286 return NULL; 287 288 AutoLocker<Locker> _(this); 289 if (fVolumes->Contains(volume)) { 290 // TODO: Any restrictions regarding volumes about to be removed? 291 volume->AcquireReference(); 292 return volume; 293 } 294 return NULL; 295 } 296 297 // PutVolume 298 // 299 // The VolumeManager must not be locked, when this method is invoked. 300 void 301 VolumeManager::PutVolume(Volume* volume) 302 { 303 if (!volume) 304 return; 305 306 // If the volume is marked unmounting and is not yet marked removed, we 307 // initiate the removal process. 308 { 309 AutoLocker<Locker> locker(this); 310 //PRINT(("VolumeManager::PutVolume(%p): reference count before: %ld\n", 311 //volume, volume->CountReferences())); 312 if (volume->IsUnmounting() && !volume->IsRemoved()) { 313 //PRINT(("VolumeManager::PutVolume(%p): Volume connection broken, marking " 314 //"removed and removing all nodes.\n", volume)); 315 // mark removed 316 volume->MarkRemoved(); 317 318 // get parent volume 319 Volume* parentVolume = volume->GetParentVolume(); 320 if (parentVolume && !GetVolume(parentVolume)) 321 parentVolume = NULL; 322 323 locker.Unlock(); 324 325 // prepare to unmount 326 volume->PrepareToUnmount(); 327 328 // remove from parent volume 329 if (parentVolume) { 330 parentVolume->RemoveChildVolume(volume); 331 PutVolume(parentVolume); 332 } 333 } 334 } 335 336 // If the volume is marked removed and it's reference count drops to 0, 337 // we unmount and delete it. 338 { 339 AutoLocker<Locker> locker(this); 340 if (volume->ReleaseReference() && volume->IsRemoved()) { 341 PRINT("VolumeManager::PutVolume(%p): Removed volume " 342 "unreferenced. Unmounting...\n", volume); 343 // remove from volume set -- now noone can get a reference to it 344 // anymore 345 fVolumes->Remove(volume); 346 347 locker.Unlock(); 348 349 // unmount and delete the volume 350 // TODO: At some point all the volume's node IDs have to be removed from 351 // fNodeIDs2Volumes. For the time being we expect the volume to do that itself 352 // in Unmount(). 353 volume->Unmount(); 354 delete volume; 355 } 356 } 357 } 358 359 // NewNodeID 360 vnode_id 361 VolumeManager::NewNodeID(Volume* volume) 362 { 363 if (!volume) 364 return B_BAD_VALUE; 365 366 AutoLocker<Locker> _(this); 367 vnode_id nodeID = fNextNodeID; 368 status_t error = fNodeIDs2Volumes->Put(nodeID, volume); 369 if (error != B_OK) 370 return error; 371 return fNextNodeID++; 372 } 373 374 // RemoveNodeID 375 void 376 VolumeManager::RemoveNodeID(vnode_id nodeID) 377 { 378 AutoLocker<Locker> _(this); 379 fNodeIDs2Volumes->Remove(nodeID); 380 } 381 382 // SendVolumeEvent 383 void 384 VolumeManager::SendVolumeEvent(VolumeEvent* event) 385 { 386 if (!event) 387 return; 388 389 fVolumeEvents->Push(event); 390 } 391 392 // _EventDelivererEntry 393 int32 394 VolumeManager::_EventDelivererEntry(void* data) 395 { 396 return ((VolumeManager*)data)->_EventDeliverer(); 397 } 398 399 // _EventDeliverer 400 int32 401 VolumeManager::_EventDeliverer() 402 { 403 while (VolumeEvent* event = fVolumeEvents->Pop()) { 404 if (Volume* volume = GetVolume(event->GetTarget())) { 405 volume->HandleEvent(event); 406 PutVolume(volume); 407 } 408 event->ReleaseReference(); 409 } 410 return 0; 411 } 412 413