[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haiku-commits
Subject:    [haiku-commits] haiku: hrev50171 - in src: system/kernel/fs add-ons/kernel/file_systems/ntfs add-ons
From:       axeld () pinc-software ! de
Date:       2016-03-28 14:18:53
Message-ID: 20160328141853.9B5CD5C0BD0 () vmrepo ! haiku-os ! org
[Download RAW message or body]

hrev50171 adds 2 changesets to branch 'master'
old head: 55f28f13961064eb5fd7b9663ff6521e58a79657
new head: 67988f501a67260d2dd434d517d08dcef29807e0
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=67988f501a67+%5E55f28f139610

----------------------------------------------------------------------------

6f7fc2204ba9: NodeMonitor: Added B_WATCH_CHILDREN flag.
  
  * Added a directory argument for notify_{stat/attribute}_changed().
  * This allows to watch only a directory, and get the notifications for
    all of its files, not just add/remove entry notifications.

67988f501a67: NodeMonitor: Resolve mount points for B_WATCH_CHILDREN.
  
  * When a watched directory contains a mount point, we need to resolve
    the actual parent directory of the mount point in the file system to
    serve the monitor.

                                   [ Axel Dörfler <axeld@pinc-software.de> ]

----------------------------------------------------------------------------

33 files changed, 460 insertions(+), 338 deletions(-)
headers/os/drivers/fs_interface.h                |   8 +-
headers/os/kernel/fs_info.h                      |   3 +-
headers/os/storage/NodeMonitor.h                 |   5 +-
headers/private/fs_shell/fssh_api_wrapper.h      |   1 +
headers/private/fs_shell/fssh_fs_info.h          |   1 +
headers/private/fs_shell/fssh_fs_interface.h     |   7 +-
headers/private/kernel/vfs.h                     |   4 +-
src/add-ons/kernel/file_systems/bfs/Inode.h      |   5 +-
.../kernel/file_systems/bfs/kernel_interface.cpp |  21 +--
.../file_systems/btrfs/kernel_interface.cpp      |   6 +-
.../file_systems/cdda/kernel_interface.cpp       |  10 +-
.../file_systems/exfat/kernel_interface.cpp      |   4 +-
.../file_systems/ext2/kernel_interface.cpp       |   8 +-
src/add-ons/kernel/file_systems/fat/file.c       |   4 +-
.../kernel/file_systems/googlefs/googlefs.c      | 102 ++++++------
.../attribute_overlay/attribute_overlay.cpp      |   9 +-
.../layers/write_overlay/write_overlay.cpp       |  30 ++--
src/add-ons/kernel/file_systems/nfs/nfs_add_on.c |   2 +-
.../kernel/file_systems/nfs4/DirectoryCache.cpp  |   6 +-
src/add-ons/kernel/file_systems/nfs4/Inode.cpp   |  10 +-
.../kernel/file_systems/nfs4/MetadataCache.cpp   |   7 +-
.../kernel/file_systems/ntfs/attributes.c        | 109 ++++++-------
src/add-ons/kernel/file_systems/ntfs/fs_func.c   | 154 +++++++++----------
.../file_systems/packagefs/volume/Volume.cpp     |  10 +-
src/add-ons/kernel/file_systems/ramfs/Jamfile    |   3 +-
.../file_systems/ramfs/kernel_interface.cpp      |  18 +--
.../kernel_add_on/KernelRequestHandler.cpp       |   7 +-
.../userlandfs/server/haiku/haiku_kernel_emu.cpp |  11 +-
src/system/kernel/device_manager/devfs.cpp       |  23 ++-
src/system/kernel/fs/node_monitor.cpp            |  99 +++++++++---
src/system/kernel/fs/rootfs.cpp                  |  19 ++-
src/system/kernel/fs/vfs.cpp                     |  84 ++++++----
src/tools/fs_shell/node_monitor.cpp              |   8 +-

############################################################################

Commit:      6f7fc2204ba9aa1329eb27461240b026c7a813ed
URL:         http://cgit.haiku-os.org/haiku/commit/?id=6f7fc2204ba9
Author:      Axel Dörfler <axeld@pinc-software.de>
Date:        Mon Mar  7 20:14:25 2016 UTC

NodeMonitor: Added B_WATCH_CHILDREN flag.

* Added a directory argument for notify_{stat/attribute}_changed().
* This allows to watch only a directory, and get the notifications for
  all of its files, not just add/remove entry notifications.

----------------------------------------------------------------------------

diff --git a/headers/os/drivers/fs_interface.h b/headers/os/drivers/fs_interface.h
index 2aa195d..96b69fa 100644
--- a/headers/os/drivers/fs_interface.h
+++ b/headers/os/drivers/fs_interface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2014, Haiku Inc. All Rights Reserved.
+ * Copyright 2004-2016, Haiku Inc. All Rights Reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _FS_INTERFACE_H
@@ -358,10 +358,10 @@ extern status_t notify_entry_removed(dev_t device, ino_t \
directory,  extern status_t notify_entry_moved(dev_t device, ino_t fromDirectory,
 					const char* fromName, ino_t toDirectory,
 					const char* toName, ino_t node);
-extern status_t notify_stat_changed(dev_t device, ino_t node,
+extern status_t notify_stat_changed(dev_t device, ino_t directory, ino_t node,
 					uint32 statFields);
-extern status_t notify_attribute_changed(dev_t device, ino_t node,
-					const char* attribute, int32 cause);
+extern status_t notify_attribute_changed(dev_t device, ino_t directory,
+					ino_t node, const char* attribute, int32 cause);
 
 extern status_t notify_query_entry_created(port_id port, int32 token,
 					dev_t device, ino_t directory, const char* name,
diff --git a/headers/os/kernel/fs_info.h b/headers/os/kernel/fs_info.h
index 13935ca..546dd45 100644
--- a/headers/os/kernel/fs_info.h
+++ b/headers/os/kernel/fs_info.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2003, Haiku Inc. All Rights Reserved.
+ * Copyright 2002-2016, Haiku Inc. All Rights Reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _FS_INFO_H
@@ -20,6 +20,7 @@
 #define B_FS_HAS_SELF_HEALING_LINKS		0x00080000
 #define B_FS_HAS_ALIASES				0x00100000
 #define B_FS_SUPPORTS_NODE_MONITORING	0x00200000
+#define B_FS_SUPPORTS_MONITOR_CHILDREN	0x00400000
 
 typedef struct fs_info {
 	dev_t	dev;								/* volume dev_t */
diff --git a/headers/os/storage/NodeMonitor.h b/headers/os/storage/NodeMonitor.h
index abd3832..45ddfa6 100644
--- a/headers/os/storage/NodeMonitor.h
+++ b/headers/os/storage/NodeMonitor.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2010 Haiku Inc. All rights reserved.
+ * Copyright 2003-2016 Haiku Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _NODE_MONITOR_H
@@ -23,7 +23,8 @@ enum {
 	B_WATCH_ALL				= 0x000f,
 
 	B_WATCH_MOUNT			= 0x0010,
-	B_WATCH_INTERIM_STAT	= 0x0020
+	B_WATCH_INTERIM_STAT	= 0x0020,
+	B_WATCH_CHILDREN		= 0x0040
 };
 
 
diff --git a/headers/private/fs_shell/fssh_api_wrapper.h \
b/headers/private/fs_shell/fssh_api_wrapper.h index 1651b2a..b7dbcfa 100644
--- a/headers/private/fs_shell/fssh_api_wrapper.h
+++ b/headers/private/fs_shell/fssh_api_wrapper.h
@@ -895,6 +895,7 @@
 #define B_FS_HAS_SELF_HEALING_LINKS		FSSH_B_FS_HAS_SELF_HEALING_LINKS
 #define B_FS_HAS_ALIASES				FSSH_B_FS_HAS_ALIASES
 #define B_FS_SUPPORTS_NODE_MONITORING	FSSH_B_FS_SUPPORTS_NODE_MONITORING
+#define B_FS_SUPPORTS_MONITOR_CHILDREN	FSSH_B_FS_SUPPORTS_MONITOR_CHILDREN
 
 #define fs_info	fssh_fs_info
 
diff --git a/headers/private/fs_shell/fssh_fs_info.h \
b/headers/private/fs_shell/fssh_fs_info.h index 66a6b52..2c79770 100644
--- a/headers/private/fs_shell/fssh_fs_info.h
+++ b/headers/private/fs_shell/fssh_fs_info.h
@@ -21,6 +21,7 @@
 #define FSSH_B_FS_HAS_SELF_HEALING_LINKS	0x00080000
 #define FSSH_B_FS_HAS_ALIASES				0x00100000
 #define FSSH_B_FS_SUPPORTS_NODE_MONITORING	0x00200000
+#define FSSH_B_FS_SUPPORTS_MONITOR_CHILDREN	0x00400000
 
 typedef struct fssh_fs_info {
 	fssh_dev_t	dev;								/* volume dev_t */
diff --git a/headers/private/fs_shell/fssh_fs_interface.h \
b/headers/private/fs_shell/fssh_fs_interface.h index 48dfce0..7d2d6fc 100644
--- a/headers/private/fs_shell/fssh_fs_interface.h
+++ b/headers/private/fs_shell/fssh_fs_interface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2008, Haiku Inc. All Rights Reserved.
+ * Copyright 2004-2016, Haiku Inc. All Rights Reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _FSSH_FS_INTERFACE_H
@@ -395,9 +395,10 @@ extern fssh_status_t fssh_notify_entry_moved(fssh_mount_id \
device,  fssh_vnode_id toDirectory, const char *toName,
 				fssh_vnode_id node);
 extern fssh_status_t fssh_notify_stat_changed(fssh_mount_id device,
-				fssh_vnode_id node, uint32_t statFields);
+				fssh_vnode_id dir, fssh_vnode_id node, uint32_t statFields);
 extern fssh_status_t fssh_notify_attribute_changed(fssh_mount_id device,
-				fssh_vnode_id node, const char *attribute, int32_t cause);
+				fssh_vnode_id dir, fssh_vnode_id node, const char *attribute,
+				int32_t cause);
 
 extern fssh_status_t fssh_notify_query_entry_created(fssh_port_id port,
 				int32_t token, fssh_mount_id device,
diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h \
b/src/add-ons/kernel/file_systems/bfs/Inode.h index c3f1b9c..1a51804 100644
--- a/src/add-ons/kernel/file_systems/bfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/bfs/Inode.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2001-2016, Axel Dörfler, axeld@pinc-software.de.
  * This file may be used under the terms of the MIT License.
  */
 #ifndef INODE_H
@@ -95,6 +95,9 @@ public:
 			const block_run&	BlockRun() const
 									{ return fNode.inode_num; }
 			block_run&			Parent() { return fNode.parent; }
+			const block_run&	Parent() const { return fNode.parent; }
+			ino_t				ParentID() const
+									{ return fVolume->ToVnode(Parent()); }
 			block_run&			Attributes() { return fNode.attributes; }
 
 			Volume*				GetVolume() const { return fVolume; }
diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index fe2478a..dac0c51 \
                100644
--- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2014, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2001-2016, Axel Dörfler, axeld@pinc-software.de.
  * This file may be used under the terms of the MIT License.
  */
 
@@ -208,7 +208,8 @@ bfs_read_fs_stat(fs_volume* _volume, struct fs_info* info)
 	// File system flags.
 	info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME
 		| (volume->IndicesNode() != NULL ? B_FS_HAS_QUERY : 0)
-		| (volume->IsReadOnly() ? B_FS_IS_READONLY : 0);
+		| (volume->IsReadOnly() ? B_FS_IS_READONLY : 0)
+		| B_FS_SUPPORTS_MONITOR_CHILDREN;
 
 	info->io_size = BFS_IO_SIZE;
 		// whatever is appropriate here?
@@ -923,7 +924,7 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct \
stat* stat,  if (status == B_OK)
 		status = transaction.Done();
 	if (status == B_OK)
-		notify_stat_changed(volume->ID(), inode->ID(), mask);
+		notify_stat_changed(volume->ID(), inode->ParentID(), inode->ID(), mask);
 
 	return status;
 }
@@ -1397,7 +1398,7 @@ bfs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, \
off_t pos,  if (!inode->IsDeleted() && cookie->last_size != inode->Size()
 			&& system_time() > cookie->last_notification
 					+ INODE_NOTIFICATION_INTERVAL) {
-			notify_stat_changed(volume->ID(), inode->ID(),
+			notify_stat_changed(volume->ID(), inode->ParentID(), inode->ID(),
 				B_STAT_MODIFICATION_TIME | B_STAT_SIZE | B_STAT_INTERIM_UPDATE);
 			cookie->last_size = inode->Size();
 			cookie->last_notification = system_time();
@@ -1483,7 +1484,7 @@ bfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* \
_cookie)  }
 
 		if (changedSize || changedTime) {
-			notify_stat_changed(volume->ID(), inode->ID(),
+			notify_stat_changed(volume->ID(), inode->ParentID(), inode->ID(),
 				(changedTime ? B_STAT_MODIFICATION_TIME : 0)
 				| (changedSize ? B_STAT_SIZE : 0));
 		}
@@ -1890,9 +1891,11 @@ bfs_write_attr(fs_volume* _volume, fs_vnode* _file, void* \
_cookie,  if (status == B_OK) {
 		status = transaction.Done();
 		if (status == B_OK) {
-			notify_attribute_changed(volume->ID(), inode->ID(), cookie->name,
+			notify_attribute_changed(volume->ID(), inode->ParentID(),
+				inode->ID(), cookie->name,
 				created ? B_ATTR_CREATED : B_ATTR_CHANGED);
-			notify_stat_changed(volume->ID(), inode->ID(), B_STAT_CHANGE_TIME);
+			notify_stat_changed(volume->ID(), inode->ParentID(), inode->ID(),
+				B_STAT_CHANGE_TIME);
 		}
 	}
 
@@ -1956,8 +1959,8 @@ bfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const \
char* name)  if (status == B_OK)
 		status = transaction.Done();
 	if (status == B_OK) {
-		notify_attribute_changed(volume->ID(), inode->ID(), name,
-			B_ATTR_REMOVED);
+		notify_attribute_changed(volume->ID(), inode->ParentID(), inode->ID(),
+			name, B_ATTR_REMOVED);
 	}
 
 	return status;
diff --git a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp index 1de0f48..3ab3765 \
                100644
--- a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp
@@ -353,7 +353,7 @@ btrfs_lookup(fs_volume* _volume, fs_vnode* _directory, const \
char* name,  status = DirectoryIterator(directory).Lookup(name, strlen(name), \
_vnodeID);  if (status != B_OK)
 		return status;
-	
+
 	return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
 }
 
@@ -373,7 +373,7 @@ static status_t
 btrfs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
 {
 	Inode* inode = (Inode*)_node->private_node;
-	
+
 	stat->st_dev = inode->GetVolume()->ID();
 	stat->st_ino = inode->ID();
 	stat->st_nlink = 1;
@@ -466,7 +466,7 @@ btrfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* \
_cookie)  Inode* inode = (Inode*)_node->private_node;
 
 	if (inode->Size() != cookie->last_size)
-		notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
+		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
 
 	delete cookie;
 	return B_OK;
diff --git a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp index d31d967..2bfad46 \
                100644
--- a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2013, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2007-2016, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  */
 
@@ -2067,7 +2067,7 @@ cdda_create_attr(fs_volume* _volume, fs_vnode* _node, const \
char* name,  if (status != B_OK)
 			return status;
 
-		notify_attribute_changed(volume->ID(), inode->ID(), name,
+		notify_attribute_changed(volume->ID(), -1, inode->ID(), name,
 			B_ATTR_CREATED);
 	} else if ((openMode & O_EXCL) == 0) {
 		if (attribute->IsProtectedNamespace())
@@ -2157,8 +2157,8 @@ cdda_write_attr(fs_volume* _volume, fs_vnode* _node, void* \
_cookie,  
 	status_t status = attribute->WriteAt(offset, (uint8*)buffer, _length);
 	if (status == B_OK) {
-		notify_attribute_changed(volume->ID(), inode->ID(), attribute->Name(),
-			B_ATTR_CHANGED);
+		notify_attribute_changed(volume->ID(), -1, inode->ID(),
+			attribute->Name(), B_ATTR_CHANGED);
 	}
 	return status;
 }
@@ -2203,7 +2203,7 @@ cdda_remove_attr(fs_volume* _volume, fs_vnode* _node, const \
char* name)  
 	status_t status = inode->RemoveAttribute(name, true);
 	if (status == B_OK) {
-		notify_attribute_changed(volume->ID(), inode->ID(), name,
+		notify_attribute_changed(volume->ID(), -1, inode->ID(), name,
 			B_ATTR_REMOVED);
 	}
 
diff --git a/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp index 627a38b..517f1a2 \
                100644
--- a/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp
@@ -421,7 +421,7 @@ static status_t
 exfat_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
 {
 	Inode* inode = (Inode*)_node->private_node;
-	
+
 	stat->st_dev = inode->GetVolume()->ID();
 	stat->st_ino = inode->ID();
 	stat->st_nlink = 1;
@@ -514,7 +514,7 @@ exfat_free_cookie(fs_volume* _volume, fs_vnode* _node, void* \
_cookie)  Inode* inode = (Inode*)_node->private_node;
 
 	if (inode->Size() != cookie->last_size)
-		notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
+		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
 
 	delete cookie;
 	return B_OK;
diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index 9bdb045..7c16d2b \
                100644
--- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
@@ -710,7 +710,7 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct \
stat* stat,  if (status == B_OK)
 		status = transaction.Done();
 	if (status == B_OK)
-		notify_stat_changed(volume->ID(), inode->ID(), mask);
+		notify_stat_changed(volume->ID(), -1, inode->ID(), mask);
 
 	return status;
 }
@@ -1219,7 +1219,7 @@ ext2_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, \
off_t pos,  if (cookie->last_size != inode->Size()
 			&& system_time() > cookie->last_notification
 				+ INODE_NOTIFICATION_INTERVAL) {
-			notify_stat_changed(volume->ID(), inode->ID(),
+			notify_stat_changed(volume->ID(), -1, inode->ID(),
 				B_STAT_MODIFICATION_TIME | B_STAT_SIZE | B_STAT_INTERIM_UPDATE);
 			cookie->last_size = inode->Size();
 			cookie->last_notification = system_time();
@@ -1247,7 +1247,7 @@ ext2_free_cookie(fs_volume* _volume, fs_vnode* _node, void* \
_cookie)  Inode* inode = (Inode*)_node->private_node;
 
 	if (inode->Size() != cookie->last_size)
-		notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
+		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
 
 	if ((cookie->open_mode & O_NOCACHE) != 0)
 		inode->EnableFileCache();
@@ -1449,7 +1449,7 @@ ext2_read_dir(fs_volume *_volume, fs_vnode *_node, void \
*_cookie,  status = iterator->Next();
 		if (status != B_OK && status != B_ENTRY_NOT_FOUND)
 			return status;
-		
+
 		dirent->d_dev = volume->ID();
 		dirent->d_ino = id;
 		dirent->d_reclen = sizeof(struct dirent) + length;
diff --git a/src/add-ons/kernel/file_systems/fat/file.c \
b/src/add-ons/kernel/file_systems/fat/file.c index 77a8d2c..86ab67a 100644
--- a/src/add-ons/kernel/file_systems/fat/file.c
+++ b/src/add-ons/kernel/file_systems/fat/file.c
@@ -116,7 +116,7 @@ status_t write_vnode_entry(nspace *vol, vnode *node)
 	diri_free(&diri);
 
 	// TODO: figure out which stats have actually changed
-	notify_stat_changed(vol->id, node->vnid, B_STAT_MODE | B_STAT_UID
+	notify_stat_changed(vol->id, -1, node->vnid, B_STAT_MODE | B_STAT_UID
 		| B_STAT_GID | B_STAT_SIZE | B_STAT_ACCESS_TIME
 		| B_STAT_MODIFICATION_TIME | B_STAT_CREATION_TIME
 		| B_STAT_CHANGE_TIME);
@@ -1025,7 +1025,7 @@ dosfs_rename(fs_volume *_vol, fs_vnode *_odir, const char \
*oldname,  // update MIME information
 	if(!(file->mode & FAT_SUBDIR)) {
 		set_mime_type(file, newname);
-		notify_attribute_changed(vol->id, file->vnid, "BEOS:TYPE",
+		notify_attribute_changed(vol->id, -1, file->vnid, "BEOS:TYPE",
 			B_ATTR_CHANGED);
 	}
 
diff --git a/src/add-ons/kernel/file_systems/googlefs/googlefs.c \
b/src/add-ons/kernel/file_systems/googlefs/googlefs.c index f8756bb..2322e51 100644
--- a/src/add-ons/kernel/file_systems/googlefs/googlefs.c
+++ b/src/add-ons/kernel/file_systems/googlefs/googlefs.c
@@ -95,14 +95,14 @@ static int googlefs_publish_static_entries(fs_volume *_volume)
 	if (err)
 		return err;
 	n->is_perm = 1;
-	
+
 	err = googlefs_create_gen(_volume, dir, "README", 0, 0444, NULL, &n, text_attrs, \
false, true);  if (err)
 		return err;
 	n->is_perm = 1;
 	n->data = readmestr;
 	n->data_size = strlen(n->data);// + 1;
-	
+
 	err = googlefs_create_gen(_volume, dir, "Author", 0, 0444, NULL, &n, \
mailto_me_bookmark_attrs, false, true);  if (err)
 		return err;
@@ -126,9 +126,9 @@ int googlefs_mount(fs_volume *_vol, const char *devname, uint32 \
flags,  /* only allow a single mount */
 	if (atomic_add(&refcount, 1))
 		return EALREADY;
-	
+
 	err = load_settings();
-	
+
 	err = google_request_init();
 	if (err)
 		goto err_http;
@@ -150,7 +150,7 @@ int googlefs_mount(fs_volume *_vol, const char *devname, uint32 \
flags,  new_lock(&(ns->l), "googlefs main lock");
 
 	ns->nodes = NULL;
-	
+
 	/* create root dir */
 	err = B_NO_MEMORY;
 	root = malloc(sizeof(fs_node));
@@ -164,7 +164,7 @@ int googlefs_mount(fs_volume *_vol, const char *devname, uint32 \
flags,  root->attrs_indirect = root_folder_attrs;
 		new_lock(&(root->l), "googlefs root dir");
 		TRACE((PFS "mount: root->l @ %p\n", &root->l));
-		
+
 		_vol->private_volume = ns;
 		_vol->ops = &sGoogleFSVolumeOps;
 		*vnid = ns->rootid;
@@ -199,10 +199,10 @@ status_t googlefs_unmount(fs_volume *_volume)
 		ns->nodes = node->nlnext; /* better cache that before we free node */
 		googlefs_free_vnode(_volume, node);
 	}
-	
+
 	// Unlike in BeOS, we need to put the reference to our root node ourselves
 	put_vnode(_volume, ns->rootid);
-	
+
 	free_lock(&ns->l);
 	vnidpool_free(ns->vnids);
 	free(ns);
@@ -338,7 +338,7 @@ int googlefs_walk(fs_volume *_volume, fs_vnode *_base, const char \
*file, ino_t *  } else
 			err = EINVAL;
 	} else if (base) { /* child of dir */
-		n = (fs_node *)SLL_FIND(base->children, next, 
+		n = (fs_node *)SLL_FIND(base->children, next,
 								(sll_compare_func)compare_fs_node_by_name, (void *)file);
 		if (n) {
 			*vnid = n->vnid;
@@ -397,7 +397,7 @@ int googlefs_closedir(fs_volume *_volume, fs_vnode *_node, \
fs_dir_cookie *cookie  err = LOCK(&node->l);
 	if (err)
 		return err;
-	
+
 	SLL_REMOVE(node->opened, next, cookie);
 	UNLOCK(&node->l);
 
@@ -532,7 +532,7 @@ int googlefs_open(fs_volume *_volume, fs_vnode *_node, int omode, \
fs_file_cookie  TRACE((PFS"open(%ld, %Ld, 0x%x)\n", ns->nsid, node->vnid, omode));
 	if (!node || !cookie)
 		return EINVAL;
-	
+
 //	err = LOCK(&ns->l);
 //	if (err)
 //		return err;
@@ -589,7 +589,7 @@ int googlefs_close(fs_volume *_volume, fs_vnode *_node, \
fs_file_cookie *cookie)  if (err)
 		return err;
 	SLL_REMOVE(node->opened, next, cookie);
-	
+
 all_ok:
 err_n_l:
 	UNLOCK(&node->l);
@@ -680,7 +680,7 @@ static int googlefs_create_gen(fs_volume *_volume, fs_node *dir, \
const char *nam  fs_node *n;
 	int i;
 	TRACE((PFS"create_gen(%ld, %Ld, '%s', 0x%08lx, %c, %c)\n", ns->nsid, dir->vnid, \
                name, omode, mkdir?'t':'f', uniq?'t':'f'));
-	
+
 	if (strlen(name) > GOOGLEFS_NAME_LEN-1)
 		return ENAMETOOLONG;
 	err = LOCK(&dir->l);
@@ -689,7 +689,7 @@ static int googlefs_create_gen(fs_volume *_volume, fs_node *dir, \
const char *nam  err = ENOTDIR;
 	if (!S_ISDIR(dir->st.st_mode))
 		goto err_l;
-	n = (fs_node *)SLL_FIND(dir->children, next, 
+	n = (fs_node *)SLL_FIND(dir->children, next,
 							(sll_compare_func)compare_fs_node_by_name, (void *)name);
 	err = EEXIST;
 	if (n && (omode & O_EXCL) && !uniq) /* already existing entry in there! */
@@ -703,13 +703,13 @@ static int googlefs_create_gen(fs_volume *_volume, fs_node \
*dir, const char *nam  strncpy(newname, name, 56);
 		newname[56] = '\0';
 		sprintf(newname+strlen(newname), " %05d", i);
-		n = (fs_node *)SLL_FIND(dir->children, next, 
+		n = (fs_node *)SLL_FIND(dir->children, next,
 								(sll_compare_func)compare_fs_node_by_name, (void *)newname);
 	}
 	if (n && (uniq || mkdir)) /* still there! */
 		goto err_l;
 	name = newname;
-	
+
 	if (n) { /* already exists, so return it */
 		if (node)
 			*node = n;
@@ -730,9 +730,9 @@ static int googlefs_create_gen(fs_volume *_volume, fs_node *dir, \
const char *nam  strcpy(n->name, name);
 	//n->is_perm = 1;
 	fill_default_stat(&n->st, ns->nsid, n->vnid, (perms & ~S_IFMT) | \
                (mkdir?S_IFDIR:S_IFREG));
-	
+
 	new_lock(&(n->l), mkdir?"googlefs dir":"googlefs file");
-	
+
 	err = LOCK(&ns->l);
 	if (err)
 		goto err_nl;
@@ -752,14 +752,14 @@ static int googlefs_create_gen(fs_volume *_volume, fs_node \
*dir, const char *nam  n->attrs_indirect = iattrs;
 	notify_entry_created(ns->nsid, dir->vnid, name, n->vnid);
 	/* dosfs doesn't do that one but I believe it should */
-	notify_stat_changed(B_STAT_CHANGED, ns->nsid, -1);
+	notify_stat_changed(B_STAT_CHANGED, -1, ns->nsid, -1);
 	/* give node to caller if it wants it */
 	if (node)
 		*node = n;
 	if (vnid)
 		*vnid = n->vnid;
 	goto done;
-	
+
 err_insnl:
 	SLL_REMOVE(ns->nodes, nlnext, n);
 err_lns:
@@ -784,7 +784,7 @@ int googlefs_create(fs_volume *_volume, fs_vnode *_dir, const \
char *name, int om  TRACE((PFS"create(%ld, %Ld, '%s', 0x%08lx)\n", ns->nsid, \
dir->vnid, name, omode));  /* don't let ppl mess our fs up */
 	return ENOSYS;
-	
+
 	err = googlefs_create_gen(_volume, dir, name, omode, perms, vnid, &n, NULL, false, \
false);  if (err)
 		return err;
@@ -804,7 +804,7 @@ static int googlefs_unlink_gen(fs_volume *_volume, fs_node *dir, \
const char *nam  return err;
 	err = ENOENT;
 	/* no need to check for S_ISDIR */
-	n = (fs_node *)SLL_FIND(dir->children, next, 
+	n = (fs_node *)SLL_FIND(dir->children, next,
 							(sll_compare_func)compare_fs_node_by_name, (void *)name);
 	if (n) {
 		if (n->children)
@@ -887,7 +887,7 @@ static int googlefs_mkdir_gen(fs_volume *_volume, fs_vnode *_dir, \
const char *na  fs_node *n;
 	int i;
 	TRACE((PFS"mkdir_gen(%ld, %Ld, '%s', 0x%08lx, %c)\n", ns->nsid, dir->vnid, name, \
                perms, uniq?'t':'f'));
-	
+
 	if (strlen(name) > GOOGLEFS_NAME_LEN-1)
 		return ENAMETOOLONG;
 	err = LOCK(&dir->l);
@@ -896,24 +896,24 @@ static int googlefs_mkdir_gen(fs_volume *_volume, fs_vnode \
*_dir, const char *na  err = ENOTDIR;
 	if (!S_ISDIR(dir->st.st_mode))
 		goto err_l;
-	n = (fs_node *)SLL_FIND(dir->children, next, 
+	n = (fs_node *)SLL_FIND(dir->children, next,
 							(sll_compare_func)compare_fs_node_by_name, (void *)name);
 	err = EEXIST;
 	if (n && !uniq) /* already existing entry in there! */
 		goto err_l;
-	
+
 	strncpy(newname, name, GOOGLEFS_NAME_LEN);
 	newname[GOOGLEFS_NAME_LEN-1] = '\0';
 	for (i = 1; n && i < 5000; i++) { /* uniquify the name */
 		//sprintf("%"#(GOOGLEFS_NAME_LEN-8)"s %05d", name, i);
 		sprintf("%56s %05d", name, i);
-		n = (fs_node *)SLL_FIND(dir->children, next, 
+		n = (fs_node *)SLL_FIND(dir->children, next,
 								(sll_compare_func)compare_fs_node_by_name, (void *)newname);
 	}
 	if (n) /* still there! */
 		goto err_l;
 	name = newname;
-	
+
 	err = ENOMEM;
 	n = malloc(sizeof(fs_node));
 	if (!n)
@@ -952,7 +952,7 @@ static int googlefs_mkdir_gen(fs_volume *_volume, fs_vnode *_dir, \
const char *na  if (node)
 		*node = n;
 	goto done;
-	
+
 err_insnl:
 	SLL_REMOVE(ns->nodes, nlnext, n);
 err_lns:
@@ -1066,7 +1066,7 @@ int googlefs_read_attrdir(fs_volume *_volume, fs_vnode *_node, \
fs_attr_dir_cooki  for (i = 0; !ae && i < 10 && node->attrs[i].name; i++)
 		if (i + count_indirect == cookie->dir_current)
 			ae = &node->attrs[i];
-	
+
 	if (ae) {
 		TRACE((PFS "read_attrdir: giving %s\n", ae->name));
 		buf->d_dev = ns->nsid;
@@ -1079,12 +1079,12 @@ int googlefs_read_attrdir(fs_volume *_volume, fs_vnode \
                *_node, fs_attr_dir_cooki
 		*num = 1;
 	} else
 		*num = 0;
-	
+
 	UNLOCK(&node->l);
 	return B_OK;
 }
 
-/* Haiku and BeOs differ in the way the handle attributes at the vfs layer. 
+/* Haiku and BeOs differ in the way the handle attributes at the vfs layer.
    BeOS uses atomic calls on the vnode,
    Haiku retains the open/close/read/write semantics for attributes (loosing \
atomicity).  Here we don't care much though, open is used for both to factorize \
attribute lookup. <- TODO @@ -1135,7 +1135,7 @@ int googlefs_open_attr_h(fs_volume \
*_volume, fs_vnode *_node, const char *name,  err = SLL_INSERT(node->opened, next, \
fc);  if (err)
 		goto err_linsert;
-	
+
 	*cookie = fc;
 	err = B_OK;
 	goto all_ok;
@@ -1165,7 +1165,7 @@ int googlefs_close_attr_h(fs_volume *_volume, fs_vnode *_node, \
fs_file_cookie *c  if (err)
 		return err;
 	SLL_REMOVE(node->opened, next, cookie);
-	
+
 all_ok:
 err_n_l:
 	UNLOCK(&node->l);
@@ -1218,7 +1218,7 @@ int	googlefs_read_attr(fs_volume *_volume, fs_vnode *_node, \
fs_file_cookie *cook  return EINVAL;
 
 	err = LOCK(&node->l);
-	
+
 	if (ae && pos < ae->size) {
 		memcpy(buf, (char *)ae->value + pos, MIN(*len, ae->size-pos));
 		*len = MIN(*len, ae->size-pos);
@@ -1227,7 +1227,7 @@ int	googlefs_read_attr(fs_volume *_volume, fs_vnode *_node, \
                fs_file_cookie *cook
 		*len = 0;
 		err = ENOENT;
 	}
-	
+
 	UNLOCK(&node->l);
 	return err;
 }
@@ -1270,7 +1270,7 @@ int	googlefs_open_query(fs_volume *_volume, const char *query, \
ulong flags,  return EINVAL;
 
 	// filter out queries that aren't for us, we don't want to trigger google searches \
                when apps check for mails, ... :)
-	
+
 	err = B_NO_MEMORY;
 	c = malloc(sizeof(fs_query_cookie));
 	if (!c)
@@ -1300,7 +1300,7 @@ int	googlefs_open_query(fs_volume *_volume, const char *query, \
ulong flags,  goto err_qs;
 		}
 	}
-	
+
 	if (!accepted) {
 		free(qstring);
 		/* return an empty cookie */
@@ -1310,7 +1310,7 @@ int	googlefs_open_query(fs_volume *_volume, const char *query, \
ulong flags,  TRACE((PFS"open_query: QUERY: '%s'\n", qstring));
 	/* reuse query if it's not too old */
 	LOCK(&ns->l);
-	qn = SLL_FIND(ns->queries, qnext, 
+	qn = SLL_FIND(ns->queries, qnext,
 				(sll_compare_func)compare_fs_node_by_recent_query_string, (void *)qstring);
 	UNLOCK(&ns->l);
 	reused = (qn != NULL);
@@ -1349,14 +1349,14 @@ int	googlefs_open_query(fs_volume *_volume, const char \
*query, ulong flags,  err = google_request_open(qstring, _volume, qn, &qn->request);
 	if (err)
 		goto err_gn;
-	
+
 	TRACE((PFS"open_query: request_open done\n"));
 #ifndef NO_SEARCH
 	err = google_request_process(qn->request);
 	if (err)
 		goto err_gro;
 	TRACE((PFS"open_query: request_process done\n"));
-	
+
 #else
 	/* fake entries */
 	for (i = 0; i < 10; i++) {
@@ -1367,11 +1367,11 @@ int	googlefs_open_query(fs_volume *_volume, const char \
*query, ulong flags,  n->attrs[0].value = &n->attrs[1].value;
 		n->attrs[0].size = sizeof(int32);
 		n->attrs[0].name = "GOOGLE:order";
-		notify_attribute_changed(ns->nsid, n->vnid, n->attrs[0].name, B_ATTR_CHANGED);
+		notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[0].name, B_ATTR_CHANGED);
 		if (err)
 			goto err_gn;
 	}
-#endif /*NO_SEARCH*/	
+#endif /*NO_SEARCH*/
 	//
 	//err = google_request_close(q->request);
 
@@ -1509,7 +1509,7 @@ int googlefs_push_result_to_query(struct google_request \
*request, struct google_  return EINVAL;
 
 	// filter out queries that aren't for us, we don't want to trigger google searches \
                when apps check for mails, ... :)
-	
+
 	/* stripped name for folder */
 	strncpy(ename, result->name, GOOGLEFS_NAME_LEN);
 	ename[GOOGLEFS_NAME_LEN-1] = '\0';
@@ -1517,7 +1517,7 @@ int googlefs_push_result_to_query(struct google_request \
*request, struct google_  p = ename;
 	while ((p = strchr(p, '/')))
 		*p++ = '_';
-	
+
 	err = googlefs_create_gen(_volume, qn, ename, 0, 0644, NULL, &n, bookmark_attrs, \
false, true);  if (err)
 		return err;
@@ -1528,32 +1528,32 @@ int googlefs_push_result_to_query(struct google_request \
*request, struct google_  n->attrs[i].value = result->name;
 	n->attrs[i].size = strlen(result->name)+1;
 	n->attrs[i].name = "META:title";
-	notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+	notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 	i++;
 	n->attrs[i].type = 'CSTR';
 	n->attrs[i].value = result->url;
 	n->attrs[i].size = strlen(result->url)+1;
 	n->attrs[i].name = "META:url";
-	notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+	notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 	i++;
 	n->attrs[i].type = 'CSTR';
 	n->attrs[i].value = request->query_string;
 	n->attrs[i].size = strlen(request->query_string)+1;
 	n->attrs[i].name = "META:keyw";
-	notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+	notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 	i++;
 	n->attrs[i].type = 'LONG';
 	n->attrs[i].value = &result->id;
 	n->attrs[i].size = sizeof(int32);
 	n->attrs[i].name = "GOOGLE:order";
-	notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+	notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 	i++;
 	if (result->snipset[0]) {
 		n->attrs[i].type = 'CSTR';
 		n->attrs[i].value = result->snipset;
 		n->attrs[i].size = strlen(result->snipset)+1;
 		n->attrs[i].name = "GOOGLE:excerpt";
-		notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+		notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 		i++;
 	}
 	if (result->cache_url[0]) {
@@ -1561,7 +1561,7 @@ int googlefs_push_result_to_query(struct google_request \
*request, struct google_  n->attrs[i].value = result->cache_url;
 		n->attrs[i].size = strlen(result->cache_url)+1;
 		n->attrs[i].name = "GOOGLE:cache_url";
-		notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+		notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 		i++;
 	}
 	if (result->similar_url[0]) {
@@ -1569,7 +1569,7 @@ int googlefs_push_result_to_query(struct google_request \
*request, struct google_  n->attrs[i].value = result->similar_url;
 		n->attrs[i].size = strlen(result->similar_url)+1;
 		n->attrs[i].name = "GOOGLE:similar_url";
-		notify_attribute_changed(ns->nsid, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
+		notify_attribute_changed(ns->nsid, -1, n->vnid, n->attrs[i].name, B_ATTR_CREATED);
 		i++;
 	}
 	UNLOCK(&n->l);
diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp \
b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp \
                index 201c558..d12fd46 100644
--- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp
+++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2010, Haiku Inc. All rights reserved.
+ * Copyright 2009-2016, Haiku Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -853,7 +853,7 @@ AttributeFile::RemoveAttribute(const char *name, AttributeEntry \
**_entry)  else
 		delete entry;
 
-	notify_attribute_changed(fVolumeID, fFileInode, name, B_ATTR_REMOVED);
+	notify_attribute_changed(fVolumeID, -1, fFileInode, name, B_ATTR_REMOVED);
 	return B_OK;
 }
 
@@ -876,7 +876,7 @@ AttributeFile::AddAttribute(AttributeEntry *entry)
 	fEntries = newEntries;
 	fEntries[fFile->entry_count++] = entry;
 
-	notify_attribute_changed(fVolumeID, fFileInode, entry->Name(),
+	notify_attribute_changed(fVolumeID, -1, fFileInode, entry->Name(),
 		B_ATTR_CREATED);
 
 	return B_OK;
@@ -1068,7 +1068,7 @@ AttributeEntry::Write(off_t position, const void *buffer, \
size_t *length)  }
 
 	memcpy(fData + position, buffer, *length);
-	notify_attribute_changed(fParent->VolumeID(), fParent->FileInode(),
+	notify_attribute_changed(fParent->VolumeID(), -1, fParent->FileInode(),
 		fEntry->name, B_ATTR_CHANGED);
 	return B_OK;
 }
@@ -1752,6 +1752,7 @@ overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
 		if (result != B_OK)
 			return result;
 
+		info->flags &= B_FS_SUPPORTS_MONITOR_CHILDREN;
 		info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/;
 		return B_OK;
 	}
diff --git a/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp \
b/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp index \
                e49074a..93078a8 100644
--- a/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp
+++ b/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Haiku Inc. All rights reserved.
+ * Copyright 2009-2016, Haiku Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -74,8 +74,8 @@ struct overlay_dirent {
 
 	void			dispose_attribute(fs_volume *volume, ino_t fileInode)
 					{
-						notify_attribute_changed(volume->id, fileInode, name,
-							B_ATTR_REMOVED);
+						notify_attribute_changed(volume->id, -1, fileInode,
+							name, B_ATTR_REMOVED);
 						free(name);
 						free(this);
 					}
@@ -547,7 +547,7 @@ OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
 	if (!fIsModified)
 		SetModified();
 
-	notify_stat_changed(SuperVolume()->id, fInodeNumber, statMask);
+	notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, statMask);
 	return B_OK;
 }
 
@@ -843,10 +843,10 @@ OverlayInode::Write(void *_cookie, off_t position, const void \
*buffer,  
 				fStat.st_mtime = time(NULL);
 				if (fIsAttribute) {
-					notify_attribute_changed(SuperVolume()->id, fInodeNumber,
-						fName, B_ATTR_CHANGED);
+					notify_attribute_changed(SuperVolume()->id, -1,
+						fInodeNumber, fName, B_ATTR_CHANGED);
 				} else {
-					notify_stat_changed(SuperVolume()->id, fInodeNumber,
+					notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
 						B_STAT_MODIFICATION_TIME);
 				}
 				return B_OK;
@@ -903,10 +903,10 @@ OverlayInode::Write(void *_cookie, off_t position, const void \
*buffer,  fStat.st_mtime = time(NULL);
 
 	if (fIsAttribute) {
-		notify_attribute_changed(SuperVolume()->id, fInodeNumber, fName,
+		notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber, fName,
 			B_ATTR_CHANGED);
 	} else {
-		notify_stat_changed(SuperVolume()->id, fInodeNumber,
+		notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
 			B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0));
 	}
 
@@ -1219,7 +1219,7 @@ OverlayInode::_PopulateStat()
 {
 	if (fHasStat)
 		return B_OK;
- 
+
  	fHasStat = true;
 	if (fIsAttribute) {
 		if (fName == NULL || fSuperVnode.ops->open_attr == NULL
@@ -1503,8 +1503,8 @@ OverlayInode::_CreateCommon(const char *name, int type, int \
                perms,
 		*_node = node;
 
 	if (attribute) {
-		notify_attribute_changed(SuperVolume()->id, fInodeNumber, entry->name,
-			B_ATTR_CREATED);
+		notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber,
+			entry->name, B_ATTR_CREATED);
 	} else {
 		notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name,
 			entry->inode_number);
@@ -2164,9 +2164,9 @@ overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
 	node->SetSuperVnode(toNode->SuperVnode());
 	node->SetInodeNumber(toNode->InodeNumber());
 
-	notify_attribute_changed(volume->id, fromNode->InodeNumber(), fromName,
+	notify_attribute_changed(volume->id, -1, fromNode->InodeNumber(), fromName,
 		B_ATTR_REMOVED);
-	notify_attribute_changed(volume->id, toNode->InodeNumber(), toName,
+	notify_attribute_changed(volume->id, -1, toNode->InodeNumber(), toName,
 		B_ATTR_CREATED);
 
 	free(oldName);
@@ -2183,7 +2183,7 @@ overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const \
char *name)  if (result != B_OK)
 		return result;
 
-	notify_attribute_changed(volume->id, node->InodeNumber(), name,
+	notify_attribute_changed(volume->id, -1, node->InodeNumber(), name,
 		B_ATTR_REMOVED);
 	return result;
 }
diff --git a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c \
b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c index eab631c..62ef40d 100644
--- a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c
+++ b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c
@@ -1694,7 +1694,7 @@ fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat \
*st, uint32 mask  XDRInPacketDestroy(&reply);
 	XDROutPacketDestroy(&call);
 
-	return notify_stat_changed(_volume->id, node->vnid, mask);
+	return notify_stat_changed(_volume->id, -1, node->vnid, mask);
 }
 
 static status_t
diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp \
b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 168f54c..5e9558b \
                100644
--- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Copyright 2012-2016 Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -304,7 +304,7 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* \
oldSnapshot,  if (!found) {
 			if (fAttrDir) {
 				notify_attribute_changed(fInode->GetFileSystem()->DevId(),
-					fInode->ID(), newCurrent->fName, B_ATTR_CREATED);
+					-1, fInode->ID(), newCurrent->fName, B_ATTR_CREATED);
 			} else {
 				notify_entry_created(fInode->GetFileSystem()->DevId(),
 					fInode->ID(), newCurrent->fName, newCurrent->fNode);
@@ -321,7 +321,7 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* \
oldSnapshot,  while (oldCurrent != NULL) {
 		if (fAttrDir) {
 			notify_attribute_changed(fInode->GetFileSystem()->DevId(),
-				fInode->ID(), oldCurrent->fName, B_ATTR_REMOVED);
+				-1, fInode->ID(), oldCurrent->fName, B_ATTR_REMOVED);
 		} else {
 			notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
 				oldCurrent->fName, oldCurrent->fNode);
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp \
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index cb13665..9e186fc 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Copyright 2012-2016 Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -293,7 +293,7 @@ Inode::Remove(const char* name, FileType type, ino_t* id)
 		*id = FileIdToInoT(fileID);
 
 	if (type == NF4NAMEDATTR) {
-		notify_attribute_changed(fFileSystem->DevId(), ID(), name,
+		notify_attribute_changed(fFileSystem->DevId(), -1, ID(), name,
 			B_ATTR_REMOVED);
 	} else {
 		notify_entry_removed(fFileSystem->DevId(), ID(), name,
@@ -382,9 +382,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const \
char* toName,  }
 
 	if (attribute) {
-		notify_attribute_changed(from->fFileSystem->DevId(), from->ID(),
+		notify_attribute_changed(from->fFileSystem->DevId(), -1, from->ID(),
 			fromName, B_ATTR_REMOVED);
-		notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName,
+		notify_attribute_changed(to->fFileSystem->DevId(), -1, to->ID(), toName,
 			B_ATTR_CREATED);
 	} else {
 		notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
@@ -898,7 +898,7 @@ Inode::SetDelegation(Delegation* delegation)
 	fMetaCache.InvalidateStat();
 	struct stat st;
 	Stat(&st);
-	fMetaCache.LockValid();	
+	fMetaCache.LockValid();
 
 	fDelegation = delegation;
 	fOpenState->AcquireReference();
diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp \
b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 4801e8e..cd4f479 \
                100644
--- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Copyright 2012-2016 Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -79,7 +79,7 @@ MetadataCache::GrowFile(size_t newSize)
 	fStatCache.st_size = max_c((off_t)newSize, fStatCache.st_size);
 
 	if (oldSize != fStatCache.st_size) {
-		notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(),
+		notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(),
 			B_STAT_SIZE);
 	}
 }
@@ -181,6 +181,7 @@ MetadataCache::NotifyChanges(const struct stat* oldStat,
 		sizeof(struct timespec) == 0))
 		flags |= B_STAT_MODIFICATION_TIME;
 
-	notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags);
+	notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(),
+		flags);
 }
 
diff --git a/src/add-ons/kernel/file_systems/ntfs/attributes.c \
b/src/add-ons/kernel/file_systems/ntfs/attributes.c index 0e10eba..9e58572 100644
--- a/src/add-ons/kernel/file_systems/ntfs/attributes.c
+++ b/src/add-ons/kernel/file_systems/ntfs/attributes.c
@@ -63,18 +63,18 @@ fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void \
**_cookie)  ni = NULL;
 	ctx = NULL;
 	*_cookie = cookie;
-	
+
 exit:
 
 	if (ctx != NULL)
 		ntfs_attr_put_search_ctx(ctx);
 	if (ni != NULL)
 		ntfs_inode_close(ni);
-	
+
 	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
-	
+
 	UNLOCK_VOL(ns);
-	
+
 	return result;
 }
 
@@ -130,7 +130,7 @@ fs_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void \
*_cookie)  TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
 
 	UNLOCK_VOL(ns);
-	
+
 	return result;
 }
 
@@ -160,18 +160,18 @@ fs_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void \
*_cookie,  // it's the actual file body
 			if (attr->name_length == 0)
 				continue;
-			
+
 			name = ntfs_attr_name_get((const ntfschar *)(((char *)attr)
 				+ attr->name_offset), attr->name_length);
-			
+
 			if(strncmp(name, kHaikuAttrPrefix, strlen(kHaikuAttrPrefix)) !=0 ) {
 				TRACE("found AT_DATA '%s' - Skip\n", name);
 				continue;
 			}
 			TRACE("found AT_DATA '%s' - Found\n", name);
-				
+
 			real_name = name + strlen(kHaikuAttrPrefix);
-			
+
 			bufsize = MIN(bufsize, sizeof(struct dirent) + strlen(real_name) + 1);
 			entry->d_ino = node->vnid;
 			entry->d_dev = ns->id;
@@ -197,7 +197,7 @@ exit:
 		strerror(result), *num);
 
 	UNLOCK_VOL(ns);
-	
+
 	if (result)
 		*num = 0;
 	else
@@ -218,9 +218,9 @@ fs_create_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name,  int ulen;
 	ntfs_inode *ni = NULL;
 	ntfs_attr *na = NULL;
-	status_t result = B_NO_ERROR;	
+	status_t result = B_NO_ERROR;
 
-	if (ns->flags & B_FS_IS_READONLY) {		
+	if (ns->flags & B_FS_IS_READONLY) {
 		return B_READ_ONLY_DEVICE;
 	}
 
@@ -250,7 +250,7 @@ fs_create_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name,  char ntfs_attr_name[MAX_PATH] = {0};
 		strcat(ntfs_attr_name, kHaikuAttrPrefix);
 		strcat(ntfs_attr_name,name);
-		
+
 		uname = ntfs_calloc(MAX_PATH);
 		ulen = ntfs_mbstoucs(ntfs_attr_name, &uname);
 		if (ulen < 0) {
@@ -261,7 +261,7 @@ fs_create_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name,  
 		na = ntfs_attr_open(ni, AT_DATA, uname, ulen);
 		if (na != NULL) {
-			if (ntfs_attr_truncate(na, 0)) {				
+			if (ntfs_attr_truncate(na, 0)) {
 				result = errno;
 				goto exit;
 			}
@@ -278,7 +278,7 @@ fs_create_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name,  TRACE("%s - ntfs_attr_open: %s\n", __FUNCTION__,
 					strerror(result));
 				goto exit;
-			}			
+			}
 		}
 		if(ntfs_attr_pwrite(na, 0, sizeof(uint32), &type) < 0 ) {
 			result = errno;
@@ -356,7 +356,7 @@ fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char \
*name,  char ntfs_attr_name[MAX_PATH] = {0};
 		strcat(ntfs_attr_name, kHaikuAttrPrefix);
 		strcat(ntfs_attr_name, name);
-		
+
 		uname = ntfs_calloc(MAX_PATH);
 		ulen = ntfs_mbstoucs(ntfs_attr_name, &uname);
 		if (ulen < 0) {
@@ -367,7 +367,7 @@ fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char \
*name,  na = ntfs_attr_open(ni, AT_DATA, uname, ulen);
 		if (na != NULL) {
 			if (openMode & O_TRUNC) {
-				if (ns->flags & B_FS_IS_READONLY) {		
+				if (ns->flags & B_FS_IS_READONLY) {
 					result = B_READ_ONLY_DEVICE;
 					goto exit;
 				} else {
@@ -445,7 +445,7 @@ fs_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void \
*_cookie)  }
 
 
-status_t 
+status_t
 fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie,
 	struct stat *stat)
 {
@@ -453,8 +453,8 @@ fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void \
*_cookie,  vnode *node = (vnode *)_node->private_node;
 	attrcookie *cookie = (attrcookie *)_cookie;
 	ntfs_inode *ni = NULL;
-	ntfs_attr *na = NULL;	
-	status_t result = B_NO_ERROR;	
+	ntfs_attr *na = NULL;
+	status_t result = B_NO_ERROR;
 
 	LOCK_VOL(ns);
 
@@ -466,7 +466,7 @@ fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void \
*_cookie,  na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len);
 	if (na == NULL) {
 		result = errno;
-		goto exit;		
+		goto exit;
 	}
 
 	stat->st_type = cookie->type;
@@ -476,15 +476,15 @@ exit:
 	if (na != NULL)
 		ntfs_attr_close(na);
 	if (ni != NULL)
-		ntfs_inode_close(ni);	
+		ntfs_inode_close(ni);
 
 	UNLOCK_VOL(ns);
-	
+
 	return B_NO_ERROR;
 }
 
 
-status_t 
+status_t
 fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos,
 	void *buffer, size_t *len)
 {
@@ -505,7 +505,7 @@ fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, \
off_t pos,  LOCK_VOL(ns);
 
 	TRACE("%s - ENTER  vnid: %d\n", __FUNCTION__, node->vnid);
-	
+
 	ni = ntfs_inode_open(ns->ntvol, node->vnid);
 	if (ni == NULL) {
 		result = errno;
@@ -514,9 +514,9 @@ fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, \
off_t pos,  na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len);
 	if (na == NULL) {
 		result = errno;
-		goto exit;		
-	}	
-	
+		goto exit;
+	}
+
 	pos += sizeof(uint32);
 
 	// it is a named stream
@@ -551,11 +551,11 @@ exit:
 		ntfs_attr_close(na);
 	if (ni != NULL)
 		ntfs_inode_close(ni);
-			
+
 	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
 
 	UNLOCK_VOL(ns);
-	
+
 	return result;
 }
 
@@ -576,8 +576,8 @@ fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, \
off_t pos,  status_t result = B_NO_ERROR;
 
 	TRACE("%s - ENTER  vnode: %d\n", __FUNCTION__, node->vnid);
-	
-	if (ns->flags & B_FS_IS_READONLY) {		
+
+	if (ns->flags & B_FS_IS_READONLY) {
 		return B_READ_ONLY_DEVICE;
 	}
 
@@ -596,8 +596,8 @@ fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, \
off_t pos,  na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len);
 	if (na == NULL) {
 		result = errno;
-		goto exit;		
-	}		
+		goto exit;
+	}
 
 	pos += sizeof(uint32);
 
@@ -611,7 +611,7 @@ fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, \
off_t pos,  if (ntfs_attr_truncate(na, pos + size))
 				size = na->data_size - pos;
 			else
-				notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
+				notify_stat_changed(ns->id, -1, MREF(ni->mft_no), B_STAT_SIZE);
 		}
 
 		while (size) {
@@ -636,28 +636,28 @@ fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void \
*_cookie, off_t pos,  result =  EINVAL;
 		goto exit;
 	}
-	
+
 	if (ntfs_ucstombs(na->name, na->name_len, &attr_name, 0) >= 0) {
 		if (attr_name != NULL) {
 			if(strncmp(attr_name, kHaikuAttrPrefix, strlen(kHaikuAttrPrefix)) !=0 )
 				goto exit;
-			real_name = attr_name + strlen(kHaikuAttrPrefix);						
-			notify_attribute_changed(ns->id, MREF(ni->mft_no),
+			real_name = attr_name + strlen(kHaikuAttrPrefix);
+			notify_attribute_changed(ns->id, -1, MREF(ni->mft_no),
 				real_name, B_ATTR_CHANGED);
 			free(attr_name);
 		}
 	}
-		
-exit:	
+
+exit:
 	if (na != NULL)
 		ntfs_attr_close(na);
 	if (ni != NULL)
 		ntfs_inode_close(ni);
-		
+
 	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
 
 	UNLOCK_VOL(ns);
-	
+
 	return result;
 }
 
@@ -670,18 +670,18 @@ fs_remove_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name)  char ntfs_attr_name[MAX_PATH]={0};
 	ntfschar *uname = NULL;
 	int ulen;
-	ntfs_inode *ni = NULL;		
+	ntfs_inode *ni = NULL;
 	status_t result = B_NO_ERROR;
 
 	TRACE("%s - ENTER - name: [%s]\n", __FUNCTION__, name);
-	
+
 	if (ns->flags & B_FS_IS_READONLY) {
 		ERROR("ntfs is read-only\n");
 		return B_READ_ONLY_DEVICE;
 	}
 
 	LOCK_VOL(ns);
-	
+
 	if (node == NULL) {
 		result = EINVAL;
 		goto exit;
@@ -691,18 +691,18 @@ fs_remove_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name)  if (ni == NULL) {
 		result = errno;
 		goto exit;
-	}		
-	
+	}
+
 	strcat(ntfs_attr_name, kHaikuAttrPrefix);
 	strcat(ntfs_attr_name, name);
-	
+
 	uname = ntfs_calloc(MAX_PATH);
 	ulen = ntfs_mbstoucs(ntfs_attr_name, &uname);
 	if (ulen < 0) {
 		result = EILSEQ;
 		goto exit;
-	}	
-	
+	}
+
 	if (ntfs_attr_remove(ni, AT_DATA, uname, ulen)) {
 		result = ENOENT;
 		goto exit;
@@ -712,17 +712,18 @@ fs_remove_attrib(fs_volume *_vol, fs_vnode *_node, const char* \
name)  ni->flags |= FILE_ATTR_ARCHIVE;
 		NInoFileNameSetDirty(ni);
 	}
-	notify_attribute_changed(ns->id, MREF(ni->mft_no), name, B_ATTR_REMOVED);
-exit:	
+	notify_attribute_changed(ns->id, -1, MREF(ni->mft_no), name,
+		B_ATTR_REMOVED);
+exit:
 	if (uname != NULL)
 		free(uname);
 
 	if (ni != NULL)
 		ntfs_inode_close(ni);
-		
+
 	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
 
 	UNLOCK_VOL(ns);
-	
+
 	return result;
 }
diff --git a/src/add-ons/kernel/file_systems/ntfs/fs_func.c \
b/src/add-ons/kernel/file_systems/ntfs/fs_func.c index 051cea6..3b89268 100644
--- a/src/add-ons/kernel/file_systems/ntfs/fs_func.c
+++ b/src/add-ons/kernel/file_systems/ntfs/fs_func.c
@@ -116,7 +116,7 @@ get_node_type(ntfs_inode* ni, int* _type)
 }
 
 
-static u64 
+static u64
 ntfs_inode_lookup(fs_volume *_vol, ino_t parent, const char *name)
 {
 	nspace *ns = (nspace*)_vol->private_volume;
@@ -124,7 +124,7 @@ ntfs_inode_lookup(fs_volume *_vol, ino_t parent, const char \
*name)  int uname_len;
 	u64 ino = (u64)-1;
 	u64 inum;
-	ntfs_inode *dir_ni;	
+	ntfs_inode *dir_ni;
 
 	/* Open target directory. */
 	dir_ni = ntfs_inode_open(ns->ntvol, parent);
@@ -133,7 +133,7 @@ ntfs_inode_lookup(fs_volume *_vol, ino_t parent, const char \
*name)  if (uname_len < 0) {
 			errno = EINVAL;
 			return (ino);
-		}		
+		}
 		/* Lookup file */
 		inum = ntfs_inode_lookup_by_name(dir_ni, uname, uname_len);
 			/* never return inodes 0 and 1 */
@@ -152,11 +152,11 @@ ntfs_inode_lookup(fs_volume *_vol, ino_t parent, const char \
*name)  }
 
 
-static int 
+static int
 ntfs_remove(fs_volume *_vol, ino_t parent, const char *name)
 {
 	nspace *ns = (nspace*)_vol->private_volume;
-	
+
 	ntfschar *uname = NULL;
 	ntfs_inode *ni = NULL;
 	ntfs_inode *dir_ni = NULL;
@@ -193,17 +193,17 @@ ntfs_remove(fs_volume *_vol, ino_t parent, const char *name)
 		result = EINVAL;
 		goto exit;
 	}
-        
+
 	if (ntfs_delete(ns->ntvol, (char*)NULL, ni, dir_ni, uname, uname_len))
 			result = EINVAL;
 		/* ntfs_delete() always closes ni and dir_ni */
-	ni = dir_ni = NULL;	
+	ni = dir_ni = NULL;
 exit:
 	if (ni != NULL)
 		ntfs_inode_close(ni);
 	if (dir_ni != NULL)
 		ntfs_inode_close(dir_ni);
-		
+
 	free(uname);
 	return result;
 }
@@ -268,7 +268,7 @@ fs_identify_partition(int fd, partition_data *partition, void \
**_cookie)  if (ntVolume->vol_name && ntVolume->vol_name[0] != '\0')
 				strcpy(cookie->label, ntVolume->vol_name);
 			ntfs_umount(ntVolume, true);
-		}	
+		}
 	}
 
 	*_cookie = cookie;
@@ -313,14 +313,14 @@ fs_get_supported_operations(partition_data* partition, uint32 \
mask)  status_t
 fs_initialize(int fd, partition_id partitionID, const char* name,
 	const char* parameterString, off_t partitionSize, disk_job_id job)
-{	
+{
 	char devpath[MAX_PATH];
 	status_t result = B_OK;
 
 	TRACE("fs_initialize - [%s] - [%s]\n",name, parameterString);
-	
+
 	update_disk_device_job_progress(job, 0);
-		
+
 	if (ioctl(fd, B_GET_PATH_FOR_DEVICE, devpath) != 0) {
 		result = mkntfs_main(devpath, name);
 		if (result != 0)
@@ -414,7 +414,7 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const \
char *args,  gNTFSVnodeOps.read_attr = fs_read_attrib;
 		gNTFSVnodeOps.read_attr_stat = fs_read_attrib_stat;
 		gNTFSVnodeOps.write_attr = fs_write_attrib;
-		gNTFSVnodeOps.remove_attr = fs_remove_attrib;		
+		gNTFSVnodeOps.remove_attr = fs_remove_attrib;
 	}
 
 	ns->ntvol = utils_mount_volume(device, mountFlags | NTFS_MNT_RECOVER);
@@ -521,7 +521,7 @@ fs_rfsstat(fs_volume *_vol, struct fs_info *fss)
 
 		size = (double)((10 * diskSize + divisor - 1) / divisor);
 		snprintf(fss->volume_name, sizeof(fss->volume_name), "%g %cB NTFS Volume",
-			size / 10, unit);	
+			size / 10, unit);
 	} else
 		fss->volume_name[i + 1] = 0;
 
@@ -598,7 +598,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_dir, const char *file, ino_t \
*_vnid)  
 		if (newNode!=NULL)
 			newNode->parent_vnid = baseNode->vnid;
-			
+
 		*_vnid = vnid;
 	}
 
@@ -686,7 +686,7 @@ fs_read_vnode(fs_volume *_vol, ino_t vnid, fs_vnode *_node, int \
*_type,  
 		newNode->vnid = vnid;
 		newNode->parent_vnid = ntfs_mft_get_parent_ref(ni);
-		
+
 		if (ns->fake_attrib) {
 			if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
 				set_mime(newNode, NULL);
@@ -905,7 +905,7 @@ fs_wstat(fs_volume *_vol, fs_vnode *_node, const struct stat *st, \
uint32 mask)  
 			ntfs_mark_free_space_outdated(ns);
 
-			notify_stat_changed(ns->id, MREF(ni->mft_no), mask);
+			notify_stat_changed(ns->id, -1, MREF(ni->mft_no), mask);
 		}
 	}
 
@@ -916,7 +916,7 @@ fs_wstat(fs_volume *_vol, fs_vnode *_node, const struct stat *st, \
uint32 mask)  ni->last_data_change_time = timespec2ntfs(st->st_mtim);
 		ni->last_mft_change_time = timespec2ntfs(st->st_ctim);
 
-		notify_stat_changed(ns->id, MREF(ni->mft_no), mask);
+		notify_stat_changed(ns->id, -1, MREF(ni->mft_no), mask);
 	}
 
 exit:
@@ -1057,9 +1057,9 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, \
int omode,  status_t result = B_NO_ERROR;
 	int unameLength;
 
-	if (ns->flags & B_FS_IS_READONLY) {		
+	if (ns->flags & B_FS_IS_READONLY) {
 		return B_READ_ONLY_DEVICE;
-	}	
+	}
 
 	LOCK_VOL(ns);
 
@@ -1111,7 +1111,7 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, \
int omode,  if (na != NULL) {
 				if (ntfs_attr_truncate(na, 0))
 					result = errno;
-				ntfs_attr_close(na);					
+				ntfs_attr_close(na);
 			} else
 				result = errno;
 		}
@@ -1121,7 +1121,7 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, \
int omode,  ni = ntfs_create(dir_ni, securid, uname, unameLength, S_IFREG);
 		if (ni != NULL)	{
 			ino_t vnid = MREF(ni->mft_no);
-			
+
 			newNode = (vnode*)ntfs_calloc(sizeof(vnode));
 			if (newNode == NULL) {
 			 	result = ENOMEM;
@@ -1130,17 +1130,17 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, \
int omode,  
 			newNode->vnid = vnid;
 			newNode->parent_vnid = dir->vnid;
-			
+
 			ni->flags |= FILE_ATTR_ARCHIVE;
 			NInoSetDirty(ni);
 
 			result = publish_vnode(_vol, vnid, (void*)newNode, &gNTFSVnodeOps,
 				S_IFREG, 0);
-				
+
 			if (ntfs_inode_close_in_dir(ni, dir_ni)) {
 				result = EINVAL;
 				goto exit;
-			}				
+			}
 
 			*_vnid = vnid;
 
@@ -1151,8 +1151,8 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, \
int omode,  set_mime(newNode, name);
 			}
 
-			ntfs_mark_free_space_outdated(ns);	
-			fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);	
+			ntfs_mark_free_space_outdated(ns);
+			fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);
 			notify_entry_created(ns->id, dir->vnid, name, vnid);
 		} else
 			result = errno;
@@ -1163,7 +1163,7 @@ exit:
 		*_cookie = cookie;
 	else
 		free(cookie);
-		
+
 	if (dir_ni != NULL)
 		ntfs_inode_close(dir_ni);
 
@@ -1316,7 +1316,7 @@ fs_write(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t \
offset,  if (ntfs_attr_truncate(na, offset + size))
 			size = na->data_size - offset;
 		else
-			notify_stat_changed(ns->id, node->vnid, B_STAT_SIZE);
+			notify_stat_changed(ns->id, -1, node->vnid, B_STAT_SIZE);
 	}
 
 	while (size) {
@@ -1504,10 +1504,10 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char \
*name,  int utargetLength;
 	status_t result = B_NO_ERROR;
 	le32 securid = const_cpu_to_le32(0);
-	
-	if (ns->flags & B_FS_IS_READONLY) {		
+
+	if (ns->flags & B_FS_IS_READONLY) {
 		return B_READ_ONLY_DEVICE;
-	}	
+	}
 
 	LOCK_VOL(ns);
 
@@ -1517,10 +1517,10 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char \
*name,  result = EINVAL;
 		goto exit;
 	}
-	
+
 	dir_ni = ntfs_inode_open(ns->ntvol, dir->vnid);
 	if (dir_ni == NULL) {
-		result = ENOENT;		
+		result = ENOENT;
 		goto exit;
 	}
 
@@ -1548,7 +1548,7 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char \
*name,  
 		newNode->vnid = vnid;
 		newNode->parent_vnid = MREF(dir_ni->mft_no);
-		
+
 		ni->flags |= FILE_ATTR_ARCHIVE;
 		NInoSetDirty(ni);
 
@@ -1556,15 +1556,15 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char \
*name,  result = publish_vnode(_vol, vnid, (void*)newNode, &gNTFSVnodeOps,
 			S_IFREG, 0);
 		put_vnode(_vol, vnid);
-					
+
 		if (ntfs_inode_close_in_dir(ni, dir_ni)) {
 			result = EINVAL;
 			goto exit;
 		}
 
-		ntfs_mark_free_space_outdated(ns);						
-		fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);			
-		notify_entry_created(ns->id, MREF(dir_ni->mft_no), name, vnid);			
+		ntfs_mark_free_space_outdated(ns);
+		fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);
+		notify_entry_created(ns->id, MREF(dir_ni->mft_no), name, vnid);
 	} else
 		result = errno;
 
@@ -1630,16 +1630,16 @@ fs_mkdir(fs_volume *_vol, fs_vnode *_dir, const char \
*name,	int perms)  ni = ntfs_create(dir_ni, securid, uname, unameLength, S_IFDIR);
 	if (ni != NULL)	{
 		ino_t vnid = MREF(ni->mft_no);
-	
+
 		newNode = (vnode*)ntfs_calloc(sizeof(vnode));
 		if (newNode == NULL) {
 		 	result = ENOMEM;
 		 	goto exit;
 		}
-		
+
 		newNode->vnid = vnid;
 		newNode->parent_vnid = MREF(dir_ni->mft_no);
-		
+
 		ni->flags |= FILE_ATTR_ARCHIVE;
 		NInoSetDirty(ni);
 
@@ -1700,51 +1700,51 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *name,
 
 	LOCK_VOL(ns);
 
-	TRACE("NTFS:fs_rename - oldname:%s newname:%s\n", name, newname);	
-	
+	TRACE("NTFS:fs_rename - oldname:%s newname:%s\n", name, newname);
+
 	inode = ntfs_inode_lookup(_vol, parent_vnid, name);
 	if (inode == (u64)-1) {
 		result = EINVAL;
-		goto exit;		
+		goto exit;
 	}
-	
+
 	/* Check whether target is present */
 	target_inode = ntfs_inode_lookup(_vol, newparent_vnid, newname);
-		
+
 	if (target_inode == (u64)-1) {
 		ntfschar *uname = NULL;
 		int uname_len;
 
 		result = get_vnode(_vol, inode, (void**)&file);
 		if (result != B_NO_ERROR)
-			goto exit;	
+			goto exit;
+
 
-				
 		ni = ntfs_inode_open(ns->ntvol, inode);
 		if (!ni) {
 			result = EINVAL;
 			goto exit;
 		}
-		
+
 		uname_len = ntfs_mbstoucs(newname, &uname);
 		if (uname_len < 0) {
 			result = EINVAL;
 			goto exit;
 		}
-				
+
 		dir_ni = ntfs_inode_open(ns->ntvol, newparent_vnid);
 		if (!dir_ni) {
 			result = EINVAL;
 			goto exit;
-		}		
-		
+		}
+
 		if (ntfs_link(ni, dir_ni, uname, uname_len)) {
 			result = EINVAL;
 			goto exit;
 		}
 
 		ni->flags |= FILE_ATTR_ARCHIVE;
-				
+
 		fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_CTIME);
 		fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);
 
@@ -1753,13 +1753,13 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *name,
 				set_mime(file, NULL);
 			else
 				set_mime(file, newname);
-			notify_attribute_changed(ns->id, file->vnid, "BEOS:TYPE",
+			notify_attribute_changed(ns->id, -1, file->vnid, "BEOS:TYPE",
 				B_ATTR_CHANGED);
 		}
 
-		ntfs_inode_close(dir_ni);             
+		ntfs_inode_close(dir_ni);
 		ntfs_inode_close(ni);
-		
+
         free(uname);
 
 		ntfs_remove(_vol, parent_vnid, name);
@@ -1767,10 +1767,10 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *name,
 		file->parent_vnid = newparent_vnid;
 
 		put_vnode(_vol, file->vnid);
-				
+
 		notify_entry_moved(ns->id, parent_vnid, name, newparent_vnid,
 			newname, inode);
-	} else 
+	} else
 		result = EINVAL;
 exit:
 	TRACE("fs_rename - EXIT, result is %s\n", strerror(result));
@@ -1814,13 +1814,13 @@ fs_rmdir(fs_volume *_vol, fs_vnode *_dir, const char *name)
 	ino = ntfs_inode_lookup(_vol, dir->vnid, name);
 	if (ino == (u64)-1) {
 		result = EINVAL;
-		goto exit;		
-	}	
+		goto exit;
+	}
 
 	result = get_vnode(_vol, ino, (void**)&file);
 	if (result != B_NO_ERROR)
-		goto exit;	
-	
+		goto exit;
+
 	ni = ntfs_inode_open(ns->ntvol, file->vnid);
 	if (ni != NULL) {
 		if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
@@ -1836,31 +1836,31 @@ fs_rmdir(fs_volume *_vol, fs_vnode *_dir, const char *name)
 		result = EINVAL;
 		goto exit;
 	}
-		
-	
+
+
 	result = ntfs_remove(_vol, dir->vnid, name);
 	if(result != B_NO_ERROR) {
 		goto exit;
 	}
-	
+
 	notify_entry_removed(ns->id, dir->vnid, name, file->vnid);
-	
+
 	remove_vnode(_vol, file->vnid);
-	
-	put_vnode(_vol, ino);	
+
+	put_vnode(_vol, ino);
 
 	dir_ni = ntfs_inode_open(ns->ntvol, dir->vnid);
 	if (dir_ni != NULL) {
 		fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);
 		ntfs_inode_close(dir_ni);
 	}
-	
+
 	ntfs_mark_free_space_outdated(ns);
 
 exit:
 	if (ni != NULL)
 		ntfs_inode_close(ni);
-		
+
 	TRACE("fs_rmdir - EXIT, result is %s\n", strerror(result));
 
 	UNLOCK_VOL(ns);
@@ -1901,13 +1901,13 @@ fs_unlink(fs_volume *_vol, fs_vnode *_dir, const char *name)
 	inode = ntfs_inode_lookup(_vol, dir->vnid, name);
 	if (inode == (u64)-1) {
 		result = EINVAL;
-		goto exit;		
-	}	
+		goto exit;
+	}
 
 	result = get_vnode(_vol, inode, (void**)&file);
 	if (result != B_NO_ERROR)
-		goto exit;	
-	
+		goto exit;
+
 	result = ntfs_remove(_vol, dir->vnid, name);
 	if(result != B_NO_ERROR) {
 		goto exit;
@@ -1917,7 +1917,7 @@ fs_unlink(fs_volume *_vol, fs_vnode *_dir, const char *name)
 
 	remove_vnode(_vol, file->vnid);
 
-	put_vnode(_vol, inode);	
+	put_vnode(_vol, inode);
 
 	dir_ni = ntfs_inode_open(ns->ntvol, dir->vnid);
 	if (dir_ni != NULL) {
@@ -1926,7 +1926,7 @@ fs_unlink(fs_volume *_vol, fs_vnode *_dir, const char *name)
 	}
 
 	ntfs_mark_free_space_outdated(ns);
-	
+
 exit:
 	TRACE("fs_unlink - EXIT, result is %s\n", strerror(result));
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp \
b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp index 7007d00..b8949b4 \
                100644
--- a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp
@@ -680,7 +680,9 @@ void
 Volume::PackageLinkNodeChanged(Node* node, uint32 statFields,
 	const OldNodeAttributes& oldAttributes)
 {
-	notify_stat_changed(ID(), node->ID(), statFields);
+	Directory* parent = node->Parent();
+	notify_stat_changed(ID(), parent != NULL ? parent->ID() : -1, node->ID(),
+		statFields);
 	_NotifyNodeChanged(node, statFields, oldAttributes);
 }
 
@@ -1261,7 +1263,8 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* \
packageNode,  // The new package node has become the one representing the node.
 			// Send stat changed notification for directories and entry
 			// removed + created notifications for files and symlinks.
-			notify_stat_changed(ID(), node->ID(), kAllStatFields);
+			notify_stat_changed(ID(), directory->ID(), node->ID(),
+				kAllStatFields);
 			// TODO: Actually the attributes might change, too!
 		}
 	}
@@ -1356,7 +1359,8 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* \
packageNode,  // Send stat changed notification for directories and entry
 		// removed + created notifications for files and symlinks.
 		if (S_ISDIR(packageNode->Mode())) {
-			notify_stat_changed(ID(), node->ID(), kAllStatFields);
+			notify_stat_changed(ID(), directory->ID(), node->ID(),
+				kAllStatFields);
 			// TODO: Actually the attributes might change, too!
 		} else {
 			notify_entry_removed(ID(), directory->ID(), node->Name(),
diff --git a/src/add-ons/kernel/file_systems/ramfs/Jamfile \
b/src/add-ons/kernel/file_systems/ramfs/Jamfile index 33bc97b..5cf9133 100644
--- a/src/add-ons/kernel/file_systems/ramfs/Jamfile
+++ b/src/add-ons/kernel/file_systems/ramfs/Jamfile
@@ -4,7 +4,8 @@ local userlandFSTop = [ FDirName $(HAIKU_TOP) src add-ons kernel
 	file_systems userlandfs ] ;
 local userlandFSIncludes = [ PrivateHeaders userlandfs ] ;
 
-UsePrivateHeaders kernel shared ;
+UsePrivateHeaders shared ;
+UsePrivateKernelHeaders ;
 
 SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
 
diff --git a/src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp \
b/src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp index 2bf4e81..64427a0 \
                100644
--- a/src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp
@@ -70,7 +70,7 @@ notify_if_stat_changed(Volume *volume, Node *node)
 {
 	if (volume && node && node->IsModified()) {
 		uint32 statFields = node->MarkUnmodified();
-		notify_stat_changed(volume->GetID(), node->GetID(), statFields);
+		notify_stat_changed(volume->GetID(), -1, node->GetID(), statFields);
 	}
 }
 
@@ -1093,11 +1093,11 @@ private:
 	// debugging
 	int32			fIteratorID;
 	int32			fGetNextCounter;
-	static vint32	fNextIteratorID;
+	static int32	fNextIteratorID;
 };
 
 
-vint32 DirectoryCookie::fNextIteratorID = 0;
+int32 DirectoryCookie::fNextIteratorID = 0;
 
 
 // ramfs_create_dir
@@ -1531,7 +1531,7 @@ ramfs_create_attr(fs_volume* _volume, fs_vnode* _node, const \
char *name,  
 			attribute->SetType(type);
 
-			notify_attribute_changed(volume->GetID(), node->GetID(), name,
+			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
 				B_ATTR_CREATED);
 
 		// else truncate if requested
@@ -1540,7 +1540,7 @@ ramfs_create_attr(fs_volume* _volume, fs_vnode* _node, const \
char *name,  if (error != B_OK)
 				return error;
 
-			notify_attribute_changed(volume->GetID(), node->GetID(), name,
+			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
 				B_ATTR_CHANGED);
 		}
 		NodeMTimeUpdater mTimeUpdater(node);
@@ -1598,8 +1598,8 @@ ramfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char \
*name,  error = attribute->SetSize(0);
 
 			if (error == B_OK) {
-				notify_attribute_changed(volume->GetID(), node->GetID(), name,
-					B_ATTR_CHANGED);
+				notify_attribute_changed(volume->GetID(), -1, node->GetID(),
+					name, B_ATTR_CHANGED);
 			}
 		}
 		NodeMTimeUpdater mTimeUpdater(node);
@@ -1718,7 +1718,7 @@ ramfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* \
_cookie,  
 		// notify listeners
 		if (error == B_OK) {
-			notify_attribute_changed(volume->GetID(), node->GetID(), name,
+			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
 				B_ATTR_CHANGED);
 		}
 	} else
@@ -1797,7 +1797,7 @@ ramfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const \
char *name)  
 		// notify listeners
 		if (error == B_OK) {
-			notify_attribute_changed(volume->GetID(), node->GetID(), name,
+			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
 				B_ATTR_REMOVED);
 		}
 	} else
diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp \
b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp \
                index d038f24..6bfc4fb 100644
--- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp
                
+++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp
 @@ -211,8 +211,8 @@ KernelRequestHandler::_HandleRequest(NotifyListenerRequest* \
request)  PRINT(("notify_stat_changed(%" B_PRId32 ", %" B_PRId64 ", "
 					"0x%" B_PRIx32 ")\n", request->device, request->node,
 					request->details));
-				result = notify_stat_changed(request->device, request->node,
-					request->details);
+				result = notify_stat_changed(request->device,
+					request->directory, request->node, request->details);
 				break;
 
 			case B_ATTR_CHANGED:
@@ -220,7 +220,8 @@ KernelRequestHandler::_HandleRequest(NotifyListenerRequest* \
request)  "\"%s\", 0x%" B_PRIx32 ")\n", request->device,
 					request->node, name, (int32)request->details));
 				result = notify_attribute_changed(request->device,
-					request->node, name, (int32)request->details);
+					request->directory, request->node, name,
+					(int32)request->details);
 				break;
 
 			default:
diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp \
b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp index \
                48b3724..62e8c46 100644
--- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp
+++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp
@@ -96,23 +96,24 @@ notify_entry_moved(dev_t device, ino_t fromDirectory,
 
 // notify_stat_changed
 status_t
-notify_stat_changed(dev_t device, ino_t node, uint32 statFields)
+notify_stat_changed(dev_t device, ino_t directory, ino_t node,
+	uint32 statFields)
 {
 	return UserlandFS::KernelEmu::notify_listener(B_STAT_CHANGED, statFields,
-		device, 0, 0, node, NULL, NULL);
+		device, 0, directory, node, NULL, NULL);
 }
 
 
 // notify_attribute_changed
 status_t
-notify_attribute_changed(dev_t device, ino_t node, const char *attribute,
-	int32 cause)
+notify_attribute_changed(dev_t device, ino_t directory, ino_t node,
+	const char *attribute, int32 cause)
 {
 	if (!attribute)
 		return B_BAD_VALUE;
 
 	return UserlandFS::KernelEmu::notify_listener(B_ATTR_CHANGED, cause,
-		device, 0, 0, node, NULL, attribute);
+		device, 0, directory, node, NULL, attribute);
 }
 
 
diff --git a/src/system/kernel/device_manager/devfs.cpp \
b/src/system/kernel/device_manager/devfs.cpp index af6c7f7..c0139f3 100644
--- a/src/system/kernel/device_manager/devfs.cpp
+++ b/src/system/kernel/device_manager/devfs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2012, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  *
  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -196,6 +196,15 @@ current_timespec()
 }
 
 
+static ino_t
+get_parent_id(struct devfs_vnode* vnode)
+{
+	if (vnode->parent != NULL)
+		return vnode->parent->id;
+	return -1;
+}
+
+
 static int32
 scan_mode(void)
 {
@@ -378,7 +387,7 @@ devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* \
vnode,  if (notify) {
 		notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name,
 			vnode->id);
-		notify_stat_changed(sDeviceFileSystem->id, dir->id,
+		notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir), dir->id,
 			B_STAT_MODIFICATION_TIME);
 	}
 	return B_OK;
@@ -407,8 +416,8 @@ devfs_remove_from_dir(struct devfs_vnode* dir, struct \
devfs_vnode* removeNode,  if (notify) {
 				notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name,
 					vnode->id);
-				notify_stat_changed(sDeviceFileSystem->id, dir->id,
-					B_STAT_MODIFICATION_TIME);
+				notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir),
+					dir->id, B_STAT_MODIFICATION_TIME);
 			}
 			return B_OK;
 		}
@@ -1833,7 +1842,7 @@ devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const \
struct stat* stat,  if (statMask & B_STAT_CREATION_TIME)
 		vnode->creation_time = stat->st_crtim;
 
-	notify_stat_changed(fs->id, vnode->id, statMask);
+	notify_stat_changed(fs->id, get_parent_id(vnode), vnode->id, statMask);
 	return B_OK;
 }
 
@@ -2081,8 +2090,8 @@ devfs_rename_partition(const char* devicePath, const char* \
oldName,  
 	notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName,
 		device->parent->id, newName, node->id);
-	notify_stat_changed(sDeviceFileSystem->id, device->parent->id,
-		B_STAT_MODIFICATION_TIME);
+	notify_stat_changed(sDeviceFileSystem->id, get_parent_id(device->parent),
+		device->parent->id, B_STAT_MODIFICATION_TIME);
 
 	return B_OK;
 }
