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 14struct VolumeManager::VolumeSet : HashSet<HashKeyPointer<Volume*> > { 15}; 16 17// NodeIDVolumeMap 18struct VolumeManager::NodeIDVolumeMap : HashMap<HashKey64<vnode_id>, Volume*> { 19}; 20 21// VolumeEventQueue 22class VolumeManager::VolumeEventQueue { 23public: 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 92private: 93 Locker fLock; 94 sem_id fCounterSem; 95 DoublyLinkedList<VolumeEvent> fEvents; 96}; 97 98 99// constructor 100VolumeManager::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 117VolumeManager::~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 132status_t 133VolumeManager::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 221void 222VolumeManager::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 234QueryManager* 235VolumeManager::GetQueryManager() const 236{ 237 return fQueryManager; 238} 239 240// GetRootVolume 241Volume* 242VolumeManager::GetRootVolume() 243{ 244 return GetVolume(fRootID); 245} 246 247// AddVolume 248// 249// The caller must have a reference to the volume and retains it. 250status_t 251VolumeManager::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 266Volume* 267VolumeManager::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 277Volume* 278VolumeManager::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. 295void 296VolumeManager::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 " 337 "unreferenced. 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 355vnode_id 356VolumeManager::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 370void 371VolumeManager::RemoveNodeID(vnode_id nodeID) 372{ 373 AutoLocker<Locker> _(this); 374 fNodeIDs2Volumes->Remove(nodeID); 375} 376 377// SendVolumeEvent 378void 379VolumeManager::SendVolumeEvent(VolumeEvent* event) 380{ 381 if (!event) 382 return; 383 384 fVolumeEvents->Push(event); 385} 386 387// _EventDelivererEntry 388int32 389VolumeManager::_EventDelivererEntry(void* data) 390{ 391 return ((VolumeManager*)data)->_EventDeliverer(); 392} 393 394// _EventDeliverer 395int32 396VolumeManager::_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