1 /* 2 * Copyright 2001-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Volume.h" 8 9 #include <util/AutoLock.h> 10 11 #include <fs/node_monitor.h> 12 #include <Notifications.h> 13 14 #include "AutoLocker.h" 15 #include "Compatibility.h" 16 #include "Debug.h" 17 #include "FileSystem.h" 18 #include "HashMap.h" 19 #include "kernel_interface.h" 20 #include "KernelRequestHandler.h" 21 #include "PortReleaser.h" 22 #include "RequestAllocator.h" 23 #include "Requests.h" 24 #include "Settings.h" 25 #include "SingleReplyRequestHandler.h" 26 27 28 // The time after which the notification thread times out at the port and 29 // restarts the loop. Of interest only when the FS is deleted. It is the 30 // maximal time the destructor has to wait for the thread. 31 static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms 32 33 34 // #pragma mark - SelectSyncMap 35 36 37 struct FileSystem::SelectSyncMap 38 : public SynchronizedHashMap<HashKeyPointer<selectsync*>, int32*, Locker> { 39 }; 40 41 42 // #pragma mark - NodeListenerKey 43 44 45 struct FileSystem::NodeListenerKey { 46 NodeListenerKey(void* clientListener, dev_t device, ino_t node) 47 : 48 fClientListener(clientListener), 49 fDevice(device), 50 fNode(node) 51 { 52 } 53 54 void* ClientListener() const 55 { 56 return fClientListener; 57 } 58 59 dev_t Device() const 60 { 61 return fDevice; 62 } 63 64 ino_t Node() const 65 { 66 return fNode; 67 } 68 69 uint32 HashValue() const 70 { 71 return (uint32)(addr_t)fClientListener ^ (uint32)fDevice 72 ^ (uint32)fNode ^ (uint32)(fNode >> 32); 73 } 74 75 bool operator==(const NodeListenerKey& other) const 76 { 77 return fClientListener == other.fClientListener 78 && fDevice == other.fDevice && fNode == other.fNode; 79 } 80 81 protected: 82 void* fClientListener; 83 dev_t fDevice; 84 ino_t fNode; 85 }; 86 87 88 // #pragma mark - NodeListenerProxy 89 90 91 struct FileSystem::NodeListenerProxy : NodeListenerKey, NotificationListener { 92 NodeListenerProxy(FileSystem* fileSystem, void* clientListener, 93 dev_t device, ino_t node) 94 : 95 NodeListenerKey(clientListener, device, node), 96 fFileSystem(fileSystem) 97 { 98 } 99 100 virtual void EventOccurred(NotificationService& service, 101 const KMessage* event) 102 { 103 fFileSystem->_NodeListenerEventOccurred(this, event); 104 } 105 106 NodeListenerProxy*& HashTableLink() 107 { 108 return fHashTableLink; 109 } 110 111 status_t StartListening(uint32 flags) 112 { 113 return add_node_listener(fDevice, fNode, flags, *this); 114 } 115 116 status_t StopListening() 117 { 118 return remove_node_listener(fDevice, fNode, *this); 119 } 120 121 private: 122 FileSystem* fFileSystem; 123 NodeListenerProxy* fHashTableLink; 124 }; 125 126 127 // #pragma mark - NodeListenerHashDefinition 128 129 130 struct FileSystem::NodeListenerHashDefinition { 131 typedef NodeListenerKey KeyType; 132 typedef NodeListenerProxy ValueType; 133 134 size_t HashKey(const NodeListenerKey& key) const 135 { 136 return key.HashValue(); 137 } 138 139 size_t Hash(const NodeListenerProxy* value) const 140 { 141 return value->HashValue(); 142 } 143 144 bool Compare(const NodeListenerKey& key, 145 const NodeListenerProxy* value) const 146 { 147 return key == *value; 148 } 149 150 NodeListenerProxy*& GetLink(NodeListenerProxy* value) const 151 { 152 return value->HashTableLink(); 153 } 154 }; 155 156 157 // #pragma mark - FileSystem 158 159 160 // constructor 161 FileSystem::FileSystem() 162 : 163 fVolumes(), 164 fName(), 165 fTeam(-1), 166 fNotificationPort(NULL), 167 fNotificationThread(-1), 168 fPortPool(), 169 fSelectSyncs(NULL), 170 fSettings(NULL), 171 fUserlandServerTeam(-1), 172 fInitialized(false), 173 fTerminating(false) 174 { 175 mutex_init(&fVolumeLock, "userlandfs volumes"); 176 mutex_init(&fVNodeOpsLock, "userlandfs vnode ops"); 177 mutex_init(&fNodeListenersLock, "userlandfs node listeners"); 178 } 179 180 // destructor 181 FileSystem::~FileSystem() 182 { 183 fTerminating = true; 184 185 // wait for the notification thread to terminate 186 if (fNotificationThread >= 0) { 187 int32 result; 188 wait_for_thread(fNotificationThread, &result); 189 } 190 191 // delete our data structures 192 if (fNodeListeners != NULL) { 193 MutexLocker nodeListenersLocker(fNodeListenersLock); 194 NodeListenerProxy* proxy = fNodeListeners->Clear(true); 195 while (proxy != NULL) { 196 NodeListenerProxy* next = proxy->HashTableLink(); 197 proxy->StopListening(); 198 delete proxy; 199 proxy = next; 200 } 201 } 202 203 if (fSelectSyncs) { 204 for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator(); 205 it.HasNext();) { 206 SelectSyncMap::Entry entry = it.Next(); 207 delete entry.value; 208 } 209 delete fSelectSyncs; 210 } 211 212 delete fSettings; 213 214 // delete vnode ops vectors -- there shouldn't be any left, though 215 VNodeOps* ops = fVNodeOps.Clear(); 216 int32 count = 0; 217 while (ops != NULL) { 218 count++; 219 VNodeOps* next = ops->hash_link; 220 free(ops); 221 ops = next; 222 } 223 if (count > 0) 224 WARN(("Deleted %" B_PRId32 " vnode ops vectors!\n", count)); 225 226 227 mutex_destroy(&fVolumeLock); 228 mutex_destroy(&fVNodeOpsLock); 229 mutex_destroy(&fNodeListenersLock); 230 } 231 232 // Init 233 status_t 234 FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count, 235 const FSCapabilities& capabilities) 236 { 237 PRINT(("FileSystem::Init(\"%s\", %p, %" B_PRId32 ")\n", name, infos, 238 count)); 239 capabilities.Dump(); 240 241 // check parameters 242 if (!name || !infos || count < 2) 243 RETURN_ERROR(B_BAD_VALUE); 244 245 // set the name 246 if (!fName.SetTo(name)) 247 return B_NO_MEMORY; 248 249 // init VNodeOps map 250 status_t error = fVNodeOps.Init(); 251 if (error != B_OK) 252 return error; 253 254 fTeam = team; 255 fCapabilities = capabilities; 256 257 // create the select sync entry map 258 fSelectSyncs = new(nothrow) SelectSyncMap; 259 if (!fSelectSyncs) 260 return B_NO_MEMORY; 261 262 // create the node listener proxy map 263 fNodeListeners = new(std::nothrow) NodeListenerMap; 264 if (fNodeListeners == NULL || fNodeListeners->Init() != B_OK) 265 return B_NO_MEMORY; 266 267 // create the request ports 268 // the notification port 269 fNotificationPort = new(nothrow) RequestPort(infos); 270 if (!fNotificationPort) 271 RETURN_ERROR(B_NO_MEMORY); 272 error = fNotificationPort->InitCheck(); 273 if (error != B_OK) 274 return error; 275 276 // the other request ports 277 for (int32 i = 1; i < count; i++) { 278 RequestPort* port = new(nothrow) RequestPort(infos + i); 279 if (!port) 280 RETURN_ERROR(B_NO_MEMORY); 281 error = port->InitCheck(); 282 if (error == B_OK) 283 error = fPortPool.AddPort(port); 284 if (error != B_OK) { 285 delete port; 286 RETURN_ERROR(error); 287 } 288 } 289 290 // get the userland team 291 port_info portInfo; 292 error = get_port_info(infos[0].owner_port, &portInfo); 293 if (error != B_OK) 294 RETURN_ERROR(error); 295 fUserlandServerTeam = portInfo.team; 296 297 // print some info about the userland team 298 D( 299 PRINT((" userland team is: %" B_PRId32 "\n", fUserlandServerTeam)); 300 int32 cookie = 0; 301 thread_info threadInfo; 302 while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo) 303 == B_OK) { 304 PRINT((" userland thread: %" B_PRId32 ": `%s'\n", 305 threadInfo.thread, threadInfo.name)); 306 } 307 ); 308 309 // load the settings 310 fSettings = new(nothrow) Settings; 311 if (fSettings) { 312 status_t settingsError = fSettings->SetTo(fName.GetString()); 313 if (settingsError != B_OK) { 314 PRINT(("Failed to load settings: %s\n", strerror(settingsError))); 315 delete fSettings; 316 fSettings = NULL; 317 } else 318 fSettings->Dump(); 319 } else 320 ERROR(("Failed to allocate settings.\n")); 321 322 // spawn the notification thread 323 #if USER 324 fNotificationThread = spawn_thread(_NotificationThreadEntry, 325 "UFS notification thread", B_NORMAL_PRIORITY, this); 326 #else 327 fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry, 328 "UFS notification thread", B_NORMAL_PRIORITY, this); 329 #endif 330 if (fNotificationThread < 0) 331 RETURN_ERROR(fNotificationThread); 332 resume_thread(fNotificationThread); 333 334 fInitialized = (error == B_OK); 335 RETURN_ERROR(error); 336 } 337 338 // GetName 339 const char* 340 FileSystem::GetName() const 341 { 342 return fName.GetString(); 343 } 344 345 // GetCapabilities 346 const FSCapabilities& 347 FileSystem::GetCapabilities() const 348 { 349 return fCapabilities; 350 } 351 352 // GetPortPool 353 RequestPortPool* 354 FileSystem::GetPortPool() 355 { 356 return &fPortPool; 357 } 358 359 // Mount 360 status_t 361 FileSystem::Mount(fs_volume* fsVolume, const char* device, uint32 flags, 362 const char* parameters, Volume** _volume) 363 { 364 // check initialization and parameters 365 if (!fInitialized || !_volume) 366 return B_BAD_VALUE; 367 368 // create volume 369 Volume* volume = new(nothrow) Volume(this, fsVolume); 370 if (!volume) 371 return B_NO_MEMORY; 372 373 // add volume to the volume list 374 MutexLocker locker(fVolumeLock); 375 status_t error = fVolumes.PushBack(volume); 376 locker.Unlock(); 377 if (error != B_OK) 378 return error; 379 380 // mount volume 381 error = volume->Mount(device, flags, parameters); 382 if (error != B_OK) { 383 MutexLocker locker(fVolumeLock); 384 fVolumes.Remove(volume); 385 locker.Unlock(); 386 volume->ReleaseReference(); 387 return error; 388 } 389 390 *_volume = volume; 391 return error; 392 } 393 394 // Initialize 395 /*status_t 396 FileSystem::Initialize(const char* deviceName, const char* parameters, 397 size_t len) 398 { 399 // get a free port 400 RequestPort* port = fPortPool.AcquirePort(); 401 if (!port) 402 return B_ERROR; 403 PortReleaser _(&fPortPool, port); 404 // prepare the request 405 RequestAllocator allocator(port->GetPort()); 406 MountVolumeRequest* request; 407 status_t error = AllocateRequest(allocator, &request); 408 if (error != B_OK) 409 return error; 410 error = allocator.AllocateString(request->device, deviceName); 411 if (error == B_OK) 412 error = allocator.AllocateData(request->parameters, parameters, len, 1); 413 if (error != B_OK) 414 return error; 415 // send the request 416 SingleReplyRequestHandler handler(MOUNT_VOLUME_REPLY); 417 InitializeVolumeReply* reply; 418 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 419 if (error != B_OK) 420 return error; 421 RequestReleaser requestReleaser(port, reply); 422 // process the reply 423 if (reply->error != B_OK) 424 return reply->error; 425 return error; 426 }*/ 427 428 // VolumeUnmounted 429 void 430 FileSystem::VolumeUnmounted(Volume* volume) 431 { 432 MutexLocker locker(fVolumeLock); 433 fVolumes.Remove(volume); 434 } 435 436 // GetVolume 437 Volume* 438 FileSystem::GetVolume(dev_t id) 439 { 440 MutexLocker _(fVolumeLock); 441 for (Vector<Volume*>::Iterator it = fVolumes.Begin(); 442 it != fVolumes.End(); 443 it++) { 444 Volume* volume = *it; 445 if (volume->GetID() == id) { 446 volume->AcquireReference(); 447 return volume; 448 } 449 } 450 return NULL; 451 } 452 453 // GetIOCtlInfo 454 const IOCtlInfo* 455 FileSystem::GetIOCtlInfo(int command) const 456 { 457 return (fSettings ? fSettings->GetIOCtlInfo(command) : NULL); 458 } 459 460 // AddSelectSyncEntry 461 status_t 462 FileSystem::AddSelectSyncEntry(selectsync* sync) 463 { 464 AutoLocker<SelectSyncMap> _(fSelectSyncs); 465 int32* count = fSelectSyncs->Get(sync); 466 if (!count) { 467 count = new(nothrow) int32(0); 468 if (!count) 469 return B_NO_MEMORY; 470 status_t error = fSelectSyncs->Put(sync, count); 471 if (error != B_OK) { 472 delete count; 473 return error; 474 } 475 } 476 (*count)++; 477 return B_OK; 478 } 479 480 // RemoveSelectSyncEntry 481 void 482 FileSystem::RemoveSelectSyncEntry(selectsync* sync) 483 { 484 AutoLocker<SelectSyncMap> _(fSelectSyncs); 485 if (int32* count = fSelectSyncs->Get(sync)) { 486 if (--(*count) <= 0) { 487 fSelectSyncs->Remove(sync); 488 delete count; 489 } 490 } 491 } 492 493 494 // KnowsSelectSyncEntry 495 bool 496 FileSystem::KnowsSelectSyncEntry(selectsync* sync) 497 { 498 return fSelectSyncs->ContainsKey(sync); 499 } 500 501 502 // AddNodeListener 503 status_t 504 FileSystem::AddNodeListener(dev_t device, ino_t node, uint32 flags, 505 void* listener) 506 { 507 MutexLocker nodeListenersLocker(fNodeListenersLock); 508 509 // lookup the proxy 510 NodeListenerProxy* proxy = fNodeListeners->Lookup( 511 NodeListenerKey(listener, device, node)); 512 if (proxy != NULL) 513 return proxy->StartListening(flags); 514 515 // it doesn't exist yet -- create it 516 proxy = new(std::nothrow) NodeListenerProxy(this, listener, device, node); 517 if (proxy == NULL) 518 return B_NO_MEMORY; 519 520 // start listening 521 status_t error = proxy->StartListening(flags); 522 if (error != B_OK) { 523 delete proxy; 524 return error; 525 } 526 527 fNodeListeners->Insert(proxy); 528 return B_OK; 529 } 530 531 532 // RemoveNodeListener 533 status_t 534 FileSystem::RemoveNodeListener(dev_t device, ino_t node, void* listener) 535 { 536 MutexLocker nodeListenersLocker(fNodeListenersLock); 537 538 // lookup the proxy 539 NodeListenerProxy* proxy = fNodeListeners->Lookup( 540 NodeListenerKey(listener, device, node)); 541 if (proxy == NULL) 542 return B_BAD_VALUE; 543 544 status_t error = proxy->StopListening(); 545 546 fNodeListeners->Remove(proxy); 547 delete proxy; 548 549 return error; 550 } 551 552 553 // GetVNodeOps 554 VNodeOps* 555 FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities) 556 { 557 MutexLocker locker(fVNodeOpsLock); 558 559 // do we already have ops for those capabilities 560 VNodeOps* ops = fVNodeOps.Lookup(capabilities); 561 if (ops != NULL) { 562 ops->refCount++; 563 return ops; 564 } 565 566 // no, create a new object 567 fs_vnode_ops* opsVector = new(std::nothrow) fs_vnode_ops; 568 if (opsVector == NULL) 569 return NULL; 570 571 // set the operations 572 _InitVNodeOpsVector(opsVector, capabilities); 573 574 // create the VNodeOps object 575 ops = new(std::nothrow) VNodeOps(capabilities, opsVector); 576 if (ops == NULL) { 577 delete opsVector; 578 return NULL; 579 } 580 581 fVNodeOps.Insert(ops); 582 583 return ops; 584 } 585 586 587 // PutVNodeOps 588 void 589 FileSystem::PutVNodeOps(VNodeOps* ops) 590 { 591 MutexLocker locker(fVNodeOpsLock); 592 593 if (--ops->refCount == 0) { 594 fVNodeOps.Remove(ops); 595 delete ops; 596 } 597 } 598 599 600 // IsUserlandServerThread 601 bool 602 FileSystem::IsUserlandServerThread() const 603 { 604 thread_info info; 605 get_thread_info(find_thread(NULL), &info); 606 return (info.team == fUserlandServerTeam); 607 } 608 609 610 // _InitVNodeOpsVector 611 void 612 FileSystem::_InitVNodeOpsVector(fs_vnode_ops* ops, 613 const FSVNodeCapabilities& capabilities) 614 { 615 memcpy(ops, &gUserlandFSVnodeOps, sizeof(fs_vnode_ops)); 616 617 #undef CLEAR_UNSUPPORTED 618 #define CLEAR_UNSUPPORTED(capability, op) \ 619 if (!capabilities.Get(capability)) \ 620 ops->op = NULL 621 622 // vnode operations 623 // FS_VNODE_CAPABILITY_LOOKUP: lookup 624 // FS_VNODE_CAPABILITY_GET_VNODE_NAME: get_vnode_name 625 // emulated in userland 626 // FS_VNODE_CAPABILITY_PUT_VNODE: put_vnode 627 // FS_VNODE_CAPABILITY_REMOVE_VNODE: remove_vnode 628 // needed by Volume to clean up 629 630 // asynchronous I/O 631 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_IO, io); 632 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CANCEL_IO, cancel_io); 633 634 // cache file access 635 ops->get_file_map = NULL; // never used 636 637 // common operations 638 // FS_VNODE_CAPABILITY_IOCTL: ioctl 639 // needed by Volume 640 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SET_FLAGS, set_flags); 641 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SELECT, select); 642 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_DESELECT, deselect); 643 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_FSYNC, fsync); 644 645 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_SYMLINK, read_symlink); 646 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SYMLINK, create_symlink); 647 648 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_LINK, link); 649 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_UNLINK, unlink); 650 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME, rename); 651 652 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_ACCESS, access); 653 // FS_VNODE_CAPABILITY_READ_STAT: read_stat 654 // needed by Volume 655 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_STAT, write_stat); 656 657 // file operations 658 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE, create); 659 // FS_VNODE_CAPABILITY_OPEN: open 660 // mandatory 661 // FS_VNODE_CAPABILITY_CLOSE: close 662 // needed by Volume 663 // FS_VNODE_CAPABILITY_FREE_COOKIE: free_cookie 664 // needed by Volume 665 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ, read); 666 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE, write); 667 668 // directory operations 669 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_DIR, create_dir); 670 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_DIR, remove_dir); 671 // FS_VNODE_CAPABILITY_OPEN_DIR: open_dir 672 // mandatory 673 // FS_VNODE_CAPABILITY_CLOSE_DIR: close_dir 674 // needed by Volume 675 // FS_VNODE_CAPABILITY_FREE_DIR_COOKIE: free_dir_cookie 676 // needed by Volume 677 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_DIR, read_dir); 678 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_DIR, rewind_dir); 679 680 // attribute directory operations 681 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, open_attr_dir); 682 // FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR: close_attr_dir 683 // needed by Volume 684 // FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE: free_attr_dir_cookie 685 // needed by Volume 686 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_DIR, read_attr_dir); 687 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, rewind_attr_dir); 688 689 // attribute operations 690 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_ATTR, create_attr); 691 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR, open_attr); 692 // FS_VNODE_CAPABILITY_CLOSE_ATTR: close_attr 693 // needed by Volume 694 // FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE: free_attr_cookie 695 // needed by Volume 696 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR, read_attr); 697 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR, write_attr); 698 699 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_STAT, read_attr_stat); 700 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT, write_attr_stat); 701 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME_ATTR, rename_attr); 702 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_ATTR, remove_attr); 703 704 // support for node and FS layers 705 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE, 706 create_special_node); 707 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, get_super_vnode); 708 709 #undef CLEAR_UNSUPPORTED 710 } 711 712 713 // _NodeListenerEventOccurred 714 void 715 FileSystem::_NodeListenerEventOccurred(NodeListenerProxy* proxy, 716 const KMessage* event) 717 { 718 // get a free port 719 RequestPort* port = fPortPool.AcquirePort(); 720 if (port == NULL) 721 return; 722 PortReleaser _(&fPortPool, port); 723 724 // prepare the request 725 RequestAllocator allocator(port->GetPort()); 726 NodeMonitoringEventRequest* request; 727 status_t error = AllocateRequest(allocator, &request); 728 if (error != B_OK) 729 return; 730 731 error = allocator.AllocateData(request->event, event->Buffer(), 732 event->ContentSize(), 1); 733 if (error != B_OK) 734 return; 735 736 Thread* thread = thread_get_current_thread(); 737 request->team = thread->team->id; 738 request->thread = thread->id; 739 request->user = geteuid(); 740 request->group = getegid(); 741 request->listener = proxy->ClientListener(); 742 743 // send the request 744 KernelRequestHandler handler(this, NODE_MONITORING_EVENT_REPLY); 745 port->SendRequest(&allocator, &handler); 746 } 747 748 749 // _NotificationThreadEntry 750 int32 751 FileSystem::_NotificationThreadEntry(void* data) 752 { 753 return ((FileSystem*)data)->_NotificationThread(); 754 } 755 756 757 // _NotificationThread 758 int32 759 FileSystem::_NotificationThread() 760 { 761 // process the notification requests until the FS is deleted 762 while (!fTerminating) { 763 if (fNotificationPort->InitCheck() != B_OK) 764 return fNotificationPort->InitCheck(); 765 KernelRequestHandler handler(this, NO_REQUEST); 766 fNotificationPort->HandleRequests(&handler, NULL, 767 kNotificationRequestTimeout); 768 } 769 // We eat all remaining notification requests, so that they aren't 770 // presented to the file system, when it is mounted next time. 771 // TODO: We should probably use a special handler that sends an ack reply, 772 // but ignores the requests otherwise. 773 KernelRequestHandler handler(this, NO_REQUEST); 774 fNotificationPort->HandleRequests(&handler, NULL, 0); 775 return 0; 776 } 777 778