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