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