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