Finally applying the patch that adds support to add path information to stat and attr monitor messages.
* for all open FD the path information is stored in a map * this info is used to fill the missing fields in the node monitor
This commit is contained in:
parent
c7413cf90c
commit
610ef6c007
243
src/system/kernel/fs/FDPath.cpp
Normal file
243
src/system/kernel/fs/FDPath.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2011 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler, haiku@clemens-zeidler.de
|
||||
*/
|
||||
|
||||
|
||||
#include "FDPath.h"
|
||||
|
||||
#include <new>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include "vfs.h" // for dump_fd_paths_hash_table
|
||||
#include "Vnode.h"
|
||||
|
||||
|
||||
void
|
||||
PathInfo::SetTo(file_descriptor* fd, ino_t dir, const char* name)
|
||||
{
|
||||
descriptor = fd;
|
||||
directory = dir;
|
||||
strlcpy(filename, name, B_FILE_NAME_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
struct vnode_hash_key {
|
||||
dev_t device;
|
||||
ino_t vnode;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
fd_paths_compare(void* _fd_paths, const void* _key)
|
||||
{
|
||||
vnode* node = ((fd_paths*)_fd_paths)->node;
|
||||
const vnode_hash_key* key = (const vnode_hash_key*)_key;
|
||||
|
||||
if (node->device == key->device && node->id == key->vnode)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
fd_paths_hash(void* _fd_paths, const void* _key, uint32 range)
|
||||
{
|
||||
fd_paths* fdPaths = (fd_paths*)_fd_paths;
|
||||
const vnode_hash_key* key = (const vnode_hash_key*)_key;
|
||||
|
||||
#define VHASH(mountid, vnodeid) \
|
||||
(((uint32)((vnodeid) >> 32) + (uint32)(vnodeid)) ^ (uint32)(mountid))
|
||||
|
||||
if (fdPaths != NULL) {
|
||||
vnode* node = fdPaths->node;
|
||||
return VHASH(node->device, node->id) % range;
|
||||
}
|
||||
|
||||
return VHASH(key->device, key->vnode) % range;
|
||||
|
||||
#undef VHASH
|
||||
}
|
||||
|
||||
|
||||
#define FD_PATH_HASH_TABLE_SIZE 1024
|
||||
static hash_table* sFdPathsTable = NULL;
|
||||
|
||||
|
||||
bool
|
||||
init_fd_paths_hash_table()
|
||||
{
|
||||
struct fd_paths dummyFdPaths;
|
||||
sFdPathsTable = hash_init(FD_PATH_HASH_TABLE_SIZE,
|
||||
offset_of_member(dummyFdPaths, next), &fd_paths_compare,
|
||||
&fd_paths_hash);
|
||||
if (sFdPathsTable == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void
|
||||
dump_fd_paths_hash_table()
|
||||
{
|
||||
hash_iterator it;
|
||||
hash_rewind(sFdPathsTable, &it);
|
||||
dprintf("fd_paths hash table:\n");
|
||||
for (unsigned int i = 0; i < hash_count_elements(sFdPathsTable); i++) {
|
||||
fd_paths* fdPath = (fd_paths*)hash_next(sFdPathsTable, &it);
|
||||
dprintf("vnode: device %i, node %i\n", (int)fdPath->node->device,
|
||||
(int)fdPath->node->id);
|
||||
PathInfoList::Iterator pathIt(&fdPath->paths);
|
||||
for (PathInfo* info = pathIt.Next(); info != NULL;
|
||||
info = pathIt.Next()) {
|
||||
char path[B_PATH_NAME_LENGTH];
|
||||
vfs_entry_ref_to_path(fdPath->node->device, info->directory,
|
||||
info->filename, path, B_PATH_NAME_LENGTH);
|
||||
dprintf("\tentry: fd %p, dir %i, name %s, path %s\n",
|
||||
info->descriptor, (int)info->directory, info->filename, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static rw_lock sFdPathsLock = RW_LOCK_INITIALIZER("fd_path_lock");
|
||||
|
||||
|
||||
void
|
||||
read_lock_fd_paths()
|
||||
{
|
||||
rw_lock_read_lock(&sFdPathsLock);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_unlock_fd_paths()
|
||||
{
|
||||
rw_lock_read_unlock(&sFdPathsLock);
|
||||
}
|
||||
|
||||
|
||||
static fd_paths*
|
||||
lookup_fd_paths(vnode* node)
|
||||
{
|
||||
vnode_hash_key key;
|
||||
key.device = node->device;
|
||||
key.vnode = node->id;
|
||||
return (fd_paths*)hash_lookup(sFdPathsTable, &key);
|
||||
}
|
||||
|
||||
|
||||
fd_paths*
|
||||
lookup_fd_paths(dev_t mountID, ino_t vnodeID)
|
||||
{
|
||||
vnode_hash_key key;
|
||||
key.device = mountID;
|
||||
key.vnode = vnodeID;
|
||||
return (fd_paths*)hash_lookup(sFdPathsTable, &key);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
insert_path_info(vnode* node, PathInfo* _info)
|
||||
{
|
||||
WriteLocker locker(sFdPathsLock);
|
||||
|
||||
fd_paths* paths = lookup_fd_paths(node);
|
||||
if (paths == NULL) {
|
||||
paths = new(std::nothrow) fd_paths;
|
||||
if (paths == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
paths->node = node;
|
||||
if (hash_insert(sFdPathsTable, paths) != B_OK)
|
||||
delete paths;
|
||||
}
|
||||
|
||||
paths->paths.Add(_info);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
insert_fd_path(vnode* node, int fd, bool kernel, ino_t directory,
|
||||
const char* name)
|
||||
{
|
||||
if (S_ISREG(node->Type()) != true)
|
||||
return B_OK;
|
||||
|
||||
file_descriptor* descriptor = get_fd(get_current_io_context(kernel), fd);
|
||||
if (descriptor == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
PathInfo* info = new(std::nothrow) PathInfo;
|
||||
if (info == NULL) {
|
||||
put_fd(descriptor);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
info->SetTo(descriptor, directory, name);
|
||||
|
||||
status_t status = insert_path_info(descriptor->u.vnode, info);
|
||||
if (status != B_OK)
|
||||
free(info);
|
||||
|
||||
put_fd(descriptor);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
remove_fd_path(file_descriptor* descriptor)
|
||||
{
|
||||
if (S_ISREG(descriptor->u.vnode->Type()) != true)
|
||||
return B_OK;
|
||||
|
||||
WriteLocker locker(sFdPathsLock);
|
||||
|
||||
fd_paths* paths = lookup_fd_paths(descriptor->u.vnode);
|
||||
if (paths == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
PathInfoList::Iterator it(&paths->paths);
|
||||
for (PathInfo* info = it.Next(); info != NULL; info = it.Next()) {
|
||||
if (info->descriptor == descriptor) {
|
||||
paths->paths.Remove(info);
|
||||
delete info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (paths->paths.IsEmpty()) {
|
||||
// it was the last path remove the complete entry
|
||||
hash_remove(sFdPathsTable, paths);
|
||||
delete paths;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
move_fd_path(dev_t device, ino_t node, const char *fromName, ino_t newDirectory,
|
||||
const char* newName)
|
||||
{
|
||||
WriteLocker locker(sFdPathsLock);
|
||||
|
||||
fd_paths* paths = lookup_fd_paths(device, node);
|
||||
if (paths == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
PathInfoList::Iterator it(&paths->paths);
|
||||
for (PathInfo* info = it.Next(); info != NULL; info = it.Next()) {
|
||||
if (strncmp(info->filename, fromName, B_FILE_NAME_LENGTH) == 0) {
|
||||
info->directory = newDirectory;
|
||||
strlcpy(info->filename, newName, B_FILE_NAME_LENGTH);
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
55
src/system/kernel/fs/FDPath.h
Normal file
55
src/system/kernel/fs/FDPath.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2011 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler, haiku@clemens-zeidler.de
|
||||
*/
|
||||
#ifndef FD_PATH_H
|
||||
#define FD_PATH_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <fd.h>
|
||||
#include <khash.h>
|
||||
#include <util/SinglyLinkedList.h>
|
||||
|
||||
|
||||
class PathInfo : public SinglyLinkedListLinkImpl<PathInfo> {
|
||||
public:
|
||||
void SetTo(file_descriptor* fd, ino_t directory,
|
||||
const char* name);
|
||||
|
||||
file_descriptor* descriptor;
|
||||
ino_t directory;
|
||||
char filename[B_FILE_NAME_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
typedef SinglyLinkedList<PathInfo> PathInfoList;
|
||||
|
||||
|
||||
struct fd_paths {
|
||||
fd_paths* next;
|
||||
vnode* node;
|
||||
PathInfoList paths;
|
||||
};
|
||||
|
||||
|
||||
bool init_fd_paths_hash_table();
|
||||
void dump_fd_paths_hash_table();
|
||||
|
||||
void read_lock_fd_paths();
|
||||
void read_unlock_fd_paths();
|
||||
|
||||
//! lookup_fd_paths needs to be locked
|
||||
fd_paths* lookup_fd_paths(dev_t device, ino_t node);
|
||||
|
||||
status_t insert_fd_path(vnode* node, int fd, bool kernel,
|
||||
ino_t directory, const char* filename);
|
||||
status_t remove_fd_path(file_descriptor* descriptor);
|
||||
status_t move_fd_path(dev_t device, ino_t node, const char *fromName,
|
||||
ino_t newDirectory, const char* newName);
|
||||
|
||||
#endif // FD_PATH_H
|
@ -10,6 +10,7 @@ UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
|
||||
KernelMergeObject kernel_fs.o :
|
||||
EntryCache.cpp
|
||||
fd.cpp
|
||||
FDPath.cpp
|
||||
fifo.cpp
|
||||
KPath.cpp
|
||||
node_monitor.cpp
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <util/KMessage.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include "FDPath.h"
|
||||
#include "node_monitor_private.h"
|
||||
|
||||
|
||||
@ -689,6 +690,8 @@ NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory,
|
||||
dev_t nodeDevice = device;
|
||||
vfs_resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node);
|
||||
|
||||
move_fd_path(device, node, fromName, toDirectory, toName);
|
||||
|
||||
RecursiveLocker locker(fRecursiveLock);
|
||||
|
||||
// get the lists of all interested listeners
|
||||
@ -760,6 +763,17 @@ NodeMonitorService::NotifyStatChanged(dev_t device, ino_t node,
|
||||
message.AddInt64("node", node);
|
||||
message.AddInt32("fields", statFields); // Haiku only
|
||||
|
||||
read_lock_fd_paths();
|
||||
fd_paths* fsPaths = lookup_fd_paths(device, node);
|
||||
if (fsPaths != NULL) {
|
||||
PathInfoList::Iterator it(&fsPaths->paths);
|
||||
for (PathInfo* info = it.Next(); info != NULL; info = it.Next()) {
|
||||
message.AddInt64("directory", info->directory);
|
||||
message.AddString("name", info->filename);
|
||||
}
|
||||
}
|
||||
read_unlock_fd_paths();
|
||||
|
||||
return _SendNotificationMessage(message, interestedListeners,
|
||||
interestedListenerCount);
|
||||
}
|
||||
@ -807,6 +821,17 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t node,
|
||||
message.AddString("attr", attribute);
|
||||
message.AddInt32("cause", cause); // Haiku only
|
||||
|
||||
read_lock_fd_paths();
|
||||
fd_paths* fsPaths = lookup_fd_paths(device, node);
|
||||
if (fsPaths != NULL) {
|
||||
PathInfoList::Iterator it(&fsPaths->paths);
|
||||
for (PathInfo* info = it.Next(); info != NULL; info = it.Next()) {
|
||||
message.AddInt64("directory", info->directory);
|
||||
message.AddString("name", info->filename);
|
||||
}
|
||||
}
|
||||
read_unlock_fd_paths();
|
||||
|
||||
return _SendNotificationMessage(message, interestedListeners,
|
||||
interestedListenerCount);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <vm/VMCache.h>
|
||||
|
||||
#include "EntryCache.h"
|
||||
#include "FDPath.h"
|
||||
#include "fifo.h"
|
||||
#include "IORequest.h"
|
||||
#include "unused_vnodes.h"
|
||||
@ -5107,6 +5108,9 @@ vfs_init(kernel_args* args)
|
||||
{
|
||||
vnode::StaticInit();
|
||||
|
||||
if (init_fd_paths_hash_table() == false)
|
||||
panic("vfs_init: error creating vnode to paths hash table\n");
|
||||
|
||||
struct vnode dummyVnode;
|
||||
sVnodeTable = hash_init(VNODE_HASH_TABLE_SIZE,
|
||||
offset_of_member(dummyVnode, next), &vnode_compare, &vnode_hash);
|
||||
@ -5250,6 +5254,8 @@ create_vnode(struct vnode* directory, const char* name, int openMode,
|
||||
if (fd >= 0)
|
||||
putter.Detach();
|
||||
|
||||
insert_fd_path(vnode, fd, kernel, directory->id, name);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -5282,8 +5288,10 @@ create_vnode(struct vnode* directory, const char* name, int openMode,
|
||||
}
|
||||
|
||||
int fd = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel);
|
||||
if (fd >= 0)
|
||||
if (fd >= 0) {
|
||||
insert_fd_path(vnode, fd, kernel, directory->id, name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
status = fd;
|
||||
|
||||
@ -5423,10 +5431,33 @@ file_open_entry_ref(dev_t mountID, ino_t directoryID, const char* name,
|
||||
} else
|
||||
put_vnode(vnode);
|
||||
|
||||
insert_fd_path(vnode, newFD, kernel, directoryID, name);
|
||||
|
||||
return newFD;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
leaf(const char* path)
|
||||
{
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
|
||||
int32 pathLength = strlen(path);
|
||||
if (pathLength > B_FILE_NAME_LENGTH)
|
||||
return NULL;
|
||||
// only "/" has trailing slashes -- then we have to return the complete
|
||||
// buffer, as we have to do in case there are no slashes at all
|
||||
if (pathLength != 1 || path[0] != '/') {
|
||||
for (int32 i = pathLength - 1; i >= 0; i--) {
|
||||
if (path[i] == '/')
|
||||
return path + i + 1;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
file_open(int fd, char* path, int openMode, bool kernel)
|
||||
{
|
||||
@ -5435,6 +5466,8 @@ file_open(int fd, char* path, int openMode, bool kernel)
|
||||
FUNCTION(("file_open: fd: %d, entry path = '%s', omode %d, kernel %d\n",
|
||||
fd, path, openMode, kernel));
|
||||
|
||||
// extract the leaf here because path get screed later
|
||||
const char* name = leaf(path);
|
||||
// get the vnode matching the vnode + path combination
|
||||
struct vnode* vnode;
|
||||
ino_t parentID;
|
||||
@ -5457,6 +5490,8 @@ file_open(int fd, char* path, int openMode, bool kernel)
|
||||
} else
|
||||
put_vnode(vnode);
|
||||
|
||||
insert_fd_path(vnode, newFD, kernel, parentID, name);
|
||||
|
||||
return newFD;
|
||||
}
|
||||
|
||||
@ -5490,6 +5525,9 @@ file_free_fd(struct file_descriptor* descriptor)
|
||||
|
||||
if (vnode != NULL) {
|
||||
FS_CALL(vnode, free_cookie, descriptor->cookie);
|
||||
|
||||
remove_fd_path(descriptor);
|
||||
|
||||
put_vnode(vnode);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user