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