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