xref: /haiku/src/system/kernel/fs/node_monitor.cpp (revision 8a6724a0ee3803f1e9f487d8111bb3f6cb8d16db)
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 %ld:%lld failed!\n", device, directory);
645 }
646 
647 
648 /*!	\brief Notifies all interested listeners that an entry has been created
649 		   or removed.
650 	\param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED.
651 	\param device The ID of the mounted FS, the entry lives/lived in.
652 	\param directory The entry's parent directory ID.
653 	\param name The entry's name.
654 	\param node The ID of the node the entry refers/referred to.
655 	\return
656 	- \c B_OK, if everything went fine,
657 	- another error code otherwise.
658 */
659 status_t
660 NodeMonitorService::NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device,
661 	ino_t directory, const char *name, ino_t node)
662 {
663 	if (!name)
664 		return B_BAD_VALUE;
665 
666 	RecursiveLocker locker(fRecursiveLock);
667 
668 	// get the lists of all interested listeners
669 	interested_monitor_listener_list interestedListeners[3];
670 	int32 interestedListenerCount = 0;
671 	// ... for the volume
672 	_GetInterestedVolumeListeners(device, B_WATCH_NAME,
673 		interestedListeners, interestedListenerCount);
674 	// ... for the node
675 	if (opcode != B_ENTRY_CREATED) {
676 		_GetInterestedMonitorListeners(device, node, B_WATCH_NAME,
677 			interestedListeners, interestedListenerCount);
678 	}
679 	// ... for the directory
680 	_GetInterestedMonitorListeners(device, directory, B_WATCH_DIRECTORY,
681 		interestedListeners, interestedListenerCount);
682 
683 	if (interestedListenerCount == 0)
684 		return B_OK;
685 
686 	// there are interested listeners: construct the message and send it
687 	char messageBuffer[1024];
688 	KMessage message;
689 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
690 	message.AddInt32("opcode", opcode);
691 	message.AddInt32("device", device);
692 	message.AddInt64("directory", directory);
693 	message.AddInt64("node", node);
694 	message.AddString("name", name);			// for "removed" Haiku only
695 
696 	return _SendNotificationMessage(message, interestedListeners,
697 		interestedListenerCount);
698 }
699 
700 
701 inline status_t
702 NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory,
703 	const char *fromName, ino_t toDirectory, const char *toName,
704 	ino_t node)
705 {
706 	if (!fromName || !toName)
707 		return B_BAD_VALUE;
708 
709 	// If node is a mount point, we need to resolve it to the mounted
710 	// volume's root node.
711 	dev_t nodeDevice = device;
712 	vfs_resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node);
713 
714 	RecursiveLocker locker(fRecursiveLock);
715 
716 	// get the lists of all interested listeners
717 	interested_monitor_listener_list interestedListeners[4];
718 	int32 interestedListenerCount = 0;
719 	// ... for the volume
720 	_GetInterestedVolumeListeners(device, B_WATCH_NAME,
721 		interestedListeners, interestedListenerCount);
722 	// ... for the node
723 	_GetInterestedMonitorListeners(nodeDevice, node, B_WATCH_NAME,
724 		interestedListeners, interestedListenerCount);
725 	// ... for the source directory
726 	_GetInterestedMonitorListeners(device, fromDirectory, B_WATCH_DIRECTORY,
727 		interestedListeners, interestedListenerCount);
728 	// ... for the target directory
729 	if (toDirectory != fromDirectory) {
730 		_GetInterestedMonitorListeners(device, toDirectory, B_WATCH_DIRECTORY,
731 			interestedListeners, interestedListenerCount);
732 	}
733 
734 	if (interestedListenerCount == 0)
735 		return B_OK;
736 
737 	// there are interested listeners: construct the message and send it
738 	char messageBuffer[1024];
739 	KMessage message;
740 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
741 	message.AddInt32("opcode", B_ENTRY_MOVED);
742 	message.AddInt32("device", device);
743 	message.AddInt64("from directory", fromDirectory);
744 	message.AddInt64("to directory", toDirectory);
745 	message.AddInt32("node device", nodeDevice);	// Haiku only
746 	message.AddInt64("node", node);
747 	message.AddString("from name", fromName);		// Haiku only
748 	message.AddString("name", toName);
749 
750 	return _SendNotificationMessage(message, interestedListeners,
751 		interestedListenerCount);
752 }
753 
754 
755 inline status_t
756 NodeMonitorService::NotifyStatChanged(dev_t device, ino_t directory, ino_t node,
757 	uint32 statFields)
758 {
759 	RecursiveLocker locker(fRecursiveLock);
760 
761 	// get the lists of all interested listeners depending on whether its an
762 	// interim update or not
763 	interested_monitor_listener_list interestedListeners[3];
764 	int32 interestedListenerCount = 0;
765 	uint32 watchFlag = (statFields & B_STAT_INTERIM_UPDATE) != 0
766 		? B_WATCH_INTERIM_STAT : B_WATCH_STAT;
767 
768 	// ... for the volume
769 	_GetInterestedVolumeListeners(device, watchFlag, interestedListeners,
770 		interestedListenerCount);
771 	// ... for the directory
772 	if (directory > 0) {
773 		dev_t parentDevice = device;
774 		ino_t parentDirectory = directory;
775 		if (directory == node) {
776 			// This is a mount point -- get its file system parent
777 			_ResolveMountPoint(device, directory, parentDevice,
778 				parentDirectory);
779 		}
780 		_GetInterestedMonitorListeners(parentDevice, parentDirectory,
781 			B_WATCH_CHILDREN | watchFlag,
782 			interestedListeners, interestedListenerCount);
783 	}
784 	// ... and for the node
785 	_GetInterestedMonitorListeners(device, node, watchFlag,
786 		interestedListeners, interestedListenerCount);
787 
788 	if (interestedListenerCount == 0)
789 		return B_OK;
790 
791 	// there are interested listeners: construct the message and send it
792 	char messageBuffer[1024];
793 	KMessage message;
794 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
795 	message.AddInt32("opcode", B_STAT_CHANGED);
796 	message.AddInt32("device", device);
797 	message.AddInt64("node", node);
798 	message.AddInt32("fields", statFields);		// Haiku only
799 
800 	return _SendNotificationMessage(message, interestedListeners,
801 		interestedListenerCount);
802 }
803 
804 
805 /*!	\brief Notifies all interested listeners that a node attribute has changed.
806 	\param device The ID of the mounted FS, the node lives in.
807 	\param node The ID of the node.
808 	\param attribute The attribute's name.
809 	\param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or
810 		   \c B_ATTR_CHANGED, indicating what exactly happened to the attribute.
811 	\return
812 	- \c B_OK, if everything went fine,
813 	- another error code otherwise.
814 */
815 status_t
816 NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t directory,
817 	ino_t node, const char *attribute, int32 cause)
818 {
819 	if (!attribute)
820 		return B_BAD_VALUE;
821 
822 	RecursiveLocker locker(fRecursiveLock);
823 
824 	// get the lists of all interested listeners
825 	interested_monitor_listener_list interestedListeners[3];
826 	int32 interestedListenerCount = 0;
827 	// ... for the volume
828 	_GetInterestedVolumeListeners(device, B_WATCH_ATTR,
829 		interestedListeners, interestedListenerCount);
830 	// ... for the directory
831 	if (directory > 0) {
832 		dev_t parentDevice = device;
833 		ino_t parentDirectory = directory;
834 		if (directory == node) {
835 			// This is a mount point -- get its file system parent
836 			_ResolveMountPoint(device, directory, parentDevice,
837 				parentDirectory);
838 		}
839 		_GetInterestedMonitorListeners(parentDevice, parentDirectory,
840 			B_WATCH_CHILDREN | B_WATCH_ATTR,
841 			interestedListeners, interestedListenerCount);
842 	}
843 	// ... for the node
844 	_GetInterestedMonitorListeners(device, node, B_WATCH_ATTR,
845 		interestedListeners, interestedListenerCount);
846 
847 	if (interestedListenerCount == 0)
848 		return B_OK;
849 
850 	// there are interested listeners: construct the message and send it
851 	char messageBuffer[1024];
852 	KMessage message;
853 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
854 	message.AddInt32("opcode", B_ATTR_CHANGED);
855 	message.AddInt32("device", device);
856 	if (directory >= 0)
857 		message.AddInt64("directory", directory);
858 	message.AddInt64("node", node);
859 	message.AddString("attr", attribute);
860 	message.AddInt32("cause", cause);		// Haiku only
861 
862 	return _SendNotificationMessage(message, interestedListeners,
863 		interestedListenerCount);
864 }
865 
866 
867 inline status_t
868 NodeMonitorService::NotifyUnmount(dev_t device)
869 {
870 	TRACE(("unmounted device: %ld\n", device));
871 
872 	RecursiveLocker locker(fRecursiveLock);
873 
874 	// get the lists of all interested listeners
875 	interested_monitor_listener_list interestedListeners[3];
876 	int32 interestedListenerCount = 0;
877 	_GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT,
878 		interestedListeners, interestedListenerCount);
879 
880 	if (interestedListenerCount == 0)
881 		return B_OK;
882 
883 	// there are interested listeners: construct the message and send it
884 	char messageBuffer[96];
885 	KMessage message;
886 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
887 	message.AddInt32("opcode", B_DEVICE_UNMOUNTED);
888 	message.AddInt32("device", device);
889 
890 	return _SendNotificationMessage(message, interestedListeners,
891 		interestedListenerCount);
892 }
893 
894 
895 inline status_t
896 NodeMonitorService::NotifyMount(dev_t device, dev_t parentDevice,
897 	ino_t parentDirectory)
898 {
899 	TRACE(("mounted device: %ld, parent %ld:%Ld\n", device, parentDevice,
900 		parentDirectory));
901 
902 	RecursiveLocker locker(fRecursiveLock);
903 
904 	// get the lists of all interested listeners
905 	interested_monitor_listener_list interestedListeners[3];
906 	int32 interestedListenerCount = 0;
907 	_GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT,
908 		interestedListeners, interestedListenerCount);
909 
910 	if (interestedListenerCount == 0)
911 		return B_OK;
912 
913 	// there are interested listeners: construct the message and send it
914 	char messageBuffer[128];
915 	KMessage message;
916 	message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
917 	message.AddInt32("opcode", B_DEVICE_MOUNTED);
918 	message.AddInt32("new device", device);
919 	message.AddInt32("device", parentDevice);
920 	message.AddInt64("directory", parentDirectory);
921 
922 	return _SendNotificationMessage(message, interestedListeners,
923 		interestedListenerCount);
924 }
925 
926 
927 inline status_t
928 NodeMonitorService::RemoveListeners(io_context *context)
929 {
930 	RecursiveLocker locker(fRecursiveLock);
931 
932 	while (!list_is_empty(&context->node_monitors)) {
933 		// the _RemoveListener() method will also free the node_monitor
934 		// if it doesn't have any listeners attached anymore
935 		_RemoveListener(
936 			(monitor_listener*)list_get_first_item(&context->node_monitors));
937 	}
938 
939 	return B_OK;
940 }
941 
942 
943 status_t
944 NodeMonitorService::AddListener(const KMessage* eventSpecifier,
945 	NotificationListener& listener)
946 {
947 	if (eventSpecifier == NULL)
948 		return B_BAD_VALUE;
949 
950 	io_context *context = get_current_io_context(
951 		eventSpecifier->GetBool("kernel", true));
952 
953 	dev_t device = eventSpecifier->GetInt32("device", -1);
954 	ino_t node = eventSpecifier->GetInt64("node", -1);
955 	uint32 flags = eventSpecifier->GetInt32("flags", 0);
956 
957 	return AddListener(context, device, node, flags, listener);
958 }
959 
960 
961 status_t
962 NodeMonitorService::UpdateListener(const KMessage* eventSpecifier,
963 	NotificationListener& listener)
964 {
965 	if (eventSpecifier == NULL)
966 		return B_BAD_VALUE;
967 
968 	io_context *context = get_current_io_context(
969 		eventSpecifier->GetBool("kernel", true));
970 
971 	dev_t device = eventSpecifier->GetInt32("device", -1);
972 	ino_t node = eventSpecifier->GetInt64("node", -1);
973 	uint32 flags = eventSpecifier->GetInt32("flags", 0);
974 	bool addFlags = eventSpecifier->GetBool("add flags", false);
975 
976 	return _UpdateListener(context, device, node, flags, addFlags, listener);
977 }
978 
979 
980 status_t
981 NodeMonitorService::RemoveListener(const KMessage* eventSpecifier,
982 	NotificationListener& listener)
983 {
984 	if (eventSpecifier == NULL)
985 		return B_BAD_VALUE;
986 
987 	io_context *context = get_current_io_context(
988 		eventSpecifier->GetBool("kernel", true));
989 
990 	dev_t device = eventSpecifier->GetInt32("device", -1);
991 	ino_t node = eventSpecifier->GetInt64("node", -1);
992 
993 	return RemoveListener(context, device, node, listener);
994 }
995 
996 
997 status_t
998 NodeMonitorService::RemoveListener(io_context *context, dev_t device,
999 	ino_t node, NotificationListener& notificationListener)
1000 {
1001 	TRACE(("%s(dev = %ld, node = %Ld, listener = %p\n",
1002 		__PRETTY_FUNCTION__, device, node, &notificationListener));
1003 
1004 	RecursiveLocker _(fRecursiveLock);
1005 
1006 	if (_RemoveListener(context, device, node, notificationListener, false)
1007 		== B_OK)
1008 		return B_OK;
1009 
1010 	return _RemoveListener(context, device, node, notificationListener, true);
1011 }
1012 
1013 
1014 inline status_t
1015 NodeMonitorService::RemoveUserListeners(struct io_context *context,
1016 	port_id port, uint32 token)
1017 {
1018 	UserNodeListener userListener(port, token);
1019 	monitor_listener *listener = NULL;
1020 	int32 count = 0;
1021 
1022 	RecursiveLocker _(fRecursiveLock);
1023 
1024 	while ((listener = (monitor_listener*)list_get_next_item(
1025 			&context->node_monitors, listener)) != NULL) {
1026 		monitor_listener *removeListener;
1027 
1028 		if (*listener->listener != userListener)
1029 			continue;
1030 
1031 		listener = (monitor_listener*)list_get_prev_item(
1032 			&context->node_monitors, removeListener = listener);
1033 			// this line sets the listener one item back, allowing us
1034 			// to remove its successor (which is saved in "removeListener")
1035 
1036 		_RemoveListener(removeListener);
1037 		context->num_monitors--;
1038 		count++;
1039 	}
1040 
1041 	return count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
1042 }
1043 
1044 
1045 status_t
1046 NodeMonitorService::UpdateUserListener(io_context *context, dev_t device,
1047 	ino_t node, uint32 flags, UserNodeListener& userListener)
1048 {
1049 	TRACE(("%s(dev = %ld, node = %Ld, flags = %ld, listener = %p\n",
1050 		__PRETTY_FUNCTION__, device, node, flags, &userListener));
1051 
1052 	RecursiveLocker _(fRecursiveLock);
1053 
1054 	node_monitor *monitor;
1055 	status_t status = _GetMonitor(context, device, node, true, &monitor,
1056 		(flags & B_WATCH_VOLUME) != 0);
1057 	if (status < B_OK)
1058 		return status;
1059 
1060 	MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator();
1061 	while (monitor_listener* listener = iterator.Next()) {
1062 		if (*listener->listener == userListener) {
1063 			listener->flags |= flags;
1064 			return B_OK;
1065 		}
1066 	}
1067 
1068 	UserNodeListener* copiedListener = new(std::nothrow) UserNodeListener(
1069 		userListener);
1070 	if (copiedListener == NULL) {
1071 		if (monitor->listeners.IsEmpty())
1072 			_RemoveMonitor(monitor, flags);
1073 		return B_NO_MEMORY;
1074 	}
1075 
1076 	status = _AddMonitorListener(context, monitor, flags, *copiedListener);
1077 	if (status != B_OK)
1078 		delete copiedListener;
1079 
1080 	return status;
1081 }
1082 
1083 
1084 //	#pragma mark - private kernel API
1085 
1086 
1087 status_t
1088 remove_node_monitors(struct io_context *context)
1089 {
1090 	return sNodeMonitorService.RemoveListeners(context);
1091 }
1092 
1093 
1094 status_t
1095 node_monitor_init(void)
1096 {
1097 	new(&sNodeMonitorSender) UserMessagingMessageSender();
1098 	new(&sNodeMonitorService) NodeMonitorService();
1099 
1100 	if (sNodeMonitorService.InitCheck() < B_OK)
1101 		panic("initializing node monitor failed\n");
1102 
1103 	return B_OK;
1104 }
1105 
1106 
1107 status_t
1108 notify_unmount(dev_t device)
1109 {
1110 	return sNodeMonitorService.NotifyUnmount(device);
1111 }
1112 
1113 
1114 status_t
1115 notify_mount(dev_t device, dev_t parentDevice, ino_t parentDirectory)
1116 {
1117 	return sNodeMonitorService.NotifyMount(device, parentDevice,
1118 		parentDirectory);
1119 }
1120 
1121 
1122 status_t
1123 remove_node_listener(dev_t device, ino_t node, NotificationListener& listener)
1124 {
1125 	return sNodeMonitorService.RemoveListener(get_current_io_context(true),
1126 		device, node, listener);
1127 }
1128 
1129 
1130 status_t
1131 add_node_listener(dev_t device, ino_t node, uint32 flags,
1132 	NotificationListener& listener)
1133 {
1134 	return sNodeMonitorService.AddListener(get_current_io_context(true),
1135 		device, node, flags, listener);
1136 }
1137 
1138 
1139 //	#pragma mark - public kernel API
1140 
1141 
1142 /*!	\brief Notifies all interested listeners that an entry has been created.
1143   	\param device The ID of the mounted FS, the entry lives in.
1144   	\param directory The entry's parent directory ID.
1145   	\param name The entry's name.
1146   	\param node The ID of the node the entry refers to.
1147   	\return
1148   	- \c B_OK, if everything went fine,
1149   	- another error code otherwise.
1150 */
1151 status_t
1152 notify_entry_created(dev_t device, ino_t directory, const char *name,
1153 	ino_t node)
1154 {
1155 	return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_CREATED,
1156 		device, directory, name, node);
1157 }
1158 
1159 
1160 /*!	\brief Notifies all interested listeners that an entry has been removed.
1161   	\param device The ID of the mounted FS, the entry lived in.
1162   	\param directory The entry's former parent directory ID.
1163   	\param name The entry's name.
1164   	\param node The ID of the node the entry referred to.
1165   	\return
1166   	- \c B_OK, if everything went fine,
1167   	- another error code otherwise.
1168 */
1169 status_t
1170 notify_entry_removed(dev_t device, ino_t directory, const char *name,
1171 	ino_t node)
1172 {
1173 	return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_REMOVED,
1174 		device, directory, name, node);
1175 }
1176 
1177 
1178 /*!	\brief Notifies all interested listeners that an entry has been moved.
1179   	\param device The ID of the mounted FS, the entry lives in.
1180   	\param fromDirectory The entry's previous parent directory ID.
1181   	\param fromName The entry's previous name.
1182   	\param toDirectory The entry's new parent directory ID.
1183   	\param toName The entry's new name.
1184   	\param node The ID of the node the entry refers to.
1185   	\return
1186   	- \c B_OK, if everything went fine,
1187   	- another error code otherwise.
1188 */
1189 status_t
1190 notify_entry_moved(dev_t device, ino_t fromDirectory,
1191 	const char *fromName, ino_t toDirectory, const char *toName,
1192 	ino_t node)
1193 {
1194 	return sNodeMonitorService.NotifyEntryMoved(device, fromDirectory,
1195 		fromName, toDirectory, toName, node);
1196 }
1197 
1198 
1199 /*!	\brief Notifies all interested listeners that a node's stat data have
1200   		   changed.
1201   	\param device The ID of the mounted FS, the node lives in.
1202   	\param node The ID of the node.
1203   	\param statFields A bitwise combination of one or more of the \c B_STAT_*
1204   		   constants defined in <NodeMonitor.h>, indicating what fields of the
1205   		   stat data have changed.
1206   	\return
1207   	- \c B_OK, if everything went fine,
1208   	- another error code otherwise.
1209 */
1210 status_t
1211 notify_stat_changed(dev_t device, ino_t directory, ino_t node,
1212 	uint32 statFields)
1213 {
1214 	return sNodeMonitorService.NotifyStatChanged(device, directory, node,
1215 		statFields);
1216 }
1217 
1218 
1219 /*!	\brief Notifies all interested listeners that a node attribute has changed.
1220   	\param device The ID of the mounted FS, the node lives in.
1221   	\param node The ID of the node.
1222   	\param attribute The attribute's name.
1223   	\param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or
1224   		   \c B_ATTR_CHANGED, indicating what exactly happened to the attribute.
1225   	\return
1226   	- \c B_OK, if everything went fine,
1227   	- another error code otherwise.
1228 */
1229 status_t
1230 notify_attribute_changed(dev_t device, ino_t directory, ino_t node,
1231 	const char *attribute, int32 cause)
1232 {
1233 	return sNodeMonitorService.NotifyAttributeChanged(device, directory, node,
1234 		attribute, cause);
1235 }
1236 
1237 
1238 /*!	\brief Notifies the listener of a live query that an entry has been added
1239   		   to the query (for whatever reason).
1240   	\param port The target port of the listener.
1241   	\param token The BHandler token of the listener.
1242   	\param device The ID of the mounted FS, the entry lives in.
1243   	\param directory The entry's parent directory ID.
1244   	\param name The entry's name.
1245   	\param node The ID of the node the entry refers to.
1246   	\return
1247   	- \c B_OK, if everything went fine,
1248   	- another error code otherwise.
1249 */
1250 status_t
1251 notify_query_entry_created(port_id port, int32 token, dev_t device,
1252 	ino_t directory, const char *name, ino_t node)
1253 {
1254 	return notify_query_entry_event(B_ENTRY_CREATED, port, token,
1255 		device, directory, name, node);
1256 }
1257 
1258 
1259 /*!	\brief Notifies the listener of a live query that an entry has been removed
1260   		   from the query (for whatever reason).
1261   	\param port The target port of the listener.
1262   	\param token The BHandler token of the listener.
1263   	\param device The ID of the mounted FS, the entry lives in.
1264   	\param directory The entry's parent directory ID.
1265   	\param name The entry's name.
1266   	\param node The ID of the node the entry refers to.
1267   	\return
1268   	- \c B_OK, if everything went fine,
1269   	- another error code otherwise.
1270 */
1271 status_t
1272 notify_query_entry_removed(port_id port, int32 token, dev_t device,
1273 	ino_t directory, const char *name, ino_t node)
1274 {
1275 	return notify_query_entry_event(B_ENTRY_REMOVED, port, token,
1276 		device, directory, name, node);
1277 }
1278 
1279 
1280 /*!	\brief Notifies the listener of a live query that an entry has been changed
1281   		   and is still in the query (for whatever reason).
1282   	\param port The target port of the listener.
1283   	\param token The BHandler token of the listener.
1284   	\param device The ID of the mounted FS, the entry lives in.
1285   	\param directory The entry's parent directory ID.
1286   	\param name The entry's name.
1287   	\param node The ID of the node the entry refers to.
1288   	\return
1289   	- \c B_OK, if everything went fine,
1290   	- another error code otherwise.
1291 */
1292 status_t
1293 notify_query_attr_changed(port_id port, int32 token, dev_t device,
1294 	ino_t directory, const char* name, ino_t node)
1295 {
1296 	return notify_query_entry_event(B_ATTR_CHANGED, port, token,
1297 		device, directory, name, node);
1298 }
1299 
1300 
1301 //	#pragma mark - User syscalls
1302 
1303 
1304 // TODO: We should verify that the port specified in the syscalls does actually
1305 // belong to the calling team. The situation is complicated by the fact that a
1306 // port can be transferred to another team. Consequently we should remove all
1307 // associated monitor listeners when a port is transferred/deleted.
1308 
1309 
1310 status_t
1311 _user_stop_notifying(port_id port, uint32 token)
1312 {
1313 	io_context *context = get_current_io_context(false);
1314 
1315 	return sNodeMonitorService.RemoveUserListeners(context, port, token);
1316 }
1317 
1318 
1319 status_t
1320 _user_start_watching(dev_t device, ino_t node, uint32 flags, port_id port,
1321 	uint32 token)
1322 {
1323 	io_context *context = get_current_io_context(false);
1324 
1325 	UserNodeListener listener(port, token);
1326 	return sNodeMonitorService.UpdateUserListener(context, device, node, flags,
1327 		listener);
1328 }
1329 
1330 
1331 status_t
1332 _user_stop_watching(dev_t device, ino_t node, port_id port, uint32 token)
1333 {
1334 	io_context *context = get_current_io_context(false);
1335 
1336 	UserNodeListener listener(port, token);
1337 	return sNodeMonitorService.RemoveListener(context, device, node,
1338 		listener);
1339 }
1340 
1341