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<HashKey32<selectsync*>, int32*> { 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 %ld 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, %ld)\n", name, infos, count)); 238 capabilities.Dump(); 239 240 // check parameters 241 if (!name || !infos || count < 2) 242 RETURN_ERROR(B_BAD_VALUE); 243 244 // set the name 245 if (!fName.SetTo(name)) 246 return B_NO_MEMORY; 247 248 // init VNodeOps map 249 status_t error = fVNodeOps.Init(); 250 if (error != B_OK) 251 return error; 252 253 fTeam = team; 254 fCapabilities = capabilities; 255 256 // create the select sync entry map 257 fSelectSyncs = new(nothrow) SelectSyncMap; 258 if (!fSelectSyncs) 259 return B_NO_MEMORY; 260 261 // create the node listener proxy map 262 fNodeListeners = new(std::nothrow) NodeListenerMap; 263 if (fNodeListeners == NULL || fNodeListeners->Init() != B_OK) 264 return B_NO_MEMORY; 265 266 // create the request ports 267 // the notification port 268 fNotificationPort = new(nothrow) RequestPort(infos); 269 if (!fNotificationPort) 270 RETURN_ERROR(B_NO_MEMORY); 271 error = fNotificationPort->InitCheck(); 272 if (error != B_OK) 273 return error; 274 275 // the other request ports 276 for (int32 i = 1; i < count; i++) { 277 RequestPort* port = new(nothrow) RequestPort(infos + i); 278 if (!port) 279 RETURN_ERROR(B_NO_MEMORY); 280 error = port->InitCheck(); 281 if (error == B_OK) 282 error = fPortPool.AddPort(port); 283 if (error != B_OK) { 284 delete port; 285 RETURN_ERROR(error); 286 } 287 } 288 289 // get the userland team 290 port_info portInfo; 291 error = get_port_info(infos[0].owner_port, &portInfo); 292 if (error != B_OK) 293 RETURN_ERROR(error); 294 fUserlandServerTeam = portInfo.team; 295 296 // print some info about the userland team 297 D( 298 PRINT((" userland team is: %ld\n", fUserlandServerTeam)); 299 int32 cookie = 0; 300 thread_info threadInfo; 301 while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo) 302 == B_OK) { 303 PRINT((" userland thread: %ld: `%s'\n", threadInfo.thread, 304 threadInfo.name)); 305 } 306 ); 307 308 // load the settings 309 fSettings = new(nothrow) Settings; 310 if (fSettings) { 311 status_t settingsError = fSettings->SetTo(fName.GetString()); 312 if (settingsError != B_OK) { 313 PRINT(("Failed to load settings: %s\n", strerror(settingsError))); 314 delete fSettings; 315 fSettings = NULL; 316 } else 317 fSettings->Dump(); 318 } else 319 ERROR(("Failed to allocate settings.\n")); 320 321 // spawn the notification thread 322 #if USER 323 fNotificationThread = spawn_thread(_NotificationThreadEntry, 324 "UFS notification thread", B_NORMAL_PRIORITY, this); 325 #else 326 fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry, 327 "UFS notification thread", B_NORMAL_PRIORITY, this); 328 #endif 329 if (fNotificationThread < 0) 330 RETURN_ERROR(fNotificationThread); 331 resume_thread(fNotificationThread); 332 333 fInitialized = (error == B_OK); 334 RETURN_ERROR(error); 335 } 336 337 // GetName 338 const char* 339 FileSystem::GetName() const 340 { 341 return fName.GetString(); 342 } 343 344 // GetCapabilities 345 const FSCapabilities& 346 FileSystem::GetCapabilities() const 347 { 348 return fCapabilities; 349 } 350 351 // GetPortPool 352 RequestPortPool* 353 FileSystem::GetPortPool() 354 { 355 return &fPortPool; 356 } 357 358 // Mount 359 status_t 360 FileSystem::Mount(fs_volume* fsVolume, const char* device, uint32 flags, 361 const char* parameters, Volume** _volume) 362 { 363 // check initialization and parameters 364 if (!fInitialized || !_volume) 365 return B_BAD_VALUE; 366 367 // create volume 368 Volume* volume = new(nothrow) Volume(this, fsVolume); 369 if (!volume) 370 return B_NO_MEMORY; 371 372 // add volume to the volume list 373 MutexLocker locker(fVolumeLock); 374 status_t error = fVolumes.PushBack(volume); 375 locker.Unlock(); 376 if (error != B_OK) 377 return error; 378 379 // mount volume 380 error = volume->Mount(device, flags, parameters); 381 if (error != B_OK) { 382 MutexLocker locker(fVolumeLock); 383 fVolumes.Remove(volume); 384 locker.Unlock(); 385 volume->ReleaseReference(); 386 return error; 387 } 388 389 *_volume = volume; 390 return error; 391 } 392 393 // Initialize 394 /*status_t 395 FileSystem::Initialize(const char* deviceName, const char* parameters, 396 size_t len) 397 { 398 // get a free port 399 RequestPort* port = fPortPool.AcquirePort(); 400 if (!port) 401 return B_ERROR; 402 PortReleaser _(&fPortPool, port); 403 // prepare the request 404 RequestAllocator allocator(port->GetPort()); 405 MountVolumeRequest* request; 406 status_t error = AllocateRequest(allocator, &request); 407 if (error != B_OK) 408 return error; 409 error = allocator.AllocateString(request->device, deviceName); 410 if (error == B_OK) 411 error = allocator.AllocateData(request->parameters, parameters, len, 1); 412 if (error != B_OK) 413 return error; 414 // send the request 415 SingleReplyRequestHandler handler(MOUNT_VOLUME_REPLY); 416 InitializeVolumeReply* reply; 417 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 418 if (error != B_OK) 419 return error; 420 RequestReleaser requestReleaser(port, reply); 421 // process the reply 422 if (reply->error != B_OK) 423 return reply->error; 424 return error; 425 }*/ 426 427 // VolumeUnmounted 428 void 429 FileSystem::VolumeUnmounted(Volume* volume) 430 { 431 MutexLocker locker(fVolumeLock); 432 fVolumes.Remove(volume); 433 } 434 435 // GetVolume 436 Volume* 437 FileSystem::GetVolume(dev_t id) 438 { 439 MutexLocker _(fVolumeLock); 440 for (Vector<Volume*>::Iterator it = fVolumes.Begin(); 441 it != fVolumes.End(); 442 it++) { 443 Volume* volume = *it; 444 if (volume->GetID() == id) { 445 volume->AcquireReference(); 446 return volume; 447 } 448 } 449 return NULL; 450 } 451 452 // GetIOCtlInfo 453 const IOCtlInfo* 454 FileSystem::GetIOCtlInfo(int command) const 455 { 456 return (fSettings ? fSettings->GetIOCtlInfo(command) : NULL); 457 } 458 459 // AddSelectSyncEntry 460 status_t 461 FileSystem::AddSelectSyncEntry(selectsync* sync) 462 { 463 AutoLocker<SelectSyncMap> _(fSelectSyncs); 464 int32* count = fSelectSyncs->Get(sync); 465 if (!count) { 466 count = new(nothrow) int32(0); 467 if (!count) 468 return B_NO_MEMORY; 469 status_t error = fSelectSyncs->Put(sync, count); 470 if (error != B_OK) { 471 delete count; 472 return error; 473 } 474 } 475 (*count)++; 476 return B_OK; 477 } 478 479 // RemoveSelectSyncEntry 480 void 481 FileSystem::RemoveSelectSyncEntry(selectsync* sync) 482 { 483 AutoLocker<SelectSyncMap> _(fSelectSyncs); 484 if (int32* count = fSelectSyncs->Get(sync)) { 485 if (--(*count) <= 0) { 486 fSelectSyncs->Remove(sync); 487 delete count; 488 } 489 } 490 } 491 492 493 // KnowsSelectSyncEntry 494 bool 495 FileSystem::KnowsSelectSyncEntry(selectsync* sync) 496 { 497 return fSelectSyncs->ContainsKey(sync); 498 } 499 500 501 // AddNodeListener 502 status_t 503 FileSystem::AddNodeListener(dev_t device, ino_t node, uint32 flags, 504 void* listener) 505 { 506 MutexLocker nodeListenersLocker(fNodeListenersLock); 507 508 // lookup the proxy 509 NodeListenerProxy* proxy = fNodeListeners->Lookup( 510 NodeListenerKey(listener, device, node)); 511 if (proxy != NULL) 512 return proxy->StartListening(flags); 513 514 // it doesn't exist yet -- create it 515 proxy = new(std::nothrow) NodeListenerProxy(this, listener, device, node); 516 if (proxy == NULL) 517 return B_NO_MEMORY; 518 519 // start listening 520 status_t error = proxy->StartListening(flags); 521 if (error != B_OK) { 522 delete proxy; 523 return error; 524 } 525 526 fNodeListeners->Insert(proxy); 527 return B_OK; 528 } 529 530 531 // RemoveNodeListener 532 status_t 533 FileSystem::RemoveNodeListener(dev_t device, ino_t node, void* listener) 534 { 535 MutexLocker nodeListenersLocker(fNodeListenersLock); 536 537 // lookup the proxy 538 NodeListenerProxy* proxy = fNodeListeners->Lookup( 539 NodeListenerKey(listener, device, node)); 540 if (proxy == NULL) 541 return B_BAD_VALUE; 542 543 status_t error = proxy->StopListening(); 544 545 fNodeListeners->Remove(proxy); 546 delete proxy; 547 548 return error; 549 } 550 551 552 // GetVNodeOps 553 VNodeOps* 554 FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities) 555 { 556 MutexLocker locker(fVNodeOpsLock); 557 558 // do we already have ops for those capabilities 559 VNodeOps* ops = fVNodeOps.Lookup(capabilities); 560 if (ops != NULL) { 561 ops->refCount++; 562 return ops; 563 } 564 565 // no, create a new object 566 fs_vnode_ops* opsVector = new(std::nothrow) fs_vnode_ops; 567 if (opsVector == NULL) 568 return NULL; 569 570 // set the operations 571 _InitVNodeOpsVector(opsVector, capabilities); 572 573 // create the VNodeOps object 574 ops = new(std::nothrow) VNodeOps(capabilities, opsVector); 575 if (ops == NULL) { 576 delete opsVector; 577 return NULL; 578 } 579 580 fVNodeOps.Insert(ops); 581 582 return ops; 583 } 584 585 586 // PutVNodeOps 587 void 588 FileSystem::PutVNodeOps(VNodeOps* ops) 589 { 590 MutexLocker locker(fVNodeOpsLock); 591 592 if (--ops->refCount == 0) { 593 fVNodeOps.Remove(ops); 594 delete ops; 595 } 596 } 597 598 599 // IsUserlandServerThread 600 bool 601 FileSystem::IsUserlandServerThread() const 602 { 603 thread_info info; 604 get_thread_info(find_thread(NULL), &info); 605 return (info.team == fUserlandServerTeam); 606 } 607 608 609 // _InitVNodeOpsVector 610 void 611 FileSystem::_InitVNodeOpsVector(fs_vnode_ops* ops, 612 const FSVNodeCapabilities& capabilities) 613 { 614 memcpy(ops, &gUserlandFSVnodeOps, sizeof(fs_vnode_ops)); 615 616 #undef CLEAR_UNSUPPORTED 617 #define CLEAR_UNSUPPORTED(capability, op) \ 618 if (!capabilities.Get(capability)) \ 619 ops->op = NULL 620 621 // vnode operations 622 // FS_VNODE_CAPABILITY_LOOKUP: lookup 623 // FS_VNODE_CAPABILITY_GET_VNODE_NAME: get_vnode_name 624 // emulated in userland 625 // FS_VNODE_CAPABILITY_PUT_VNODE: put_vnode 626 // FS_VNODE_CAPABILITY_REMOVE_VNODE: remove_vnode 627 // needed by Volume to clean up 628 629 // asynchronous I/O 630 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_IO, io); 631 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CANCEL_IO, cancel_io); 632 633 // cache file access 634 ops->get_file_map = NULL; // never used 635 636 // common operations 637 // FS_VNODE_CAPABILITY_IOCTL: ioctl 638 // needed by Volume 639 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SET_FLAGS, set_flags); 640 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SELECT, select); 641 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_DESELECT, deselect); 642 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_FSYNC, fsync); 643 644 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_SYMLINK, read_symlink); 645 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SYMLINK, create_symlink); 646 647 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_LINK, link); 648 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_UNLINK, unlink); 649 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME, rename); 650 651 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_ACCESS, access); 652 // FS_VNODE_CAPABILITY_READ_STAT: read_stat 653 // needed by Volume 654 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_STAT, write_stat); 655 656 // file operations 657 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE, create); 658 // FS_VNODE_CAPABILITY_OPEN: open 659 // mandatory 660 // FS_VNODE_CAPABILITY_CLOSE: close 661 // needed by Volume 662 // FS_VNODE_CAPABILITY_FREE_COOKIE: free_cookie 663 // needed by Volume 664 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ, read); 665 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE, write); 666 667 // directory operations 668 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_DIR, create_dir); 669 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_DIR, remove_dir); 670 // FS_VNODE_CAPABILITY_OPEN_DIR: open_dir 671 // mandatory 672 // FS_VNODE_CAPABILITY_CLOSE_DIR: close_dir 673 // needed by Volume 674 // FS_VNODE_CAPABILITY_FREE_DIR_COOKIE: free_dir_cookie 675 // needed by Volume 676 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_DIR, read_dir); 677 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_DIR, rewind_dir); 678 679 // attribute directory operations 680 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, open_attr_dir); 681 // FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR: close_attr_dir 682 // needed by Volume 683 // FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE: free_attr_dir_cookie 684 // needed by Volume 685 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_DIR, read_attr_dir); 686 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, rewind_attr_dir); 687 688 // attribute operations 689 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_ATTR, create_attr); 690 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR, open_attr); 691 // FS_VNODE_CAPABILITY_CLOSE_ATTR: close_attr 692 // needed by Volume 693 // FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE: free_attr_cookie 694 // needed by Volume 695 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR, read_attr); 696 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR, write_attr); 697 698 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_STAT, read_attr_stat); 699 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT, write_attr_stat); 700 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME_ATTR, rename_attr); 701 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_ATTR, remove_attr); 702 703 // support for node and FS layers 704 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE, 705 create_special_node); 706 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, get_super_vnode); 707 708 #undef CLEAR_UNSUPPORTED 709 } 710 711 712 // _NodeListenerEventOccurred 713 void 714 FileSystem::_NodeListenerEventOccurred(NodeListenerProxy* proxy, 715 const KMessage* event) 716 { 717 // get a free port 718 RequestPort* port = fPortPool.AcquirePort(); 719 if (port == NULL) 720 return; 721 PortReleaser _(&fPortPool, port); 722 723 // prepare the request 724 RequestAllocator allocator(port->GetPort()); 725 NodeMonitoringEventRequest* request; 726 status_t error = AllocateRequest(allocator, &request); 727 if (error != B_OK) 728 return; 729 730 error = allocator.AllocateData(request->event, event->Buffer(), 731 event->ContentSize(), 1); 732 if (error != B_OK) 733 return; 734 735 Thread* thread = thread_get_current_thread(); 736 request->team = thread->team->id; 737 request->thread = thread->id; 738 request->user = geteuid(); 739 request->group = getegid(); 740 request->listener = proxy->ClientListener(); 741 742 // send the request 743 KernelRequestHandler handler(this, NODE_MONITORING_EVENT_REPLY); 744 port->SendRequest(&allocator, &handler); 745 } 746 747 748 // _NotificationThreadEntry 749 int32 750 FileSystem::_NotificationThreadEntry(void* data) 751 { 752 return ((FileSystem*)data)->_NotificationThread(); 753 } 754 755 756 // _NotificationThread 757 int32 758 FileSystem::_NotificationThread() 759 { 760 // process the notification requests until the FS is deleted 761 while (!fTerminating) { 762 if (fNotificationPort->InitCheck() != B_OK) 763 return fNotificationPort->InitCheck(); 764 KernelRequestHandler handler(this, NO_REQUEST); 765 fNotificationPort->HandleRequests(&handler, NULL, 766 kNotificationRequestTimeout); 767 } 768 // We eat all remaining notification requests, so that they aren't 769 // presented to the file system, when it is mounted next time. 770 // TODO: We should probably use a special handler that sends an ack reply, 771 // but ignores the requests otherwise. 772 KernelRequestHandler handler(this, NO_REQUEST); 773 fNotificationPort->HandleRequests(&handler, NULL, 0); 774 return 0; 775 } 776 777