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