1 /* 2 * Copyright 2003-2016, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2005-2008, Ingo Weinhold, bonefish@users.sf.net. 4 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de. 5 * 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include <fs/node_monitor.h> 11 12 #include <stddef.h> 13 #include <stdlib.h> 14 15 #include <AppDefs.h> 16 #include <NodeMonitor.h> 17 18 #include <fd.h> 19 #include <lock.h> 20 #include <messaging.h> 21 #include <Notifications.h> 22 #include <vfs.h> 23 #include <util/AutoLock.h> 24 #include <util/DoublyLinkedList.h> 25 #include <util/KMessage.h> 26 #include <util/list.h> 27 28 #include "node_monitor_private.h" 29 #include "Vnode.h" 30 31 32 //#define TRACE_MONITOR 33 #ifdef TRACE_MONITOR 34 # define TRACE(x) dprintf x 35 #else 36 # define TRACE(x) ; 37 #endif 38 39 40 // ToDo: add more fine grained locking - maybe using a ref_count in the 41 // node_monitor structure? 42 // ToDo: return another error code than B_NO_MEMORY if the team's maximum is hit 43 44 45 typedef struct monitor_listener monitor_listener; 46 typedef struct node_monitor node_monitor; 47 48 struct monitor_listener { 49 list_link context_link; 50 DoublyLinkedListLink<monitor_listener> monitor_link; 51 NotificationListener *listener; 52 uint32 flags; 53 node_monitor *monitor; 54 }; 55 56 typedef DoublyLinkedList<monitor_listener, DoublyLinkedListMemberGetLink< 57 monitor_listener, &monitor_listener::monitor_link> > MonitorListenerList; 58 59 struct node_monitor { 60 node_monitor* hash_link; 61 dev_t device; 62 ino_t node; 63 MonitorListenerList listeners; 64 }; 65 66 struct interested_monitor_listener_list { 67 MonitorListenerList::Iterator iterator; 68 uint32 flags; 69 }; 70 71 static UserMessagingMessageSender sNodeMonitorSender; 72 73 class UserNodeListener : public UserMessagingListener { 74 public: 75 UserNodeListener(port_id port, int32 token) 76 : UserMessagingListener(sNodeMonitorSender, port, token) 77 { 78 } 79 80 bool operator==(const NotificationListener& _other) const 81 { 82 const UserNodeListener* other 83 = dynamic_cast<const UserNodeListener*>(&_other); 84 return other != NULL && other->Port() == Port() 85 && other->Token() == Token(); 86 } 87 }; 88 89 class NodeMonitorService : public NotificationService { 90 public: 91 NodeMonitorService(); 92 virtual ~NodeMonitorService(); 93 94 status_t InitCheck(); 95 96 status_t NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device, 97 ino_t directory, const char *name, ino_t node); 98 status_t NotifyEntryMoved(dev_t device, ino_t fromDirectory, 99 const char *fromName, ino_t toDirectory, const char *toName, 100 ino_t node); 101 status_t NotifyStatChanged(dev_t device, ino_t directory, ino_t node, 102 uint32 statFields); 103 status_t NotifyAttributeChanged(dev_t device, ino_t directory, 104 ino_t node, const char *attribute, int32 cause); 105 status_t NotifyUnmount(dev_t device); 106 status_t NotifyMount(dev_t device, dev_t parentDevice, 107 ino_t parentDirectory); 108 109 status_t RemoveListeners(io_context *context); 110 111 status_t AddListener(const KMessage *eventSpecifier, 112 NotificationListener &listener); 113 status_t UpdateListener(const KMessage *eventSpecifier, 114 NotificationListener &listener); 115 status_t RemoveListener(const KMessage *eventSpecifier, 116 NotificationListener &listener); 117 118 status_t AddListener(io_context *context, dev_t device, ino_t node, 119 uint32 flags, NotificationListener ¬ificationListener); 120 status_t RemoveListener(io_context *context, dev_t device, ino_t node, 121 NotificationListener ¬ificationListener); 122 123 status_t RemoveUserListeners(struct io_context *context, 124 port_id port, uint32 token); 125 status_t UpdateUserListener(io_context *context, dev_t device, 126 ino_t node, uint32 flags, UserNodeListener &userListener); 127 128 virtual const char* Name() { return "node monitor"; } 129 130 private: 131 void _RemoveMonitor(node_monitor *monitor, uint32 flags); 132 status_t _RemoveListener(io_context *context, dev_t device, ino_t node, 133 NotificationListener& notificationListener, bool isVolumeListener); 134 void _RemoveListener(monitor_listener *listener); 135 node_monitor *_MonitorFor(dev_t device, ino_t node, 136 bool isVolumeListener); 137 status_t _GetMonitor(io_context *context, dev_t device, ino_t node, 138 bool addIfNecessary, node_monitor **_monitor, 139 bool isVolumeListener); 140 monitor_listener *_MonitorListenerFor(node_monitor* monitor, 141 NotificationListener& notificationListener); 142 status_t _AddMonitorListener(io_context *context, 143 node_monitor* monitor, uint32 flags, 144 NotificationListener& notificationListener); 145 status_t _UpdateListener(io_context *context, dev_t device, ino_t node, 146 uint32 flags, bool addFlags, 147 NotificationListener ¬ificationListener); 148 void _GetInterestedMonitorListeners(dev_t device, ino_t node, 149 uint32 flags, interested_monitor_listener_list *interestedListeners, 150 int32 &interestedListenerCount); 151 void _GetInterestedVolumeListeners(dev_t device, uint32 flags, 152 interested_monitor_listener_list *interestedListeners, 153 int32 &interestedListenerCount); 154 status_t _SendNotificationMessage(KMessage &message, 155 interested_monitor_listener_list *interestedListeners, 156 int32 interestedListenerCount); 157 void _ResolveMountPoint(dev_t device, ino_t directory, 158 dev_t& parentDevice, ino_t& parentDirectory); 159 160 struct monitor_hash_key { 161 dev_t device; 162 ino_t node; 163 }; 164 165 struct HashDefinition { 166 typedef monitor_hash_key* KeyType; 167 typedef node_monitor ValueType; 168 169 size_t HashKey(monitor_hash_key* key) const 170 { return _Hash(key->device, key->node); } 171 size_t Hash(node_monitor *monitor) const 172 { return _Hash(monitor->device, monitor->node); } 173 174 bool Compare(monitor_hash_key* key, node_monitor *monitor) const 175 { 176 return key->device == monitor->device 177 && key->node == monitor->node; 178 } 179 180 node_monitor*& GetLink(node_monitor* monitor) const 181 { return monitor->hash_link; } 182 183 uint32 _Hash(dev_t device, ino_t node) const 184 { 185 return ((uint32)(node >> 32) + (uint32)node) ^ (uint32)device; 186 } 187 }; 188 189 typedef BOpenHashTable<HashDefinition> MonitorHash; 190 191 struct VolumeHashDefinition { 192 typedef dev_t KeyType; 193 typedef node_monitor ValueType; 194 195 size_t HashKey(dev_t key) const 196 { return _Hash(key); } 197 size_t Hash(node_monitor *monitor) const 198 { return _Hash(monitor->device); } 199 200 bool Compare(dev_t key, node_monitor *monitor) const 201 { 202 return key == monitor->device; 203 } 204 205 node_monitor*& GetLink(node_monitor* monitor) const 206 { return monitor->hash_link; } 207 208 uint32 _Hash(dev_t device) const 209 { 210 return (uint32)(device >> 16) + (uint16)device; 211 } 212 }; 213 214 typedef BOpenHashTable<VolumeHashDefinition> VolumeMonitorHash; 215 216 MonitorHash fMonitors; 217 VolumeMonitorHash fVolumeMonitors; 218 recursive_lock fRecursiveLock; 219 }; 220 221 static NodeMonitorService sNodeMonitorService; 222 223 224 /*! \brief Notifies the listener of a live query that an entry has been added 225 to or removed from or updated and still in the query (for whatever 226 reason). 227 \param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED or \c B_ATTR_CHANGED. 228 \param port The target port of the listener. 229 \param token The BHandler token of the listener. 230 \param device The ID of the mounted FS, the entry lives in. 231 \param directory The entry's parent directory ID. 232 \param name The entry's name. 233 \param node The ID of the node the entry refers to. 234 \return 235 - \c B_OK, if everything went fine, 236 - another error code otherwise. 237 */ 238 static status_t 239 notify_query_entry_event(int32 opcode, port_id port, int32 token, 240 dev_t device, ino_t directory, const char *name, ino_t node) 241 { 242 if (!name) 243 return B_BAD_VALUE; 244 245 // construct the message 246 char messageBuffer[1024]; 247 KMessage message; 248 message.SetTo(messageBuffer, sizeof(messageBuffer), B_QUERY_UPDATE); 249 message.AddInt32("opcode", opcode); 250 message.AddInt32("device", device); 251 message.AddInt64("directory", directory); 252 message.AddInt64("node", node); 253 message.AddString("name", name); 254 255 // send the message 256 messaging_target target; 257 target.port = port; 258 target.token = token; 259 260 return send_message(&message, &target, 1); 261 } 262 263 264 // #pragma mark - NodeMonitorService 265 266 267 NodeMonitorService::NodeMonitorService() 268 { 269 recursive_lock_init(&fRecursiveLock, "node monitor"); 270 } 271 272 273 NodeMonitorService::~NodeMonitorService() 274 { 275 recursive_lock_destroy(&fRecursiveLock); 276 } 277 278 279 status_t 280 NodeMonitorService::InitCheck() 281 { 282 return B_OK; 283 } 284 285 286 /*! Removes the specified node_monitor from the hashtable 287 and free it. 288 Must be called with monitors lock hold. 289 */ 290 void 291 NodeMonitorService::_RemoveMonitor(node_monitor *monitor, uint32 flags) 292 { 293 if ((flags & B_WATCH_VOLUME) != 0) 294 fVolumeMonitors.Remove(monitor); 295 else 296 fMonitors.Remove(monitor); 297 delete monitor; 298 } 299 300 301 //! Helper function for the RemoveListener function. 302 status_t 303 NodeMonitorService::_RemoveListener(io_context *context, dev_t device, 304 ino_t node, NotificationListener& notificationListener, 305 bool isVolumeListener) 306 { 307 TRACE(("%s(dev = %ld, node = %lld, listener = %p\n", 308 __PRETTY_FUNCTION__, device, node, ¬ificationListener)); 309 310 RecursiveLocker _(fRecursiveLock); 311 312 // get the monitor for this device/node pair 313 node_monitor *monitor = _MonitorFor(device, node, isVolumeListener); 314 if (monitor == NULL) 315 return B_BAD_VALUE; 316 317 // see if it has the listener we are looking for 318 monitor_listener* listener = _MonitorListenerFor(monitor, 319 notificationListener); 320 if (listener == NULL) 321 return B_BAD_VALUE; 322 323 _RemoveListener(listener); 324 context->num_monitors--; 325 326 return B_OK; 327 } 328 329 330 /*! Removes the specified monitor_listener from all lists 331 and free it. 332 Must be called with monitors lock hold. 333 */ 334 void 335 NodeMonitorService::_RemoveListener(monitor_listener *listener) 336 { 337 uint32 flags = listener->flags; 338 node_monitor *monitor = listener->monitor; 339 340 // remove it from the listener and I/O context lists 341 monitor->listeners.Remove(listener); 342 list_remove_link(listener); 343 344 if (dynamic_cast<UserNodeListener*>(listener->listener) != NULL) { 345 // This is a listener we copied ourselves in UpdateUserListener(), 346 // so we have to delete it here. 347 delete listener->listener; 348 } 349 350 delete listener; 351 352 if (monitor->listeners.IsEmpty()) 353 _RemoveMonitor(monitor, flags); 354 } 355 356 357 /*! Returns the monitor that matches the specified device/node pair. 358 Must be called with monitors lock hold. 359 */ 360 node_monitor * 361 NodeMonitorService::_MonitorFor(dev_t device, ino_t node, bool isVolumeListener) 362 { 363 if (isVolumeListener) 364 return fVolumeMonitors.Lookup(device); 365 366 struct monitor_hash_key key; 367 key.device = device; 368 key.node = node; 369 370 return fMonitors.Lookup(&key); 371 } 372 373 374 /*! Returns the monitor that matches the specified device/node pair. 375 If the monitor does not exist yet, it will be created. 376 Must be called with monitors lock hold. 377 */ 378 status_t 379 NodeMonitorService::_GetMonitor(io_context *context, dev_t device, ino_t node, 380 bool addIfNecessary, node_monitor** _monitor, bool isVolumeListener) 381 { 382 node_monitor* monitor = _MonitorFor(device, node, isVolumeListener); 383 if (monitor != NULL) { 384 *_monitor = monitor; 385 return B_OK; 386 } 387 if (!addIfNecessary) 388 return B_BAD_VALUE; 389 390 // check if this team is allowed to have more listeners 391 if (context->num_monitors >= context->max_monitors) { 392 // the BeBook says to return B_NO_MEMORY in this case, but 393 // we should have another one. 394 return B_NO_MEMORY; 395 } 396 397 // create new monitor 398 monitor = new(std::nothrow) node_monitor; 399 if (monitor == NULL) 400 return B_NO_MEMORY; 401 402 // initialize monitor 403 monitor->device = device; 404 monitor->node = node; 405 406 status_t status; 407 if (isVolumeListener) 408 status = fVolumeMonitors.Insert(monitor); 409 else 410 status = fMonitors.Insert(monitor); 411 if (status < B_OK) { 412 delete monitor; 413 return B_NO_MEMORY; 414 } 415 416 *_monitor = monitor; 417 return B_OK; 418 } 419 420 421 /*! Returns the listener that matches the specified port/token pair. 422 Must be called with monitors lock hold. 423 */ 424 monitor_listener* 425 NodeMonitorService::_MonitorListenerFor(node_monitor* monitor, 426 NotificationListener& notificationListener) 427 { 428 MonitorListenerList::Iterator iterator 429 = monitor->listeners.GetIterator(); 430 431 while (monitor_listener* listener = iterator.Next()) { 432 // does this listener match? 433 if (*listener->listener == notificationListener) 434 return listener; 435 } 436 437 return NULL; 438 } 439 440 441 status_t 442 NodeMonitorService::_AddMonitorListener(io_context *context, 443 node_monitor* monitor, uint32 flags, 444 NotificationListener& notificationListener) 445 { 446 monitor_listener *listener = new(std::nothrow) monitor_listener; 447 if (listener == NULL) { 448 // no memory for the listener, so remove the monitor as well if needed 449 if (monitor->listeners.IsEmpty()) 450 _RemoveMonitor(monitor, flags); 451 452 return B_NO_MEMORY; 453 } 454 455 // initialize listener, and add it to the lists 456 listener->listener = ¬ificationListener; 457 listener->flags = flags; 458 listener->monitor = monitor; 459 460 monitor->listeners.Add(listener); 461 list_add_link_to_head(&context->node_monitors, listener); 462 463 context->num_monitors++; 464 return B_OK; 465 } 466 467 468 status_t 469 NodeMonitorService::AddListener(io_context *context, dev_t device, ino_t node, 470 uint32 flags, NotificationListener& notificationListener) 471 { 472 TRACE(("%s(dev = %ld, node = %lld, flags = %ld, listener = %p\n", 473 __PRETTY_FUNCTION__, device, node, flags, ¬ificationListener)); 474 475 RecursiveLocker _(fRecursiveLock); 476 477 node_monitor *monitor; 478 status_t status = _GetMonitor(context, device, node, true, &monitor, 479 (flags & B_WATCH_VOLUME) != 0); 480 if (status < B_OK) 481 return status; 482 483 // add listener 484 485 return _AddMonitorListener(context, monitor, flags, notificationListener); 486 } 487 488 489 status_t 490 NodeMonitorService::_UpdateListener(io_context *context, dev_t device, 491 ino_t node, uint32 flags, bool addFlags, 492 NotificationListener& notificationListener) 493 { 494 TRACE(("%s(dev = %ld, node = %lld, flags = %ld, listener = %p\n", 495 __PRETTY_FUNCTION__, device, node, flags, ¬ificationListener)); 496 497 RecursiveLocker _(fRecursiveLock); 498 499 node_monitor *monitor; 500 status_t status = _GetMonitor(context, device, node, false, &monitor, 501 (flags & B_WATCH_VOLUME) != 0); 502 if (status < B_OK) 503 return status; 504 505 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 506 while (monitor_listener* listener = iterator.Next()) { 507 if (*listener->listener == notificationListener) { 508 if (addFlags) 509 listener->flags |= flags; 510 else 511 listener->flags = flags; 512 return B_OK; 513 } 514 } 515 516 return B_BAD_VALUE; 517 } 518 519 520 /*! \brief Given device and node ID and a node monitoring event mask, the 521 function checks whether there are listeners interested in any of 522 the events for that node and, if so, adds the respective listener 523 list to a supplied array of listener lists. 524 525 Note, that in general not all of the listeners in an appended list will be 526 interested in the events, but it is guaranteed that 527 interested_monitor_listener_list::first_listener is indeed 528 the first listener in the list, that is interested. 529 530 \param device The ID of the mounted FS, the node lives in. 531 \param node The ID of the node. 532 \param flags The mask specifying the events occurred for the given node 533 (a combination of \c B_WATCH_* constants). 534 \param interestedListeners An array of listener lists. If there are 535 interested listeners for the node, the list will be appended to 536 this array. 537 \param interestedListenerCount The number of elements in the 538 \a interestedListeners array. Will be incremented, if a list is 539 appended. 540 */ 541 void 542 NodeMonitorService::_GetInterestedMonitorListeners(dev_t device, ino_t node, 543 uint32 flags, interested_monitor_listener_list *interestedListeners, 544 int32 &interestedListenerCount) 545 { 546 // get the monitor for the node 547 node_monitor *monitor = _MonitorFor(device, node, false); 548 if (monitor == NULL) 549 return; 550 551 // iterate through the listeners until we find one with matching flags 552 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 553 while (monitor_listener *listener = iterator.Next()) { 554 if ((listener->flags & flags) == flags) { 555 interested_monitor_listener_list &list 556 = interestedListeners[interestedListenerCount++]; 557 list.iterator = iterator; 558 list.flags = flags; 559 return; 560 } 561 } 562 } 563 564 565 void 566 NodeMonitorService::_GetInterestedVolumeListeners(dev_t device, uint32 flags, 567 interested_monitor_listener_list *interestedListeners, 568 int32 &interestedListenerCount) 569 { 570 // get the monitor for the node 571 node_monitor *monitor = _MonitorFor(device, -1, true); 572 if (monitor == NULL) 573 return; 574 575 // iterate through the listeners until we find one with matching flags 576 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 577 while (monitor_listener *listener = iterator.Next()) { 578 if ((listener->flags & flags) == flags) { 579 interested_monitor_listener_list &list 580 = interestedListeners[interestedListenerCount++]; 581 list.iterator = iterator; 582 list.flags = flags; 583 return; 584 } 585 } 586 } 587 588 589 /*! \brief Sends a notifcation message to the given listeners. 590 \param message The message to be sent. 591 \param interestedListeners An array of listener lists. 592 \param interestedListenerCount The number of elements in the 593 \a interestedListeners array. 594 \return 595 - \c B_OK, if everything went fine, 596 - another error code otherwise. 597 */ 598 status_t 599 NodeMonitorService::_SendNotificationMessage(KMessage &message, 600 interested_monitor_listener_list *interestedListeners, 601 int32 interestedListenerCount) 602 { 603 // iterate through the lists 604 interested_monitor_listener_list *list = interestedListeners; 605 for (int32 i = 0; i < interestedListenerCount; i++, list++) { 606 // iterate through the listeners 607 MonitorListenerList::Iterator iterator = list->iterator; 608 do { 609 monitor_listener *listener = iterator.Current(); 610 if (listener->flags & list->flags) 611 listener->listener->EventOccurred(*this, &message); 612 } while (iterator.Next() != NULL); 613 } 614 615 list = interestedListeners; 616 for (int32 i = 0; i < interestedListenerCount; i++, list++) { 617 // iterate through the listeners 618 do { 619 monitor_listener *listener = list->iterator.Current(); 620 if (listener->flags & list->flags) 621 listener->listener->AllListenersNotified(*this); 622 } while (list->iterator.Next() != NULL); 623 } 624 625 return B_OK; 626 } 627 628 629 /*! \brief Resolves the device/directory node pair to the node it's covered 630 by, if any. 631 */ 632 void 633 NodeMonitorService::_ResolveMountPoint(dev_t device, ino_t directory, 634 dev_t& parentDevice, ino_t& parentDirectory) 635 { 636 struct vnode* vnode; 637 status_t status = vfs_get_vnode(device, directory, true, &vnode); 638 if (status == B_OK) { 639 if (vnode->covers != NULL) 640 status = vfs_resolve_parent(vnode, &parentDevice, &parentDirectory); 641 vfs_put_vnode(vnode); 642 } 643 if (status != B_OK) { 644 dprintf("Resolving mount point %" B_PRIdDEV ":%" B_PRIdINO " failed!" 645 "\n", device, directory); 646 } 647 } 648 649 650 /*! \brief Notifies all interested listeners that an entry has been created 651 or removed. 652 \param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED. 653 \param device The ID of the mounted FS, the entry lives/lived in. 654 \param directory The entry's parent directory ID. 655 \param name The entry's name. 656 \param node The ID of the node the entry refers/referred to. 657 \return 658 - \c B_OK, if everything went fine, 659 - another error code otherwise. 660 */ 661 status_t 662 NodeMonitorService::NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device, 663 ino_t directory, const char *name, ino_t node) 664 { 665 if (!name) 666 return B_BAD_VALUE; 667 668 RecursiveLocker locker(fRecursiveLock); 669 670 // get the lists of all interested listeners 671 interested_monitor_listener_list interestedListeners[3]; 672 int32 interestedListenerCount = 0; 673 // ... for the volume 674 _GetInterestedVolumeListeners(device, B_WATCH_NAME, 675 interestedListeners, interestedListenerCount); 676 // ... for the node 677 if (opcode != B_ENTRY_CREATED) { 678 _GetInterestedMonitorListeners(device, node, B_WATCH_NAME, 679 interestedListeners, interestedListenerCount); 680 } 681 // ... for the directory 682 _GetInterestedMonitorListeners(device, directory, B_WATCH_DIRECTORY, 683 interestedListeners, interestedListenerCount); 684 685 if (interestedListenerCount == 0) 686 return B_OK; 687 688 // there are interested listeners: construct the message and send it 689 char messageBuffer[1024]; 690 KMessage message; 691 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 692 message.AddInt32("opcode", opcode); 693 message.AddInt32("device", device); 694 message.AddInt64("directory", directory); 695 message.AddInt64("node", node); 696 message.AddString("name", name); // for "removed" Haiku only 697 698 return _SendNotificationMessage(message, interestedListeners, 699 interestedListenerCount); 700 } 701 702 703 inline status_t 704 NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory, 705 const char *fromName, ino_t toDirectory, const char *toName, 706 ino_t node) 707 { 708 if (!fromName || !toName) 709 return B_BAD_VALUE; 710 711 // If node is a mount point, we need to resolve it to the mounted 712 // volume's root node. 713 dev_t nodeDevice = device; 714 vfs_resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node); 715 716 RecursiveLocker locker(fRecursiveLock); 717 718 // get the lists of all interested listeners 719 interested_monitor_listener_list interestedListeners[4]; 720 int32 interestedListenerCount = 0; 721 // ... for the volume 722 _GetInterestedVolumeListeners(device, B_WATCH_NAME, 723 interestedListeners, interestedListenerCount); 724 // ... for the node 725 _GetInterestedMonitorListeners(nodeDevice, node, B_WATCH_NAME, 726 interestedListeners, interestedListenerCount); 727 // ... for the source directory 728 _GetInterestedMonitorListeners(device, fromDirectory, B_WATCH_DIRECTORY, 729 interestedListeners, interestedListenerCount); 730 // ... for the target directory 731 if (toDirectory != fromDirectory) { 732 _GetInterestedMonitorListeners(device, toDirectory, B_WATCH_DIRECTORY, 733 interestedListeners, interestedListenerCount); 734 } 735 736 if (interestedListenerCount == 0) 737 return B_OK; 738 739 // there are interested listeners: construct the message and send it 740 char messageBuffer[1024]; 741 KMessage message; 742 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 743 message.AddInt32("opcode", B_ENTRY_MOVED); 744 message.AddInt32("device", device); 745 message.AddInt64("from directory", fromDirectory); 746 message.AddInt64("to directory", toDirectory); 747 message.AddInt32("node device", nodeDevice); // Haiku only 748 message.AddInt64("node", node); 749 message.AddString("from name", fromName); // Haiku only 750 message.AddString("name", toName); 751 752 return _SendNotificationMessage(message, interestedListeners, 753 interestedListenerCount); 754 } 755 756 757 inline status_t 758 NodeMonitorService::NotifyStatChanged(dev_t device, ino_t directory, ino_t node, 759 uint32 statFields) 760 { 761 RecursiveLocker locker(fRecursiveLock); 762 763 // get the lists of all interested listeners depending on whether its an 764 // interim update or not 765 interested_monitor_listener_list interestedListeners[3]; 766 int32 interestedListenerCount = 0; 767 uint32 watchFlag = (statFields & B_STAT_INTERIM_UPDATE) != 0 768 ? B_WATCH_INTERIM_STAT : B_WATCH_STAT; 769 770 // ... for the volume 771 _GetInterestedVolumeListeners(device, watchFlag, interestedListeners, 772 interestedListenerCount); 773 // ... for the directory 774 if (directory > 0) { 775 dev_t parentDevice = device; 776 ino_t parentDirectory = directory; 777 if (directory == node) { 778 // This is a mount point -- get its file system parent 779 _ResolveMountPoint(device, directory, parentDevice, 780 parentDirectory); 781 } 782 _GetInterestedMonitorListeners(parentDevice, parentDirectory, 783 B_WATCH_CHILDREN | watchFlag, 784 interestedListeners, interestedListenerCount); 785 } 786 // ... and for the node 787 _GetInterestedMonitorListeners(device, node, watchFlag, 788 interestedListeners, interestedListenerCount); 789 790 if (interestedListenerCount == 0) 791 return B_OK; 792 793 // there are interested listeners: construct the message and send it 794 char messageBuffer[1024]; 795 KMessage message; 796 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 797 message.AddInt32("opcode", B_STAT_CHANGED); 798 message.AddInt32("device", device); 799 message.AddInt64("node", node); 800 message.AddInt32("fields", statFields); // Haiku only 801 802 return _SendNotificationMessage(message, interestedListeners, 803 interestedListenerCount); 804 } 805 806 807 /*! \brief Notifies all interested listeners that a node attribute has changed. 808 \param device The ID of the mounted FS, the node lives in. 809 \param node The ID of the node. 810 \param attribute The attribute's name. 811 \param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or 812 \c B_ATTR_CHANGED, indicating what exactly happened to the attribute. 813 \return 814 - \c B_OK, if everything went fine, 815 - another error code otherwise. 816 */ 817 status_t 818 NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t directory, 819 ino_t node, const char *attribute, int32 cause) 820 { 821 if (!attribute) 822 return B_BAD_VALUE; 823 824 RecursiveLocker locker(fRecursiveLock); 825 826 // get the lists of all interested listeners 827 interested_monitor_listener_list interestedListeners[3]; 828 int32 interestedListenerCount = 0; 829 // ... for the volume 830 _GetInterestedVolumeListeners(device, B_WATCH_ATTR, 831 interestedListeners, interestedListenerCount); 832 // ... for the directory 833 if (directory > 0) { 834 dev_t parentDevice = device; 835 ino_t parentDirectory = directory; 836 if (directory == node) { 837 // This is a mount point -- get its file system parent 838 _ResolveMountPoint(device, directory, parentDevice, 839 parentDirectory); 840 } 841 _GetInterestedMonitorListeners(parentDevice, parentDirectory, 842 B_WATCH_CHILDREN | B_WATCH_ATTR, 843 interestedListeners, interestedListenerCount); 844 } 845 // ... for the node 846 _GetInterestedMonitorListeners(device, node, B_WATCH_ATTR, 847 interestedListeners, interestedListenerCount); 848 849 if (interestedListenerCount == 0) 850 return B_OK; 851 852 // there are interested listeners: construct the message and send it 853 char messageBuffer[1024]; 854 KMessage message; 855 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 856 message.AddInt32("opcode", B_ATTR_CHANGED); 857 message.AddInt32("device", device); 858 if (directory >= 0) 859 message.AddInt64("directory", directory); 860 message.AddInt64("node", node); 861 message.AddString("attr", attribute); 862 message.AddInt32("cause", cause); // Haiku only 863 864 return _SendNotificationMessage(message, interestedListeners, 865 interestedListenerCount); 866 } 867 868 869 inline status_t 870 NodeMonitorService::NotifyUnmount(dev_t device) 871 { 872 TRACE(("unmounted device: %ld\n", device)); 873 874 RecursiveLocker locker(fRecursiveLock); 875 876 // get the lists of all interested listeners 877 interested_monitor_listener_list interestedListeners[3]; 878 int32 interestedListenerCount = 0; 879 _GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT, 880 interestedListeners, interestedListenerCount); 881 882 if (interestedListenerCount == 0) 883 return B_OK; 884 885 // there are interested listeners: construct the message and send it 886 char messageBuffer[96]; 887 KMessage message; 888 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 889 message.AddInt32("opcode", B_DEVICE_UNMOUNTED); 890 message.AddInt32("device", device); 891 892 return _SendNotificationMessage(message, interestedListeners, 893 interestedListenerCount); 894 } 895 896 897 inline status_t 898 NodeMonitorService::NotifyMount(dev_t device, dev_t parentDevice, 899 ino_t parentDirectory) 900 { 901 TRACE(("mounted device: %ld, parent %ld:%lld\n", device, parentDevice, 902 parentDirectory)); 903 904 RecursiveLocker locker(fRecursiveLock); 905 906 // get the lists of all interested listeners 907 interested_monitor_listener_list interestedListeners[3]; 908 int32 interestedListenerCount = 0; 909 _GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT, 910 interestedListeners, interestedListenerCount); 911 912 if (interestedListenerCount == 0) 913 return B_OK; 914 915 // there are interested listeners: construct the message and send it 916 char messageBuffer[128]; 917 KMessage message; 918 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 919 message.AddInt32("opcode", B_DEVICE_MOUNTED); 920 message.AddInt32("new device", device); 921 message.AddInt32("device", parentDevice); 922 message.AddInt64("directory", parentDirectory); 923 924 return _SendNotificationMessage(message, interestedListeners, 925 interestedListenerCount); 926 } 927 928 929 inline status_t 930 NodeMonitorService::RemoveListeners(io_context *context) 931 { 932 RecursiveLocker locker(fRecursiveLock); 933 934 while (!list_is_empty(&context->node_monitors)) { 935 // the _RemoveListener() method will also free the node_monitor 936 // if it doesn't have any listeners attached anymore 937 _RemoveListener( 938 (monitor_listener*)list_get_first_item(&context->node_monitors)); 939 } 940 941 return B_OK; 942 } 943 944 945 status_t 946 NodeMonitorService::AddListener(const KMessage* eventSpecifier, 947 NotificationListener& listener) 948 { 949 if (eventSpecifier == NULL) 950 return B_BAD_VALUE; 951 952 io_context *context = get_current_io_context( 953 eventSpecifier->GetBool("kernel", true)); 954 955 dev_t device = eventSpecifier->GetInt32("device", -1); 956 ino_t node = eventSpecifier->GetInt64("node", -1); 957 uint32 flags = eventSpecifier->GetInt32("flags", 0); 958 959 return AddListener(context, device, node, flags, listener); 960 } 961 962 963 status_t 964 NodeMonitorService::UpdateListener(const KMessage* eventSpecifier, 965 NotificationListener& listener) 966 { 967 if (eventSpecifier == NULL) 968 return B_BAD_VALUE; 969 970 io_context *context = get_current_io_context( 971 eventSpecifier->GetBool("kernel", true)); 972 973 dev_t device = eventSpecifier->GetInt32("device", -1); 974 ino_t node = eventSpecifier->GetInt64("node", -1); 975 uint32 flags = eventSpecifier->GetInt32("flags", 0); 976 bool addFlags = eventSpecifier->GetBool("add flags", false); 977 978 return _UpdateListener(context, device, node, flags, addFlags, listener); 979 } 980 981 982 status_t 983 NodeMonitorService::RemoveListener(const KMessage* eventSpecifier, 984 NotificationListener& listener) 985 { 986 if (eventSpecifier == NULL) 987 return B_BAD_VALUE; 988 989 io_context *context = get_current_io_context( 990 eventSpecifier->GetBool("kernel", true)); 991 992 dev_t device = eventSpecifier->GetInt32("device", -1); 993 ino_t node = eventSpecifier->GetInt64("node", -1); 994 995 return RemoveListener(context, device, node, listener); 996 } 997 998 999 status_t 1000 NodeMonitorService::RemoveListener(io_context *context, dev_t device, 1001 ino_t node, NotificationListener& notificationListener) 1002 { 1003 TRACE(("%s(dev = %ld, node = %lld, listener = %p\n", 1004 __PRETTY_FUNCTION__, device, node, ¬ificationListener)); 1005 1006 RecursiveLocker _(fRecursiveLock); 1007 1008 if (_RemoveListener(context, device, node, notificationListener, false) 1009 == B_OK) 1010 return B_OK; 1011 1012 return _RemoveListener(context, device, node, notificationListener, true); 1013 } 1014 1015 1016 inline status_t 1017 NodeMonitorService::RemoveUserListeners(struct io_context *context, 1018 port_id port, uint32 token) 1019 { 1020 UserNodeListener userListener(port, token); 1021 monitor_listener *listener = NULL; 1022 int32 count = 0; 1023 1024 RecursiveLocker _(fRecursiveLock); 1025 1026 while ((listener = (monitor_listener*)list_get_next_item( 1027 &context->node_monitors, listener)) != NULL) { 1028 monitor_listener *removeListener; 1029 1030 if (*listener->listener != userListener) 1031 continue; 1032 1033 listener = (monitor_listener*)list_get_prev_item( 1034 &context->node_monitors, removeListener = listener); 1035 // this line sets the listener one item back, allowing us 1036 // to remove its successor (which is saved in "removeListener") 1037 1038 _RemoveListener(removeListener); 1039 context->num_monitors--; 1040 count++; 1041 } 1042 1043 return count > 0 ? B_OK : B_ENTRY_NOT_FOUND; 1044 } 1045 1046 1047 status_t 1048 NodeMonitorService::UpdateUserListener(io_context *context, dev_t device, 1049 ino_t node, uint32 flags, UserNodeListener& userListener) 1050 { 1051 TRACE(("%s(dev = %ld, node = %lld, flags = %ld, listener = %p\n", 1052 __PRETTY_FUNCTION__, device, node, flags, &userListener)); 1053 1054 RecursiveLocker _(fRecursiveLock); 1055 1056 node_monitor *monitor; 1057 status_t status = _GetMonitor(context, device, node, true, &monitor, 1058 (flags & B_WATCH_VOLUME) != 0); 1059 if (status < B_OK) 1060 return status; 1061 1062 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 1063 while (monitor_listener* listener = iterator.Next()) { 1064 if (*listener->listener == userListener) { 1065 listener->flags |= flags; 1066 return B_OK; 1067 } 1068 } 1069 1070 UserNodeListener* copiedListener = new(std::nothrow) UserNodeListener( 1071 userListener); 1072 if (copiedListener == NULL) { 1073 if (monitor->listeners.IsEmpty()) 1074 _RemoveMonitor(monitor, flags); 1075 return B_NO_MEMORY; 1076 } 1077 1078 status = _AddMonitorListener(context, monitor, flags, *copiedListener); 1079 if (status != B_OK) 1080 delete copiedListener; 1081 1082 return status; 1083 } 1084 1085 1086 // #pragma mark - private kernel API 1087 1088 1089 status_t 1090 remove_node_monitors(struct io_context *context) 1091 { 1092 return sNodeMonitorService.RemoveListeners(context); 1093 } 1094 1095 1096 status_t 1097 node_monitor_init(void) 1098 { 1099 new(&sNodeMonitorSender) UserMessagingMessageSender(); 1100 new(&sNodeMonitorService) NodeMonitorService(); 1101 1102 if (sNodeMonitorService.InitCheck() < B_OK) 1103 panic("initializing node monitor failed\n"); 1104 1105 return B_OK; 1106 } 1107 1108 1109 status_t 1110 notify_unmount(dev_t device) 1111 { 1112 return sNodeMonitorService.NotifyUnmount(device); 1113 } 1114 1115 1116 status_t 1117 notify_mount(dev_t device, dev_t parentDevice, ino_t parentDirectory) 1118 { 1119 return sNodeMonitorService.NotifyMount(device, parentDevice, 1120 parentDirectory); 1121 } 1122 1123 1124 status_t 1125 remove_node_listener(dev_t device, ino_t node, NotificationListener& listener) 1126 { 1127 return sNodeMonitorService.RemoveListener(get_current_io_context(true), 1128 device, node, listener); 1129 } 1130 1131 1132 status_t 1133 add_node_listener(dev_t device, ino_t node, uint32 flags, 1134 NotificationListener& listener) 1135 { 1136 return sNodeMonitorService.AddListener(get_current_io_context(true), 1137 device, node, flags, listener); 1138 } 1139 1140 1141 // #pragma mark - public kernel API 1142 1143 1144 /*! \brief Notifies all interested listeners that an entry has been created. 1145 \param device The ID of the mounted FS, the entry lives in. 1146 \param directory The entry's parent directory ID. 1147 \param name The entry's name. 1148 \param node The ID of the node the entry refers to. 1149 \return 1150 - \c B_OK, if everything went fine, 1151 - another error code otherwise. 1152 */ 1153 status_t 1154 notify_entry_created(dev_t device, ino_t directory, const char *name, 1155 ino_t node) 1156 { 1157 return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_CREATED, 1158 device, directory, name, node); 1159 } 1160 1161 1162 /*! \brief Notifies all interested listeners that an entry has been removed. 1163 \param device The ID of the mounted FS, the entry lived in. 1164 \param directory The entry's former parent directory ID. 1165 \param name The entry's name. 1166 \param node The ID of the node the entry referred to. 1167 \return 1168 - \c B_OK, if everything went fine, 1169 - another error code otherwise. 1170 */ 1171 status_t 1172 notify_entry_removed(dev_t device, ino_t directory, const char *name, 1173 ino_t node) 1174 { 1175 return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_REMOVED, 1176 device, directory, name, node); 1177 } 1178 1179 1180 /*! \brief Notifies all interested listeners that an entry has been moved. 1181 \param device The ID of the mounted FS, the entry lives in. 1182 \param fromDirectory The entry's previous parent directory ID. 1183 \param fromName The entry's previous name. 1184 \param toDirectory The entry's new parent directory ID. 1185 \param toName The entry's new name. 1186 \param node The ID of the node the entry refers to. 1187 \return 1188 - \c B_OK, if everything went fine, 1189 - another error code otherwise. 1190 */ 1191 status_t 1192 notify_entry_moved(dev_t device, ino_t fromDirectory, 1193 const char *fromName, ino_t toDirectory, const char *toName, 1194 ino_t node) 1195 { 1196 return sNodeMonitorService.NotifyEntryMoved(device, fromDirectory, 1197 fromName, toDirectory, toName, node); 1198 } 1199 1200 1201 /*! \brief Notifies all interested listeners that a node's stat data have 1202 changed. 1203 \param device The ID of the mounted FS, the node lives in. 1204 \param node The ID of the node. 1205 \param statFields A bitwise combination of one or more of the \c B_STAT_* 1206 constants defined in <NodeMonitor.h>, indicating what fields of the 1207 stat data have changed. 1208 \return 1209 - \c B_OK, if everything went fine, 1210 - another error code otherwise. 1211 */ 1212 status_t 1213 notify_stat_changed(dev_t device, ino_t directory, ino_t node, 1214 uint32 statFields) 1215 { 1216 return sNodeMonitorService.NotifyStatChanged(device, directory, node, 1217 statFields); 1218 } 1219 1220 1221 /*! \brief Notifies all interested listeners that a node attribute has changed. 1222 \param device The ID of the mounted FS, the node lives in. 1223 \param node The ID of the node. 1224 \param attribute The attribute's name. 1225 \param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or 1226 \c B_ATTR_CHANGED, indicating what exactly happened to the attribute. 1227 \return 1228 - \c B_OK, if everything went fine, 1229 - another error code otherwise. 1230 */ 1231 status_t 1232 notify_attribute_changed(dev_t device, ino_t directory, ino_t node, 1233 const char *attribute, int32 cause) 1234 { 1235 return sNodeMonitorService.NotifyAttributeChanged(device, directory, node, 1236 attribute, cause); 1237 } 1238 1239 1240 /*! \brief Notifies the listener of a live query that an entry has been added 1241 to the query (for whatever reason). 1242 \param port The target port of the listener. 1243 \param token The BHandler token of the listener. 1244 \param device The ID of the mounted FS, the entry lives in. 1245 \param directory The entry's parent directory ID. 1246 \param name The entry's name. 1247 \param node The ID of the node the entry refers to. 1248 \return 1249 - \c B_OK, if everything went fine, 1250 - another error code otherwise. 1251 */ 1252 status_t 1253 notify_query_entry_created(port_id port, int32 token, dev_t device, 1254 ino_t directory, const char *name, ino_t node) 1255 { 1256 return notify_query_entry_event(B_ENTRY_CREATED, port, token, 1257 device, directory, name, node); 1258 } 1259 1260 1261 /*! \brief Notifies the listener of a live query that an entry has been removed 1262 from the query (for whatever reason). 1263 \param port The target port of the listener. 1264 \param token The BHandler token of the listener. 1265 \param device The ID of the mounted FS, the entry lives in. 1266 \param directory The entry's parent directory ID. 1267 \param name The entry's name. 1268 \param node The ID of the node the entry refers to. 1269 \return 1270 - \c B_OK, if everything went fine, 1271 - another error code otherwise. 1272 */ 1273 status_t 1274 notify_query_entry_removed(port_id port, int32 token, dev_t device, 1275 ino_t directory, const char *name, ino_t node) 1276 { 1277 return notify_query_entry_event(B_ENTRY_REMOVED, port, token, 1278 device, directory, name, node); 1279 } 1280 1281 1282 /*! \brief Notifies the listener of a live query that an entry has been changed 1283 and is still in the query (for whatever reason). 1284 \param port The target port of the listener. 1285 \param token The BHandler token of the listener. 1286 \param device The ID of the mounted FS, the entry lives in. 1287 \param directory The entry's parent directory ID. 1288 \param name The entry's name. 1289 \param node The ID of the node the entry refers to. 1290 \return 1291 - \c B_OK, if everything went fine, 1292 - another error code otherwise. 1293 */ 1294 status_t 1295 notify_query_attr_changed(port_id port, int32 token, dev_t device, 1296 ino_t directory, const char* name, ino_t node) 1297 { 1298 return notify_query_entry_event(B_ATTR_CHANGED, port, token, 1299 device, directory, name, node); 1300 } 1301 1302 1303 // #pragma mark - User syscalls 1304 1305 1306 // TODO: We should verify that the port specified in the syscalls does actually 1307 // belong to the calling team. The situation is complicated by the fact that a 1308 // port can be transferred to another team. Consequently we should remove all 1309 // associated monitor listeners when a port is transferred/deleted. 1310 1311 1312 status_t 1313 _user_stop_notifying(port_id port, uint32 token) 1314 { 1315 io_context *context = get_current_io_context(false); 1316 1317 return sNodeMonitorService.RemoveUserListeners(context, port, token); 1318 } 1319 1320 1321 status_t 1322 _user_start_watching(dev_t device, ino_t node, uint32 flags, port_id port, 1323 uint32 token) 1324 { 1325 io_context *context = get_current_io_context(false); 1326 1327 UserNodeListener listener(port, token); 1328 return sNodeMonitorService.UpdateUserListener(context, device, node, flags, 1329 listener); 1330 } 1331 1332 1333 status_t 1334 _user_stop_watching(dev_t device, ino_t node, port_id port, uint32 token) 1335 { 1336 io_context *context = get_current_io_context(false); 1337 1338 UserNodeListener listener(port, token); 1339 return sNodeMonitorService.RemoveListener(context, device, node, 1340 listener); 1341 } 1342 1343