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.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2015, Axel Dörfler, [email protected].
|
* Copyright 2002-2016, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* 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);
|
void vfs_unlock_vnode_if_locked(struct file_descriptor *descriptor);
|
||||||
status_t vfs_unmount(dev_t mountID, uint32 flags);
|
status_t vfs_unmount(dev_t mountID, uint32 flags);
|
||||||
status_t vfs_disconnect_vnode(dev_t mountID, ino_t vnodeID);
|
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);
|
void vfs_free_unused_vnodes(int32 level);
|
||||||
|
|
||||||
status_t vfs_read_stat(int fd, const char *path, bool traverseLeafLink,
|
status_t vfs_read_stat(int fd, const char *path, bool traverseLeafLink,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
#include "node_monitor_private.h"
|
#include "node_monitor_private.h"
|
||||||
|
#include "Vnode.h"
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_MONITOR
|
//#define TRACE_MONITOR
|
||||||
@@ -153,6 +154,8 @@ class NodeMonitorService : public NotificationService {
|
|||||||
status_t _SendNotificationMessage(KMessage &message,
|
status_t _SendNotificationMessage(KMessage &message,
|
||||||
interested_monitor_listener_list *interestedListeners,
|
interested_monitor_listener_list *interestedListeners,
|
||||||
int32 interestedListenerCount);
|
int32 interestedListenerCount);
|
||||||
|
void _ResolveMountPoint(dev_t device, ino_t directory,
|
||||||
|
dev_t& parentDevice, ino_t& parentDirectory);
|
||||||
|
|
||||||
struct monitor_hash_key {
|
struct monitor_hash_key {
|
||||||
dev_t device;
|
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
|
/*! \brief Notifies all interested listeners that an entry has been created
|
||||||
or removed.
|
or removed.
|
||||||
\param opcode \c B_ENTRY_CREATED or \c B_ENTRY_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,
|
_GetInterestedVolumeListeners(device, watchFlag, interestedListeners,
|
||||||
interestedListenerCount);
|
interestedListenerCount);
|
||||||
// ... for the directory
|
// ... for the directory
|
||||||
if (directory >= 0) {
|
if (directory > 0) {
|
||||||
_GetInterestedMonitorListeners(device, directory,
|
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,
|
B_WATCH_CHILDREN | watchFlag,
|
||||||
interestedListeners, interestedListenerCount);
|
interestedListeners, interestedListenerCount);
|
||||||
}
|
}
|
||||||
@@ -799,8 +828,15 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t directory,
|
|||||||
_GetInterestedVolumeListeners(device, B_WATCH_ATTR,
|
_GetInterestedVolumeListeners(device, B_WATCH_ATTR,
|
||||||
interestedListeners, interestedListenerCount);
|
interestedListeners, interestedListenerCount);
|
||||||
// ... for the directory
|
// ... for the directory
|
||||||
if (directory >= 0) {
|
if (directory > 0) {
|
||||||
_GetInterestedMonitorListeners(device, directory,
|
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,
|
B_WATCH_CHILDREN | B_WATCH_ATTR,
|
||||||
interestedListeners, interestedListenerCount);
|
interestedListeners, interestedListenerCount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* 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
|
#ifdef ADD_DEBUGGER_COMMANDS
|
||||||
|
|
||||||
|
|
||||||
@@ -4425,6 +4453,19 @@ vfs_normalize_path(const char* path, char* buffer, size_t bufferSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Gets the parent of the passed in node.
|
||||||
|
|
||||||
|
Gets the parent of the passed in node, and correctly resolves covered
|
||||||
|
nodes.
|
||||||
|
*/
|
||||||
|
extern "C" status_t
|
||||||
|
vfs_resolve_parent(struct vnode* parent, dev_t* device, ino_t* node)
|
||||||
|
{
|
||||||
|
return resolve_covered_parent(parent, device, node,
|
||||||
|
get_current_io_context(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Creates a special node in the file system.
|
/*! \brief Creates a special node in the file system.
|
||||||
|
|
||||||
The caller gets a reference to the newly created node (which is passed
|
The caller gets a reference to the newly created node (which is passed
|
||||||
@@ -5863,26 +5904,10 @@ fix_dirent(struct vnode* parent, struct dirent* entry,
|
|||||||
// If this is the ".." entry and the directory covering another vnode,
|
// If this is the ".." entry and the directory covering another vnode,
|
||||||
// we need to replace d_dev and d_ino with the actual values.
|
// we need to replace d_dev and d_ino with the actual values.
|
||||||
if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) {
|
if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) {
|
||||||
// Make sure the IO context root is not bypassed.
|
return resolve_covered_parent(parent, &entry->d_dev, &entry->d_ino,
|
||||||
if (parent == ioContext->root) {
|
ioContext);
|
||||||
entry->d_dev = parent->device;
|
|
||||||
entry->d_ino = parent->id;
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
entry->d_dev = vnode->device;
|
|
||||||
entry->d_ino = vnode->id;
|
|
||||||
put_vnode(vnode);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// resolve covered vnodes
|
// resolve covered vnodes
|
||||||
ReadLocker _(&sVnodeLock);
|
ReadLocker _(&sVnodeLock);
|
||||||
|
|
||||||
@@ -5895,7 +5920,6 @@ fix_dirent(struct vnode* parent, struct dirent* entry,
|
|||||||
entry->d_dev = vnode->device;
|
entry->d_dev = vnode->device;
|
||||||
entry->d_ino = vnode->id;
|
entry->d_ino = vnode->id;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user