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