nfs4: Implement node monitoring

This commit is contained in:
Pawel Dziepak
2012-08-08 03:48:35 +02:00
parent d8e2263f3b
commit 3ae5e813c4
9 changed files with 171 additions and 12 deletions
@@ -175,7 +175,77 @@ DirectoryCache::Revalidate()
return B_OK; return B_OK;
} }
DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache;
oldSnapshot->AcquireReference();
Trash(); 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(); inline time_t ExpireTime();
static const bigtime_t kExpirationTime = 15000000; static const bigtime_t kExpirationTime = 15000000;
protected:
void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
DirectoryCacheSnapshot* newSnapshot);
private: private:
SinglyLinkedList<NameCacheEntry> fNameCache; SinglyLinkedList<NameCacheEntry> fNameCache;
+14 -1
View File
@@ -22,6 +22,7 @@
Inode::Inode() Inode::Inode()
: :
fMetaCache(this),
fCache(NULL), fCache(NULL),
fDelegation(NULL), fDelegation(NULL),
fFileCache(NULL), fFileCache(NULL),
@@ -248,6 +249,8 @@ Inode::Link(Inode* dir, const char* name)
dir->fCache->Unlock(); dir->fCache->Unlock();
} }
notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID());
return B_OK; return B_OK;
} }
@@ -256,7 +259,8 @@ status_t
Inode::Remove(const char* name, FileType type) Inode::Remove(const char* name, FileType type)
{ {
ChangeInfo changeInfo; 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) if (result != B_OK)
return result; return result;
@@ -272,6 +276,9 @@ Inode::Remove(const char* name, FileType type)
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
notify_entry_removed(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
return B_OK; return B_OK;
} }
@@ -311,6 +318,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName)
to->fCache->Unlock(); to->fCache->Unlock();
} }
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
to->ID(), toName, FileIdToInoT(fileID));
return B_OK; return B_OK;
} }
@@ -349,6 +359,9 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type)
fCache->Unlock(); fCache->Unlock();
} }
notify_entry_created(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
return B_OK; return B_OK;
} }
+4 -3
View File
@@ -90,6 +90,10 @@ public:
const struct flock* lock); const struct flock* lock);
status_t ReleaseAllLocks(OpenFileCookie* cookie); status_t ReleaseAllLocks(OpenFileCookie* cookie);
status_t GetDirSnapshot(DirectoryCacheSnapshot**
_snapshot, OpenDirCookie* cookie,
uint64* _change);
protected: protected:
Inode(); Inode();
@@ -105,9 +109,6 @@ protected:
uint32 size); uint32 size);
status_t FillDirEntry(struct dirent* de, ino_t id, status_t FillDirEntry(struct dirent* de, ino_t id,
const char* name, uint32 pos, uint32 size); const char* name, uint32 pos, uint32 size);
status_t GetDirSnapshot(DirectoryCacheSnapshot**
_snapshot, OpenDirCookie* cookie,
uint64* _change);
status_t ChildAdded(const char* name, uint64 fileID, status_t ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle); const FileHandle& fileHandle);
@@ -90,6 +90,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
fFileSystem->AddOpenFile(state); fFileSystem->AddOpenFile(state);
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
notify_entry_created(fFileSystem->DevId(), ID(), name, *id);
return B_OK; return B_OK;
} }
@@ -9,11 +9,17 @@
#include "MetadataCache.h" #include "MetadataCache.h"
#include <NodeMonitor.h>
MetadataCache::MetadataCache() #include "Inode.h"
MetadataCache::MetadataCache(Inode* inode)
: :
fExpire(0), fExpire(0),
fForceValid(false) fForceValid(false),
fInode(inode),
fInited(false)
{ {
mutex_init(&fLock, NULL); mutex_init(&fLock, NULL);
} }
@@ -52,8 +58,12 @@ void
MetadataCache::SetStat(const struct stat& st) MetadataCache::SetStat(const struct stat& st)
{ {
MutexLocker _(fLock); MutexLocker _(fLock);
if (fInited)
NotifyChanges(&fStatCache, &st);
fStatCache = st; fStatCache = st;
fExpire = time(NULL) + kExpirationTime; 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 #define METADATACACHE_H
#include <fs_interface.h>
#include <lock.h> #include <lock.h>
#include <SupportDefs.h> #include <SupportDefs.h>
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include <util/AVLTreeMap.h> #include <util/AVLTreeMap.h>
class Inode;
struct AccessEntry { struct AccessEntry {
time_t fExpire; time_t fExpire;
uint32 fAllowed; uint32 fAllowed;
@@ -22,7 +25,7 @@ struct AccessEntry {
class MetadataCache { class MetadataCache {
public: public:
MetadataCache(); MetadataCache(Inode* inode);
~MetadataCache(); ~MetadataCache();
status_t GetStat(struct stat* st); status_t GetStat(struct stat* st);
@@ -41,11 +44,19 @@ public:
inline void Invalidate(); inline void Invalidate();
static const time_t kExpirationTime = 60; static const time_t kExpirationTime = 60;
protected:
void NotifyChanges(const struct stat* oldStat,
const struct stat* newStat);
private: private:
struct stat fStatCache; struct stat fStatCache;
time_t fExpire; time_t fExpire;
bool fForceValid; bool fForceValid;
Inode* fInode;
bool fInited;
AVLTreeMap<uid_t, AccessEntry> fAccessCache; AVLTreeMap<uid_t, AccessEntry> fAccessCache;
mutex fLock; mutex fLock;
@@ -736,7 +736,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
status_t status_t
NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
uint64* fileID)
{ {
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
@@ -755,6 +756,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo)
req.Nverify(&attr, 1); req.Nverify(&attr, 1);
req.PutFH(fInfo.fHandle); req.PutFH(fInfo.fHandle);
Attribute idAttr[] = { FATTR4_FILEID };
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
req.Remove(name); req.Remove(name);
status_t result = request.Send(); status_t result = request.Send();
@@ -785,6 +790,18 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo)
reply.PutFH(); 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, return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
changeInfo->fAtomic); changeInfo->fAtomic);
} while (true); } while (true);
@@ -831,8 +848,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
return result; return result;
} }
result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof);
count, eof);
if (result != B_OK) { if (result != B_OK) {
delete[] before; delete[] before;
return result; return result;
@@ -62,7 +62,7 @@ protected:
int mode, FileType type, ChangeInfo* changeInfo, int mode, FileType type, ChangeInfo* changeInfo,
uint64* fileID, FileHandle* handle); uint64* fileID, FileHandle* handle);
status_t RemoveObject(const char* name, FileType type, status_t RemoveObject(const char* name, FileType type,
ChangeInfo* changeInfo); ChangeInfo* changeInfo, uint64* fileID);
status_t ReadDirOnce(DirEntry** dirents, uint32* count, status_t ReadDirOnce(DirEntry** dirents, uint32* count,
OpenDirCookie* cookie, bool* eof, uint64* change, OpenDirCookie* cookie, bool* eof, uint64* change,