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