xref: /haiku/src/system/kernel/fs/node_monitor.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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:
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 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 &notificationListener);
120 		status_t RemoveListener(io_context *context, dev_t device, ino_t node,
121 			NotificationListener &notificationListener);
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 
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 &notificationListener);
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 
169 			size_t HashKey(monitor_hash_key* key) const
170 				{ return _Hash(key->device, key->node); }
171 			size_t Hash(node_monitor *monitor) const
172 				{ return _Hash(monitor->device, monitor->node); }
173 
174 			bool Compare(monitor_hash_key* key, node_monitor *monitor) const
175 			{
176 				return key->device == monitor->device
177 					&& key->node == monitor->node;
178 			}
179 
180 			node_monitor*& GetLink(node_monitor* monitor) const
181 				{ return monitor->hash_link; }
182 
183 			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 
195 			size_t HashKey(dev_t key) const
196 				{ return _Hash(key); }
197 			size_t Hash(node_monitor *monitor) const
198 				{ return _Hash(monitor->device); }
199 
200 			bool Compare(dev_t key, node_monitor *monitor) const
201 			{
202 				return key == monitor->device;
203 			}
204 
205 			node_monitor*& GetLink(node_monitor* monitor) const
206 				{ return monitor->hash_link; }
207 
208 			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
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 
267 NodeMonitorService::NodeMonitorService()
268 {
269 	recursive_lock_init(&fRecursiveLock, "node monitor");
270 }
271 
272 
273 NodeMonitorService::~NodeMonitorService()
274 {
275 	recursive_lock_destroy(&fRecursiveLock);
276 }
277 
278 
279 status_t
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
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
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 = %Ld, listener = %p\n",
308 		__PRETTY_FUNCTION__, device, node, &notificationListener));
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
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 *
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
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*
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
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 = &notificationListener;
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
469 NodeMonitorService::AddListener(io_context *context, dev_t device, ino_t node,
470 	uint32 flags, NotificationListener& notificationListener)
471 {
472 	TRACE(("%s(dev = %ld, node = %Ld, flags = %ld, listener = %p\n",
473 		__PRETTY_FUNCTION__, device, node, flags, &notificationListener));
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
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 = %Ld, flags = %ld, listener = %p\n",
495 		__PRETTY_FUNCTION__, device, node, flags, &notificationListener));
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
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
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
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
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
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
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
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
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
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
898 NodeMonitorService::NotifyMount(dev_t device, dev_t parentDevice,
899 	ino_t parentDirectory)
900 {
901 	TRACE(("mounted device: %ld, parent %ld:%Ld\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
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
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
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
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
1000 NodeMonitorService::RemoveListener(io_context *context, dev_t device,
1001 	ino_t node, NotificationListener& notificationListener)
1002 {
1003 	TRACE(("%s(dev = %ld, node = %Ld, listener = %p\n",
1004 		__PRETTY_FUNCTION__, device, node, &notificationListener));
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
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
1048 NodeMonitorService::UpdateUserListener(io_context *context, dev_t device,
1049 	ino_t node, uint32 flags, UserNodeListener& userListener)
1050 {
1051 	TRACE(("%s(dev = %ld, node = %Ld, 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
1090 remove_node_monitors(struct io_context *context)
1091 {
1092 	return sNodeMonitorService.RemoveListeners(context);
1093 }
1094 
1095 
1096 status_t
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
1110 notify_unmount(dev_t device)
1111 {
1112 	return sNodeMonitorService.NotifyUnmount(device);
1113 }
1114 
1115 
1116 status_t
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
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
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
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
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
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
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
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
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
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
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
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
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
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