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