hrev43680 adds 2 changesets to branch 'master' old head: c7413cf90cd13672348a8c1421c2f8d11de95798 new head: d3ff06683af390a4c2e83b69177e0a2eb76679bc ---------------------------------------------------------------------------- 610ef6c: 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 d3ff066: Use new node monitor fields in the index_server. * remove unnecessary modified query hack [ czeidler <haiku@xxxxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 10 files changed, 404 insertions(+), 165 deletions(-) src/servers/index/Jamfile | 1 - src/servers/index/ModifiedNotifications.cpp | 86 -------- src/servers/index/ModifiedNotifications.h | 44 ---- src/servers/index/VolumeWatcher.cpp | 69 ++++--- src/servers/index/VolumeWatcher.h | 5 +- src/system/kernel/fs/FDPath.cpp | 243 +++++++++++++++++++++++ src/system/kernel/fs/FDPath.h | 55 +++++ src/system/kernel/fs/Jamfile | 1 + src/system/kernel/fs/node_monitor.cpp | 25 +++ src/system/kernel/fs/vfs.cpp | 40 ++++- ############################################################################ Commit: 610ef6c00781522022455c0cbf34495420b2db1d URL: http://cgit.haiku-os.org/haiku/commit/?id=610ef6c Author: czeidler <haiku@xxxxxxxxxxxxxxxxxx> Date: Sun Jan 22 04:34:17 2012 UTC 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 ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/FDPath.cpp b/src/system/kernel/fs/FDPath.cpp new file mode 100644 index 0000000..a540084 --- /dev/null +++ b/src/system/kernel/fs/FDPath.cpp @@ -0,0 +1,243 @@ +/* + * Copyright 2011 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Clemens Zeidler, haiku@xxxxxxxxxxxxxxxxxx + */ + + +#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; +} diff --git a/src/system/kernel/fs/FDPath.h b/src/system/kernel/fs/FDPath.h new file mode 100644 index 0000000..0c55388 --- /dev/null +++ b/src/system/kernel/fs/FDPath.h @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Clemens Zeidler, haiku@xxxxxxxxxxxxxxxxxx + */ +#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 diff --git a/src/system/kernel/fs/Jamfile b/src/system/kernel/fs/Jamfile index d2d0f84..6187198 100644 --- a/src/system/kernel/fs/Jamfile +++ b/src/system/kernel/fs/Jamfile @@ -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 diff --git a/src/system/kernel/fs/node_monitor.cpp b/src/system/kernel/fs/node_monitor.cpp index 601fd6c..85f63ec 100644 --- a/src/system/kernel/fs/node_monitor.cpp +++ b/src/system/kernel/fs/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); } diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index c44fba3..995f24b 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -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); } } ############################################################################ Revision: hrev43680 Commit: d3ff06683af390a4c2e83b69177e0a2eb76679bc URL: http://cgit.haiku-os.org/haiku/commit/?id=d3ff066 Author: czeidler <haiku@xxxxxxxxxxxxxxxxxx> Date: Sun Jan 22 04:51:46 2012 UTC Use new node monitor fields in the index_server. * remove unnecessary modified query hack ---------------------------------------------------------------------------- diff --git a/src/servers/index/Jamfile b/src/servers/index/Jamfile index ded7a9a..bbe6811 100644 --- a/src/servers/index/Jamfile +++ b/src/servers/index/Jamfile @@ -10,7 +10,6 @@ Server index_server : main.cpp IndexServer.cpp IndexServerAddOn.cpp - ModifiedNotifications.cpp VolumeWatcher.cpp # storage diff --git a/src/servers/index/ModifiedNotifications.cpp b/src/servers/index/ModifiedNotifications.cpp deleted file mode 100644 index a241209..0000000 --- a/src/servers/index/ModifiedNotifications.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2010, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler <haiku@xxxxxxxxxxxxxxxxxx> - */ - -#include "ModifiedNotifications.h" - -#include "fs_query.h" - -#include <MessengerPrivate.h> -#include <syscalls.h> - -#include "query_private.h" - - -NotifyAllQuery::NotifyAllQuery() - : - fQueryFd(-1) -{ - -} - - -NotifyAllQuery::~NotifyAllQuery() -{ - StopWatching(); -} - - -status_t -NotifyAllQuery::StartWatching(const BVolume& volume, const char* query, - const BMessenger& target) -{ - if (fQueryFd >= 0) - return B_NOT_ALLOWED; - - BMessenger::Private messengerPrivate(const_cast<BMessenger&>(target)); - port_id port = messengerPrivate.Port(); - long token = (messengerPrivate.IsPreferredTarget() ? -1 - : messengerPrivate.Token()); - - fQueryFd = _kern_open_query(volume.Device(), query, strlen(query), - B_LIVE_QUERY | B_ATTR_CHANGE_NOTIFICATION, port, token); - if (fQueryFd < 0) - return fQueryFd; - return B_OK; -} - - -status_t -NotifyAllQuery::StopWatching() -{ - status_t error = B_OK; - if (fQueryFd >= 0) { - error = _kern_close(fQueryFd); - fQueryFd = -1; - } - return error; -} - - -ModfiedNotifications::~ModfiedNotifications() -{ - StopWatching(); -} - - -status_t -ModfiedNotifications::StartWatching(const BVolume& volume, time_t startTime, - const BMessenger& target) -{ - BString string = "(last_modified>="; - string << startTime; - string << ")"; - return fQuery.StartWatching(volume, string.String(), target); -} - - -status_t -ModfiedNotifications::StopWatching() -{ - return fQuery.StopWatching(); -} diff --git a/src/servers/index/ModifiedNotifications.h b/src/servers/index/ModifiedNotifications.h deleted file mode 100644 index 50cd1b2..0000000 --- a/src/servers/index/ModifiedNotifications.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2010, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler <haiku@xxxxxxxxxxxxxxxxxx> - */ -#ifndef MODIFIED_NOTIFICATIONS_H -#define MODIFIED_NOTIFICATIONS_H - - -#include <String.h> -#include <Volume.h> -#include <Messenger.h> - - -class NotifyAllQuery { -public: - NotifyAllQuery(); - ~NotifyAllQuery(); - - status_t StartWatching(const BVolume& volume, - const char* query, - const BMessenger& target); - status_t StopWatching(); -private: - int fQueryFd; -}; - - -class ModfiedNotifications { -public: - ~ModfiedNotifications(); - - status_t StartWatching(const BVolume& volume, - time_t startTime, const BMessenger& target); - status_t StopWatching(); - -private: - NotifyAllQuery fQuery; -}; - - -#endif // MODIFIED_NOTIFICATIONS_H diff --git a/src/servers/index/VolumeWatcher.cpp b/src/servers/index/VolumeWatcher.cpp index 4192c82..a945e17 100644 --- a/src/servers/index/VolumeWatcher.cpp +++ b/src/servers/index/VolumeWatcher.cpp @@ -74,6 +74,44 @@ WatchNameHandler::StatChanged(ino_t node, dev_t device, int32 statFields) } +void +WatchNameHandler::MessageReceived(BMessage* msg) +{ + if (msg->what == B_NODE_MONITOR) { + int32 opcode; + if (msg->FindInt32("opcode", &opcode) == B_OK) { + switch (opcode) { + case B_STAT_CHANGED: { + BString name; + entry_ref ref; + ino_t node; + int32 statFields; + msg->FindInt32("fields", &statFields); + if ((statFields & B_STAT_MODIFICATION_TIME) == 0) + break; + msg->FindInt32("device", &ref.device); + msg->FindInt64("node", &node); + msg->FindInt64("directory", &ref.directory); + msg->FindString("name", &name); + + ref.set_name(name); + + BPath path(&ref); + printf("stat changed node %i name %s %s\n", (int)node, + name.String(), path.Path()); + + fVolumeWatcher->fModifiedList.CurrentList()->push_back(ref); + fVolumeWatcher->_NewEntriesArrived(); + + break; + } + } + } + } + NodeMonitorHandler::MessageReceived(msg); +} + + AnalyserDispatcher::AnalyserDispatcher(const char* name) : BLooper(name, B_LOW_PRIORITY), @@ -408,33 +446,6 @@ VolumeWatcher::~VolumeWatcher() } -void -VolumeWatcher::MessageReceived(BMessage *message) -{ - int32 opcode; - switch (message->what) { - case B_QUERY_UPDATE: - message->FindInt32("opcode", &opcode); - if (opcode == B_ATTR_CHANGED || opcode == B_ENTRY_CREATED) { - const char *name; - ino_t directory; - dev_t device; - if ((message->FindString("name", &name) != B_OK) || - (message->FindInt64("directory", &directory) != B_OK) || - (message->FindInt32("device", &device) != B_OK)) - break; - entry_ref ref(device, directory, name); - fModifiedList.CurrentList()->push_back(ref); - _NewEntriesArrived(); - } - break; - - default: - BLooper::MessageReceived(message); - } -} - - bool VolumeWatcher::StartWatching() { @@ -442,9 +453,7 @@ VolumeWatcher::StartWatching() watch_volume(fVolume.Device(), B_WATCH_NAME | B_WATCH_STAT, &fWatchNameHandler); - if (fModfiedNotifications.StartWatching(fVolume.Device(), real_time_clock(), - this) != B_OK) - return false; + // set the time after start watching to not miss anything fVolumeWorker->SetWatchingStart(real_time_clock_usecs()); diff --git a/src/servers/index/VolumeWatcher.h b/src/servers/index/VolumeWatcher.h index dc5e7e1..7131ae3 100644 --- a/src/servers/index/VolumeWatcher.h +++ b/src/servers/index/VolumeWatcher.h @@ -21,7 +21,6 @@ #include "AnalyserDispatcher.h" #include "CatchUpManager.h" #include "IndexServerAddOn.h" -#include "ModifiedNotifications.h" class VolumeWatcher; @@ -41,6 +40,8 @@ public: ino_t node, dev_t nodeDevice); void StatChanged(ino_t node, dev_t device, int32 statFields); + + void MessageReceived(BMessage* msg); private: VolumeWatcher* fVolumeWatcher; }; @@ -127,7 +128,6 @@ public: VolumeWatcher(const BVolume& volume); ~VolumeWatcher(); - void MessageReceived(BMessage *message); bool StartWatching(); void Stop(); @@ -157,7 +157,6 @@ private: VolumeWorker* fVolumeWorker; CatchUpManager fCatchUpManager; - ModfiedNotifications fModfiedNotifications; };