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