nfs4: Implement node monitoring
This commit is contained in:
@@ -175,7 +175,77 @@ DirectoryCache::Revalidate()
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache;
|
||||
oldSnapshot->AcquireReference();
|
||||
|
||||
Trash();
|
||||
return B_ERROR;
|
||||
|
||||
DirectoryCacheSnapshot* newSnapshot;
|
||||
status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange);
|
||||
if (result != B_OK) {
|
||||
oldSnapshot->ReleaseReference();
|
||||
return B_OK;
|
||||
}
|
||||
newSnapshot->AcquireReference();
|
||||
|
||||
SetSnapshot(newSnapshot);
|
||||
fExpireTime = system_time() + kExpirationTime;
|
||||
fTrashed = false;
|
||||
|
||||
NotifyChanges(oldSnapshot, newSnapshot);
|
||||
oldSnapshot->ReleaseReference();
|
||||
newSnapshot->ReleaseReference();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
|
||||
DirectoryCacheSnapshot* newSnapshot)
|
||||
{
|
||||
MutexLocker _(newSnapshot->fLock);
|
||||
|
||||
SinglyLinkedList<NameCacheEntry>::Iterator oldIt
|
||||
= oldSnapshot->fEntries.GetIterator();
|
||||
NameCacheEntry* oldCurrent;
|
||||
|
||||
SinglyLinkedList<NameCacheEntry>::Iterator newIt
|
||||
= newSnapshot->fEntries.GetIterator();
|
||||
NameCacheEntry* newCurrent = newIt.Next();
|
||||
while (newCurrent != NULL) {
|
||||
oldIt = oldSnapshot->fEntries.GetIterator();
|
||||
oldCurrent = oldIt.Next();
|
||||
|
||||
bool found = false;
|
||||
NameCacheEntry* prev = NULL;
|
||||
while (oldCurrent != NULL) {
|
||||
if (oldCurrent->fNode == newCurrent->fNode &&
|
||||
strcmp(oldCurrent->fName, newCurrent->fName) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = oldCurrent;
|
||||
oldCurrent = oldIt.Next();
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
notify_entry_created(fInode->GetFileSystem()->DevId(),
|
||||
fInode->ID(), newCurrent->fName, newCurrent->fNode);
|
||||
} else
|
||||
oldSnapshot->fEntries.Remove(prev, oldCurrent);
|
||||
|
||||
newCurrent = newIt.Next();
|
||||
}
|
||||
|
||||
oldIt = oldSnapshot->fEntries.GetIterator();
|
||||
oldCurrent = oldIt.Next();
|
||||
|
||||
while (oldCurrent != NULL) {
|
||||
notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
|
||||
oldCurrent->fName, oldCurrent->fNode);
|
||||
oldCurrent = oldIt.Next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,10 @@ public:
|
||||
inline time_t ExpireTime();
|
||||
|
||||
static const bigtime_t kExpirationTime = 15000000;
|
||||
protected:
|
||||
void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
|
||||
DirectoryCacheSnapshot* newSnapshot);
|
||||
|
||||
private:
|
||||
SinglyLinkedList<NameCacheEntry> fNameCache;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
Inode::Inode()
|
||||
:
|
||||
fMetaCache(this),
|
||||
fCache(NULL),
|
||||
fDelegation(NULL),
|
||||
fFileCache(NULL),
|
||||
@@ -248,6 +249,8 @@ Inode::Link(Inode* dir, const char* name)
|
||||
dir->fCache->Unlock();
|
||||
}
|
||||
|
||||
notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -256,7 +259,8 @@ status_t
|
||||
Inode::Remove(const char* name, FileType type)
|
||||
{
|
||||
ChangeInfo changeInfo;
|
||||
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo);
|
||||
uint64 fileID;
|
||||
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
@@ -272,6 +276,9 @@ Inode::Remove(const char* name, FileType type)
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
notify_entry_removed(fFileSystem->DevId(), ID(), name,
|
||||
FileIdToInoT(fileID));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -311,6 +318,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName)
|
||||
to->fCache->Unlock();
|
||||
}
|
||||
|
||||
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
|
||||
to->ID(), toName, FileIdToInoT(fileID));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -349,6 +359,9 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type)
|
||||
fCache->Unlock();
|
||||
}
|
||||
|
||||
notify_entry_created(fFileSystem->DevId(), ID(), name,
|
||||
FileIdToInoT(fileID));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,10 @@ public:
|
||||
const struct flock* lock);
|
||||
status_t ReleaseAllLocks(OpenFileCookie* cookie);
|
||||
|
||||
status_t GetDirSnapshot(DirectoryCacheSnapshot**
|
||||
_snapshot, OpenDirCookie* cookie,
|
||||
uint64* _change);
|
||||
|
||||
protected:
|
||||
Inode();
|
||||
|
||||
@@ -105,9 +109,6 @@ protected:
|
||||
uint32 size);
|
||||
status_t FillDirEntry(struct dirent* de, ino_t id,
|
||||
const char* name, uint32 pos, uint32 size);
|
||||
status_t GetDirSnapshot(DirectoryCacheSnapshot**
|
||||
_snapshot, OpenDirCookie* cookie,
|
||||
uint64* _change);
|
||||
|
||||
status_t ChildAdded(const char* name, uint64 fileID,
|
||||
const FileHandle& fileHandle);
|
||||
|
||||
@@ -90,6 +90,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
fFileSystem->AddOpenFile(state);
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
notify_entry_created(fFileSystem->DevId(), ID(), name, *id);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,17 @@
|
||||
|
||||
#include "MetadataCache.h"
|
||||
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
MetadataCache::MetadataCache()
|
||||
#include "Inode.h"
|
||||
|
||||
|
||||
MetadataCache::MetadataCache(Inode* inode)
|
||||
:
|
||||
fExpire(0),
|
||||
fForceValid(false)
|
||||
fForceValid(false),
|
||||
fInode(inode),
|
||||
fInited(false)
|
||||
{
|
||||
mutex_init(&fLock, NULL);
|
||||
}
|
||||
@@ -52,8 +58,12 @@ void
|
||||
MetadataCache::SetStat(const struct stat& st)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
if (fInited)
|
||||
NotifyChanges(&fStatCache, &st);
|
||||
|
||||
fStatCache = st;
|
||||
fExpire = time(NULL) + kExpirationTime;
|
||||
fInited = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,3 +131,35 @@ MetadataCache::UnlockValid()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MetadataCache::NotifyChanges(const struct stat* oldStat,
|
||||
const struct stat* newStat)
|
||||
{
|
||||
uint32 flags = 0;
|
||||
if (oldStat->st_size != newStat->st_size)
|
||||
flags |= B_STAT_SIZE;
|
||||
if (oldStat->st_mode != newStat->st_mode)
|
||||
flags |= B_STAT_MODE;
|
||||
if (oldStat->st_uid != newStat->st_uid)
|
||||
flags |= B_STAT_UID;
|
||||
if (oldStat->st_gid != newStat->st_gid)
|
||||
flags |= B_STAT_GID;
|
||||
|
||||
if (memcmp(&oldStat->st_atim, &newStat->st_atim,
|
||||
sizeof(struct timespec) == 0))
|
||||
flags |= B_STAT_ACCESS_TIME;
|
||||
|
||||
if (memcmp(&oldStat->st_ctim, &newStat->st_ctim,
|
||||
sizeof(struct timespec) == 0))
|
||||
flags |= B_STAT_CHANGE_TIME;
|
||||
|
||||
if (memcmp(&oldStat->st_crtim, &newStat->st_crtim,
|
||||
sizeof(struct timespec) == 0))
|
||||
flags |= B_STAT_CREATION_TIME;
|
||||
|
||||
if (memcmp(&oldStat->st_mtim, &newStat->st_mtim,
|
||||
sizeof(struct timespec) == 0))
|
||||
flags |= B_STAT_MODIFICATION_TIME;
|
||||
|
||||
notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
#define METADATACACHE_H
|
||||
|
||||
|
||||
#include <fs_interface.h>
|
||||
#include <lock.h>
|
||||
#include <SupportDefs.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/AVLTreeMap.h>
|
||||
|
||||
|
||||
class Inode;
|
||||
|
||||
struct AccessEntry {
|
||||
time_t fExpire;
|
||||
uint32 fAllowed;
|
||||
@@ -22,7 +25,7 @@ struct AccessEntry {
|
||||
|
||||
class MetadataCache {
|
||||
public:
|
||||
MetadataCache();
|
||||
MetadataCache(Inode* inode);
|
||||
~MetadataCache();
|
||||
|
||||
status_t GetStat(struct stat* st);
|
||||
@@ -41,11 +44,19 @@ public:
|
||||
inline void Invalidate();
|
||||
|
||||
static const time_t kExpirationTime = 60;
|
||||
|
||||
protected:
|
||||
void NotifyChanges(const struct stat* oldStat,
|
||||
const struct stat* newStat);
|
||||
|
||||
private:
|
||||
struct stat fStatCache;
|
||||
time_t fExpire;
|
||||
bool fForceValid;
|
||||
|
||||
Inode* fInode;
|
||||
bool fInited;
|
||||
|
||||
AVLTreeMap<uid_t, AccessEntry> fAccessCache;
|
||||
|
||||
mutex fLock;
|
||||
|
||||
@@ -736,7 +736,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo)
|
||||
NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
|
||||
uint64* fileID)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
@@ -755,6 +756,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo)
|
||||
req.Nverify(&attr, 1);
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
|
||||
Attribute idAttr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
|
||||
|
||||
req.Remove(name);
|
||||
|
||||
status_t result = request.Send();
|
||||
@@ -785,6 +790,18 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo)
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (count == 0)
|
||||
*fileID = fFileSystem->AllocFileId();
|
||||
else
|
||||
*fileID = values[0].fData.fValue64;
|
||||
delete[] values;
|
||||
|
||||
return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
|
||||
changeInfo->fAtomic);
|
||||
} while (true);
|
||||
@@ -831,8 +848,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
|
||||
return result;
|
||||
}
|
||||
|
||||
result = reply.ReadDir(dirCookie, dirCookieVerf, dirents,
|
||||
count, eof);
|
||||
result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof);
|
||||
if (result != B_OK) {
|
||||
delete[] before;
|
||||
return result;
|
||||
|
||||
@@ -62,7 +62,7 @@ protected:
|
||||
int mode, FileType type, ChangeInfo* changeInfo,
|
||||
uint64* fileID, FileHandle* handle);
|
||||
status_t RemoveObject(const char* name, FileType type,
|
||||
ChangeInfo* changeInfo);
|
||||
ChangeInfo* changeInfo, uint64* fileID);
|
||||
|
||||
status_t ReadDirOnce(DirEntry** dirents, uint32* count,
|
||||
OpenDirCookie* cookie, bool* eof, uint64* change,
|
||||
|
||||
Reference in New Issue
Block a user