diff --git a/src/system/kernel/fs/node_monitor.cpp \
b/src/system/kernel/fs/node_monitor.cpp index 95f1641..a953e75 100644
--- a/src/system/kernel/fs/node_monitor.cpp
+++ b/src/system/kernel/fs/node_monitor.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
+ * Copyright 2003-2016, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
  * Copyright 2005-2008, Ingo Weinhold, bonefish@users.sf.net.
  * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
  *
@@ -97,9 +97,10 @@ class NodeMonitorService : public NotificationService {
 		status_t NotifyEntryMoved(dev_t device, ino_t fromDirectory,
 			const char *fromName, ino_t toDirectory, const char *toName,
 			ino_t node);
-		status_t NotifyStatChanged(dev_t device, ino_t node, uint32 statFields);
-		status_t NotifyAttributeChanged(dev_t device, ino_t node,
-			const char *attribute, int32 cause);
+		status_t NotifyStatChanged(dev_t device, ino_t directory, ino_t node,
+			uint32 statFields);
+		status_t NotifyAttributeChanged(dev_t device, ino_t directory,
+			ino_t node, const char *attribute, int32 cause);
 		status_t NotifyUnmount(dev_t device);
 		status_t NotifyMount(dev_t device, dev_t parentDevice,
 			ino_t parentDirectory);
@@ -547,7 +548,7 @@ NodeMonitorService::_GetInterestedMonitorListeners(dev_t device, \
ino_t node,  // iterate through the listeners until we find one with matching flags
 	MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator();
 	while (monitor_listener *listener = iterator.Next()) {
-		if (listener->flags & flags) {
+		if ((listener->flags & flags) == flags) {
 			interested_monitor_listener_list &list
 				= interestedListeners[interestedListenerCount++];
 			list.iterator = iterator;
@@ -571,7 +572,7 @@ NodeMonitorService::_GetInterestedVolumeListeners(dev_t device, \
uint32 flags,  // iterate through the listeners until we find one with matching flags
 	MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator();
 	while (monitor_listener *listener = iterator.Next()) {
-		if (listener->flags & flags) {
+		if ((listener->flags & flags) == flags) {
 			interested_monitor_listener_list &list
 				= interestedListeners[interestedListenerCount++];
 			list.iterator = iterator;
@@ -730,21 +731,29 @@ NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t \
fromDirectory,  
 
 inline status_t
-NodeMonitorService::NotifyStatChanged(dev_t device, ino_t node,
+NodeMonitorService::NotifyStatChanged(dev_t device, ino_t directory, ino_t node,
 	uint32 statFields)
 {
 	RecursiveLocker locker(fRecursiveLock);
 
-	// get the lists of all interested listeners
+	// get the lists of all interested listeners depending on whether its an
+	// interim update or not
 	interested_monitor_listener_list interestedListeners[3];
 	int32 interestedListenerCount = 0;
+	uint32 watchFlag = (statFields & B_STAT_INTERIM_UPDATE) != 0
+		? B_WATCH_INTERIM_STAT : B_WATCH_STAT;
+
 	// ... for the volume
-	_GetInterestedVolumeListeners(device, B_WATCH_STAT,
-		interestedListeners, interestedListenerCount);
-	// ... for the node, depending on whether its an interim update or not
-	_GetInterestedMonitorListeners(device, node,
-		(statFields & B_STAT_INTERIM_UPDATE) != 0
-			? B_WATCH_INTERIM_STAT : B_WATCH_STAT,
+	_GetInterestedVolumeListeners(device, watchFlag, interestedListeners,
+		interestedListenerCount);
+	// ... for the directory
+	if (directory >= 0) {
+		_GetInterestedMonitorListeners(device, directory,
+			B_WATCH_CHILDREN | watchFlag,
+			interestedListeners, interestedListenerCount);
+	}
+	// ... and for the node
+	_GetInterestedMonitorListeners(device, node, watchFlag,
 		interestedListeners, interestedListenerCount);
 
 	if (interestedListenerCount == 0)
@@ -775,8 +784,8 @@ NodeMonitorService::NotifyStatChanged(dev_t device, ino_t node,
 	- another error code otherwise.
 */
 status_t
-NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t node,
-	const char *attribute, int32 cause)
+NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t directory,
+	ino_t node, const char *attribute, int32 cause)
 {
 	if (!attribute)
 		return B_BAD_VALUE;
@@ -789,6 +798,12 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t \
node,  // ... for the volume
 	_GetInterestedVolumeListeners(device, B_WATCH_ATTR,
 		interestedListeners, interestedListenerCount);
+	// ... for the directory
+	if (directory >= 0) {
+		_GetInterestedMonitorListeners(device, directory,
+			B_WATCH_CHILDREN | B_WATCH_ATTR,
+			interestedListeners, interestedListenerCount);
+	}
 	// ... for the node
 	_GetInterestedMonitorListeners(device, node, B_WATCH_ATTR,
 		interestedListeners, interestedListenerCount);
@@ -802,6 +817,8 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t \
node,  message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
 	message.AddInt32("opcode", B_ATTR_CHANGED);
 	message.AddInt32("device", device);
+	if (directory >= 0)
+		message.AddInt64("directory", directory);
 	message.AddInt64("node", node);
 	message.AddString("attr", attribute);
 	message.AddInt32("cause", cause);		// Haiku only
@@ -1155,9 +1172,11 @@ notify_entry_moved(dev_t device, ino_t fromDirectory,
   	- another error code otherwise.
 */
 status_t
-notify_stat_changed(dev_t device, ino_t node, uint32 statFields)
+notify_stat_changed(dev_t device, ino_t directory, ino_t node,
+	uint32 statFields)
 {
-	return sNodeMonitorService.NotifyStatChanged(device, node, statFields);
+	return sNodeMonitorService.NotifyStatChanged(device, directory, node,
+		statFields);
 }
 
 
@@ -1172,11 +1191,11 @@ notify_stat_changed(dev_t device, ino_t node, uint32 \
                statFields)
   	- another error code otherwise.
 */
 status_t
-notify_attribute_changed(dev_t device, ino_t node, const char *attribute,
-	int32 cause)
+notify_attribute_changed(dev_t device, ino_t directory, ino_t node,
+	const char *attribute, int32 cause)
 {
-	return sNodeMonitorService.NotifyAttributeChanged(device, node, attribute,
-		cause);
+	return sNodeMonitorService.NotifyAttributeChanged(device, directory, node,
+		attribute, cause);
 }
 
 
diff --git a/src/system/kernel/fs/rootfs.cpp b/src/system/kernel/fs/rootfs.cpp
index 2dbd5b1..21214fa 100644
--- a/src/system/kernel/fs/rootfs.cpp
+++ b/src/system/kernel/fs/rootfs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  *
  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -149,6 +149,15 @@ current_timespec()
 }
 
 
+static ino_t
+get_parent_id(struct rootfs_vnode* vnode)
+{
+	if (vnode->parent != NULL)
+		return vnode->parent->id;
+	return -1;
+}
+
+
 static struct rootfs_vnode*
 rootfs_create_vnode(struct rootfs* fs, struct rootfs_vnode* parent,
 	const char* name, int type)
@@ -264,7 +273,8 @@ rootfs_insert_in_dir(struct rootfs* fs, struct rootfs_vnode* dir,
 	vnode->parent = dir;
 	dir->modification_time = current_timespec();
 
-	notify_stat_changed(fs->id, dir->id, B_STAT_MODIFICATION_TIME);
+	notify_stat_changed(fs->id, get_parent_id(dir), dir->id,
+		B_STAT_MODIFICATION_TIME);
 	return B_OK;
 }
 
@@ -289,7 +299,8 @@ rootfs_remove_from_dir(struct rootfs* fs, struct rootfs_vnode* \
dir,  vnode->dir_next = NULL;
 
 			dir->modification_time = current_timespec();
-			notify_stat_changed(fs->id, dir->id, B_STAT_MODIFICATION_TIME);
+			notify_stat_changed(fs->id, get_parent_id(dir), dir->id,
+				B_STAT_MODIFICATION_TIME);
 			return B_OK;
 		}
 	}
@@ -1057,7 +1068,7 @@ rootfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const \
struct stat* stat,  
 	locker.Unlock();
 
-	notify_stat_changed(fs->id, vnode->id, statMask);
+	notify_stat_changed(fs->id, get_parent_id(vnode), vnode->id, statMask);
 	return B_OK;
 }
 
diff --git a/src/tools/fs_shell/node_monitor.cpp \
b/src/tools/fs_shell/node_monitor.cpp index daa604d..f15aa9e 100644
--- a/src/tools/fs_shell/node_monitor.cpp
+++ b/src/tools/fs_shell/node_monitor.cpp
@@ -33,16 +33,16 @@ fssh_notify_entry_moved(fssh_mount_id device, fssh_vnode_id \
fromDirectory,  
 
 fssh_status_t
-fssh_notify_stat_changed(fssh_mount_id device, fssh_vnode_id node,
-	uint32_t statFields)
+fssh_notify_stat_changed(fssh_mount_id device, fssh_vnode_id dir,
+	fssh_vnode_id node, uint32_t statFields)
 {
 	return FSSH_B_OK;
 }
 
 
 fssh_status_t
-fssh_notify_attribute_changed(fssh_mount_id device, fssh_vnode_id node,
-	const char *attribute, int32_t cause)
+fssh_notify_attribute_changed(fssh_mount_id device, fssh_vnode_id dir,
+	fssh_vnode_id node, const char *attribute, int32_t cause)
 {
 	return FSSH_B_OK;
 }

############################################################################

Revision:    hrev50171
Commit:      67988f501a67260d2dd434d517d08dcef29807e0
URL:         http://cgit.haiku-os.org/haiku/commit/?id=67988f501a67
Author:      Axel Dörfler <axeld@pinc-software.de>
Date:        Mon Mar 21 19:12:44 2016 UTC

NodeMonitor: Resolve mount points for B_WATCH_CHILDREN.

* When a watched directory contains a mount point, we need to resolve
  the actual parent directory of the mount point in the file system to
  serve the monitor.

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h
index f108cd0..fc818ba 100644
--- a/headers/private/kernel/vfs.h
+++ b/headers/private/kernel/vfs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2015, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  *
  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -126,6 +126,8 @@ status_t	vfs_get_cwd(dev_t *_mountID, ino_t *_vnodeID);
 void		vfs_unlock_vnode_if_locked(struct file_descriptor *descriptor);
 status_t	vfs_unmount(dev_t mountID, uint32 flags);
 status_t	vfs_disconnect_vnode(dev_t mountID, ino_t vnodeID);
+status_t	vfs_resolve_parent(struct vnode* parent, dev_t* device,
+				ino_t* node);
 void		vfs_free_unused_vnodes(int32 level);
 
 status_t	vfs_read_stat(int fd, const char *path, bool traverseLeafLink,
diff --git a/src/system/kernel/fs/node_monitor.cpp \
b/src/system/kernel/fs/node_monitor.cpp index a953e75..092f217 100644
--- a/src/system/kernel/fs/node_monitor.cpp
+++ b/src/system/kernel/fs/node_monitor.cpp
@@ -26,6 +26,7 @@
 #include <util/list.h>
 
 #include "node_monitor_private.h"
+#include "Vnode.h"
 
 
 //#define TRACE_MONITOR
@@ -153,6 +154,8 @@ class NodeMonitorService : public NotificationService {
 		status_t _SendNotificationMessage(KMessage &message,
 			interested_monitor_listener_list *interestedListeners,
 			int32 interestedListenerCount);
+		void _ResolveMountPoint(dev_t device, ino_t directory,
+			dev_t& parentDevice, ino_t& parentDirectory);
 
 		struct monitor_hash_key {
 			dev_t	device;
@@ -623,6 +626,25 @@ NodeMonitorService::_SendNotificationMessage(KMessage &message,
 }
 
 
+/*!	\brief Resolves the device/directory node pair to the node it's covered
+	by, if any.
+*/
+void
+NodeMonitorService::_ResolveMountPoint(dev_t device, ino_t directory,
+	dev_t& parentDevice, ino_t& parentDirectory)
+{
+	struct vnode* vnode;
+	status_t status = vfs_get_vnode(device, directory, true, &vnode);
+	if (status == B_OK) {
+		if (vnode->covers != NULL)
+			status = vfs_resolve_parent(vnode, &parentDevice, &parentDirectory);
+		vfs_put_vnode(vnode);
+	}
+	if (status != B_OK)
+		dprintf("Resolving mount point %ld:%lld failed!\n", device, directory);
+}
+
+
 /*!	\brief Notifies all interested listeners that an entry has been created
 		   or removed.
 	\param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED.
@@ -747,8 +769,15 @@ NodeMonitorService::NotifyStatChanged(dev_t device, ino_t \
directory, ino_t node,  _GetInterestedVolumeListeners(device, watchFlag, \
interestedListeners,  interestedListenerCount);
 	// ... for the directory
-	if (directory >= 0) {
-		_GetInterestedMonitorListeners(device, directory,
+	if (directory > 0) {
+		dev_t parentDevice = device;
+		ino_t parentDirectory = directory;
+		if (directory == node) {
+			// This is a mount point -- get its file system parent
+			_ResolveMountPoint(device, directory, parentDevice,
+				parentDirectory);
+		}
+		_GetInterestedMonitorListeners(parentDevice, parentDirectory,
 			B_WATCH_CHILDREN | watchFlag,
 			interestedListeners, interestedListenerCount);
 	}
@@ -799,8 +828,15 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t \
directory,  _GetInterestedVolumeListeners(device, B_WATCH_ATTR,
 		interestedListeners, interestedListenerCount);
 	// ... for the directory
-	if (directory >= 0) {
-		_GetInterestedMonitorListeners(device, directory,
+	if (directory > 0) {
+		dev_t parentDevice = device;
+		ino_t parentDirectory = directory;
+		if (directory == node) {
+			// This is a mount point -- get its file system parent
+			_ResolveMountPoint(device, directory, parentDevice,
+				parentDirectory);
+		}
+		_GetInterestedMonitorListeners(parentDevice, parentDirectory,
 			B_WATCH_CHILDREN | B_WATCH_ATTR,
 			interestedListeners, interestedListenerCount);
 	}
diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
index 7e23512..0482459 100644
--- a/src/system/kernel/fs/vfs.cpp
+++ b/src/system/kernel/fs/vfs.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
- * Copyright 2002-2015, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  *
  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -2914,6 +2914,34 @@ normalize_path(char* path, size_t pathSize, bool traverseLink, \
bool kernel)  }
 
 
+static status_t
+resolve_covered_parent(struct vnode* parent, dev_t* _device, ino_t* _node,
+	struct io_context* ioContext)
+{
+	// Make sure the IO context root is not bypassed.
+	if (parent == ioContext->root) {
+		*_device = parent->device;
+		*_node = parent->id;
+		return B_OK;
+	}
+
+	inc_vnode_ref_count(parent);
+		// vnode_path_to_vnode() puts the node
+
+	// ".." is guaranteed not to be clobbered by this call
+	struct vnode* vnode;
+	status_t status = vnode_path_to_vnode(parent, (char*)"..", false, 0,
+		ioContext, &vnode, NULL);
+	if (status == B_OK) {
+		*_device = vnode->device;
+		*_node = vnode->id;
+		put_vnode(vnode);
+	}
+
+	return status;
+}
+
+
 #ifdef ADD_DEBUGGER_COMMANDS
 
 
@@ -4425,6 +4453,19 @@ vfs_normalize_path(const char* path, char* buffer, size_t \
bufferSize,

[ *** diff truncated: 70 lines dropped *** ]


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic