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