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.
|
||||
*
|
||||
* 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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
/*! \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.
|
||||
|
||||
The caller gets a reference to the newly created node (which is passed
|
||||
@@ -5863,38 +5904,21 @@ fix_dirent(struct vnode* parent, struct dirent* entry,
|
||||
// If this is the ".." entry and the directory covering another vnode,
|
||||
// we need to replace d_dev and d_ino with the actual values.
|
||||
if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) {
|
||||
// Make sure the IO context root is not bypassed.
|
||||
if (parent == ioContext->root) {
|
||||
entry->d_dev = parent->device;
|
||||
entry->d_ino = parent->id;
|
||||
} else {
|
||||
inc_vnode_ref_count(parent);
|
||||
// vnode_path_to_vnode() puts the node
|
||||
return resolve_covered_parent(parent, &entry->d_dev, &entry->d_ino,
|
||||
ioContext);
|
||||
}
|
||||
|
||||
// ".." 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);
|
||||
// resolve covered vnodes
|
||||
ReadLocker _(&sVnodeLock);
|
||||
|
||||
if (status == B_OK) {
|
||||
entry->d_dev = vnode->device;
|
||||
entry->d_ino = vnode->id;
|
||||
put_vnode(vnode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// resolve covered vnodes
|
||||
ReadLocker _(&sVnodeLock);
|
||||
struct vnode* vnode = lookup_vnode(entry->d_dev, entry->d_ino);
|
||||
if (vnode != NULL && vnode->covered_by != NULL) {
|
||||
do {
|
||||
vnode = vnode->covered_by;
|
||||
} while (vnode->covered_by != NULL);
|
||||
|
||||
struct vnode* vnode = lookup_vnode(entry->d_dev, entry->d_ino);
|
||||
if (vnode != NULL && vnode->covered_by != NULL) {
|
||||
do {
|
||||
vnode = vnode->covered_by;
|
||||
} while (vnode->covered_by != NULL);
|
||||
|
||||
entry->d_dev = vnode->device;
|
||||
entry->d_ino = vnode->id;
|
||||
}
|
||||
entry->d_dev = vnode->device;
|
||||
entry->d_ino = vnode->id;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
||||
Reference in New Issue
Block a user