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