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