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