nfs4: Add directory and name basic implementation

This commit is contained in:
Pawel Dziepak
2012-07-19 01:54:44 +02:00
parent 6fcc3500cf
commit 75fe7b90bb
9 changed files with 537 additions and 4 deletions
@@ -0,0 +1,113 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#include "CacheRevalidator.h"
#include <fs_cache.h>
#include "NFS4Defs.h"
CacheRevalidator::CacheRevalidator()
:
fThreadCancel(false),
fWaitCancel(create_sem(0, NULL))
{
mutex_init(&fDirectoryCachesLock, NULL);
_StartRevalidator();
}
CacheRevalidator::~CacheRevalidator()
{
fThreadCancel = true;
release_sem(fWaitCancel);
status_t result;
wait_for_thread(fThread, &result);
delete_sem(fThreadCancel);
mutex_destroy(&fDirectoryCachesLock);
}
status_t
CacheRevalidator::_StartRevalidator()
{
fThreadCancel = false;
fThread = spawn_kernel_thread(&CacheRevalidator::_DirectoryRevalidatorStart,
"NFSv4 Cache Revalidator", B_NORMAL_PRIORITY, this);
if (fThread < B_OK)
return fThread;
status_t result = resume_thread(fThread);
if (result != B_OK) {
kill_thread(fThread);
return result;
}
return B_OK;
}
status_t
CacheRevalidator::_DirectoryRevalidatorStart(void* object)
{
CacheRevalidator* revalidator = reinterpret_cast<CacheRevalidator*>(object);
revalidator->_DirectoryCacheRevalidator();
return B_OK;
}
void
CacheRevalidator::_DirectoryCacheRevalidator()
{
while (!fThreadCancel) {
MutexLocker locker(fDirectoryCachesLock);
DirectoryCache* current = fDirectoryCaches.Head();
if (current == NULL) {
locker.Unlock();
status_t result = acquire_sem_etc(fWaitCancel, 1,
B_RELATIVE_TIMEOUT, DirectoryCache::kExpirationTime);
if (result != B_TIMED_OUT) {
release_sem(fWaitCancel);
return;
}
continue;
}
current->Lock();
if (current->ExpireTime() > system_time()) {
current->Unlock();
locker.Unlock();
status_t result = acquire_sem_etc(fWaitCancel, 1,
B_ABSOLUTE_TIMEOUT, current->ExpireTime());
if (result != B_TIMED_OUT) {
release_sem(fWaitCancel);
return;
}
continue;
}
fDirectoryCaches.RemoveHead();
if (current->Revalidate() == B_OK)
AddDirectory(current);
locker.Unlock();
current->Unlock();
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef CACHEREVALIDATOR_H
#define CACHEREVALIDATOR_H
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedQueue.h>
#include "DirectoryCache.h"
class CacheRevalidator {
public:
CacheRevalidator();
~CacheRevalidator();
inline void Lock();
inline void Unlock();
inline void AddDirectory(DirectoryCache* cache);
inline void RemoveDirectory(DirectoryCache* cache);
private:
void _DirectoryCacheRevalidator();
static status_t _DirectoryRevalidatorStart(void* object);
status_t _StartRevalidator();
thread_id fThread;
bool fThreadCancel;
sem_id fWaitCancel;
DoublyLinkedQueue<DirectoryCache> fDirectoryCaches;
mutex fDirectoryCachesLock;
};
inline void
CacheRevalidator::Lock()
{
mutex_lock(&fDirectoryCachesLock);
}
inline void
CacheRevalidator::Unlock()
{
mutex_unlock(&fDirectoryCachesLock);
}
inline void
CacheRevalidator::AddDirectory(DirectoryCache* cache)
{
fDirectoryCaches.Add(cache);
}
inline void
CacheRevalidator::RemoveDirectory(DirectoryCache* cache)
{
fDirectoryCaches.Remove(cache);
}
#endif // CACHEREVALIDATOR_H
@@ -0,0 +1,112 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#include "DirectoryCache.h"
#include <fs_cache.h>
#include "Inode.h"
DirectoryCache::DirectoryCache(Inode* inode)
:
fInode(inode),
fTrashed(true)
{
mutex_init(&fLock, NULL);
}
DirectoryCache::~DirectoryCache()
{
mutex_destroy(&fLock);
}
void
DirectoryCache::ResetAndLock()
{
mutex_lock(&fLock);
Trash();
fExpireTime = system_time() + kExpirationTime;
fTrashed = false;
}
void
DirectoryCache::Trash()
{
while (!fNameCache.IsEmpty()) {
NameCacheEntry* current = fNameCache.RemoveHead();
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
current->fName);
free(const_cast<char*>(current->fName));
delete current;
}
fTrashed = true;
}
status_t
DirectoryCache::AddEntry(const char* name, ino_t node)
{
NameCacheEntry* entry = new(std::nothrow) NameCacheEntry;
if (entry == NULL)
return B_NO_MEMORY;
entry->fName = strdup(name);
if (entry->fName == NULL) {
delete entry;
return B_NO_MEMORY;
}
entry->fNode = node;
fNameCache.Add(entry);
return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name,
node);
}
void
DirectoryCache::RemoveEntry(const char* name)
{
SinglyLinkedList<NameCacheEntry>::Iterator iterator
= fNameCache.GetIterator();
NameCacheEntry* previous = NULL;
NameCacheEntry* current = iterator.Next();
while (current != NULL) {
if (strcmp(current->fName, name) == 0) {
free(const_cast<char*>(current->fName));
delete current;
fNameCache.Remove(previous, current);
break;
}
previous = current;
current = iterator.Next();
}
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), name);
}
status_t
DirectoryCache::Revalidate()
{
uint64 change;
if (fInode->GetChangeInfo(&change) == B_OK && change == fChange) {
fExpireTime = system_time() + kExpirationTime;
return B_OK;
}
Trash();
return B_ERROR;
}
@@ -0,0 +1,136 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef DIRECTORYCACHE_H
#define DIRECTORYCACHE_H
#include <lock.h>
#include <SupportDefs.h>
#include <util/DoublyLinkedList.h>
#include <util/SinglyLinkedList.h>
class Inode;
struct NameCacheEntry :
public SinglyLinkedListLinkImpl<NameCacheEntry> {
ino_t fNode;
const char* fName;
};
class DirectoryCache : public DoublyLinkedListLinkImpl<DirectoryCache> {
public:
DirectoryCache(Inode* inode);
~DirectoryCache();
inline status_t Lock();
inline void Unlock();
void ResetAndLock();
void Trash();
status_t AddEntry(const char* name, ino_t node);
void RemoveEntry(const char* name);
inline SinglyLinkedList<NameCacheEntry>& EntriesList();
status_t Revalidate();
inline status_t ValidateChangeInfo(uint64 change);
inline void SetChangeInfo(uint64 change);
inline uint64 ChangeInfo();
inline Inode* GetInode();
inline time_t ExpireTime();
static const bigtime_t kExpirationTime = 5000000;
private:
SinglyLinkedList<NameCacheEntry> fNameCache;
Inode* fInode;
bool fTrashed;
mutex fLock;
uint64 fChange;
bigtime_t fExpireTime;
};
inline status_t
DirectoryCache::Lock()
{
mutex_lock(&fLock);
if (fTrashed) {
mutex_unlock(&fLock);
return B_ERROR;
}
return B_OK;
}
inline void
DirectoryCache::Unlock()
{
mutex_unlock(&fLock);
}
inline SinglyLinkedList<NameCacheEntry>&
DirectoryCache::EntriesList()
{
return fNameCache;
}
inline status_t
DirectoryCache::ValidateChangeInfo(uint64 change)
{
if (fTrashed || change != fChange) {
Trash();
change = fChange;
fExpireTime = system_time() + kExpirationTime;
return B_ERROR;
}
return B_OK;
}
inline void
DirectoryCache::SetChangeInfo(uint64 change)
{
fExpireTime = system_time() + kExpirationTime;
fChange = change;
}
inline uint64
DirectoryCache::ChangeInfo()
{
return fChange;
}
inline Inode*
DirectoryCache::GetInode()
{
return fInode;
}
inline time_t
DirectoryCache::ExpireTime()
{
return fExpireTime;
}
#endif // DIRECTORYCACHE_H
@@ -9,6 +9,7 @@
#define FILESYSTEM_H #define FILESYSTEM_H
#include "CacheRevalidator.h"
#include "InodeIdMap.h" #include "InodeIdMap.h"
#include "NFS4Defs.h" #include "NFS4Defs.h"
#include "NFS4Server.h" #include "NFS4Server.h"
@@ -34,6 +35,8 @@ public:
void AddOpenFile(OpenFileCookie* cookie); void AddOpenFile(OpenFileCookie* cookie);
void RemoveOpenFile(OpenFileCookie* cookie); void RemoveOpenFile(OpenFileCookie* cookie);
inline CacheRevalidator& Revalidator();
inline bool IsAttrSupported(Attribute attr) const; inline bool IsAttrSupported(Attribute attr) const;
inline uint32 ExpireType() const; inline uint32 ExpireType() const;
@@ -53,6 +56,8 @@ public:
private: private:
FileSystem(); FileSystem();
CacheRevalidator fCacheRevalidator;
OpenFileCookie* fOpenFiles; OpenFileCookie* fOpenFiles;
uint32 fOpenCount; uint32 fOpenCount;
mutex fOpenLock; mutex fOpenLock;
@@ -74,6 +79,13 @@ private:
}; };
inline CacheRevalidator&
FileSystem::Revalidator()
{
return fCacheRevalidator;
}
inline RootInode* inline RootInode*
FileSystem::Root() FileSystem::Root()
{ {
+79 -4
View File
@@ -21,7 +21,8 @@
Inode::Inode() Inode::Inode()
: :
fAttrCacheExpire(0) fAttrCacheExpire(0),
fCache(NULL)
{ {
mutex_init(&fAttrCacheLock, NULL); mutex_init(&fAttrCacheLock, NULL);
} }
@@ -80,6 +81,9 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
// FATTR4_TYPE is mandatory // FATTR4_TYPE is mandatory
inode->fType = values[0].fData.fValue32; inode->fType = values[0].fData.fValue32;
if (inode->fType == NF4DIR)
inode->fCache = new DirectoryCache(inode);
// FATTR4_FSID is mandatory // FATTR4_FSID is mandatory
FileSystemId* fsid = FileSystemId* fsid =
reinterpret_cast<FileSystemId*>(values[1].fData.fPointer); reinterpret_cast<FileSystemId*>(values[1].fData.fPointer);
@@ -99,10 +103,50 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
Inode::~Inode() Inode::~Inode()
{ {
delete fCache;
mutex_destroy(&fAttrCacheLock); mutex_destroy(&fAttrCacheLock);
} }
status_t
Inode::GetChangeInfo(uint64* change)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
Attribute attr[] = { FATTR4_CHANGE };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 1)
return result;
// FATTR4_CHANGE is mandatory
*change = values[0].fData.fValue64;
delete[] values;
return B_OK;
} while (true);
}
status_t status_t
Inode::LookUp(const char* name, ino_t* id) Inode::LookUp(const char* name, ino_t* id)
{ {
@@ -121,6 +165,9 @@ Inode::LookUp(const char* name, ino_t* id)
req.PutFH(fInfo.fHandle); req.PutFH(fInfo.fHandle);
Attribute dirAttr[] = { FATTR4_CHANGE };
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
if (!strcmp(name, "..")) if (!strcmp(name, ".."))
req.LookUpUp(); req.LookUpUp();
else else
@@ -141,6 +188,16 @@ Inode::LookUp(const char* name, ino_t* id)
continue; continue;
reply.PutFH(); reply.PutFH();
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
uint64 change = values[0].fData.fValue64;
delete[] values;
if (!strcmp(name, "..")) if (!strcmp(name, ".."))
result = reply.LookUpUp(); result = reply.LookUpUp();
else else
@@ -151,8 +208,6 @@ Inode::LookUp(const char* name, ino_t* id)
FileHandle fh; FileHandle fh;
reply.GetFH(&fh); reply.GetFH(&fh);
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count); result = reply.GetAttr(&values, &count);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -194,6 +249,20 @@ Inode::LookUp(const char* name, ino_t* id)
fFileSystem->InoIdMap()->AddEntry(fi, *id); fFileSystem->InoIdMap()->AddEntry(fi, *id);
fFileSystem->Revalidator().Lock();
if (fCache->Lock() != B_OK) {
fCache->ResetAndLock();
fCache->SetChangeInfo(change);
} else {
fFileSystem->Revalidator().RemoveDirectory(fCache);
fCache->ValidateChangeInfo(change);
}
fCache->AddEntry(name, *id);
fFileSystem->Revalidator().AddDirectory(fCache);
fCache->Unlock();
fFileSystem->Revalidator().Unlock();
return B_OK; return B_OK;
} while (true); } while (true);
} }
@@ -294,6 +363,8 @@ Inode::Remove(const char* name, FileType type)
reply.PutFH(); reply.PutFH();
result = reply.Remove(); result = reply.Remove();
// remove entry
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
return result; return result;
@@ -344,7 +415,11 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName)
reply.SaveFH(); reply.SaveFH();
reply.PutFH(); reply.PutFH();
return reply.Rename(); result = reply.Rename();
// remove entry
return result;
} while (true); } while (true);
} }
@@ -30,6 +30,8 @@ public:
inline const char* Name() const; inline const char* Name() const;
inline FileSystem* GetFileSystem() const; inline FileSystem* GetFileSystem() const;
status_t GetChangeInfo(uint64* change);
status_t LookUp(const char* name, ino_t* id); status_t LookUp(const char* name, ino_t* id);
status_t CreateLink(const char* name, const char* path, status_t CreateLink(const char* name, const char* path,
@@ -99,6 +101,8 @@ protected:
FileInfo fInfo; FileInfo fInfo;
FileSystem* fFileSystem; FileSystem* fFileSystem;
DirectoryCache* fCache;
}; };
@@ -4,8 +4,10 @@ UsePrivateKernelHeaders ;
UsePrivateHeaders shared ; UsePrivateHeaders shared ;
KernelAddon nfs4 : KernelAddon nfs4 :
CacheRevalidator.cpp
Cookie.cpp Cookie.cpp
Connection.cpp Connection.cpp
DirectoryCache.cpp
FileInfo.cpp FileInfo.cpp
FileSystem.cpp FileSystem.cpp
IdMap.cpp IdMap.cpp
@@ -528,6 +528,12 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
current++; current++;
} }
if (sIsAttrSet(FATTR4_CHANGE, bitmap, bcount)) {
values[current].fAttribute = FATTR4_CHANGE;
values[current].fData.fValue64 = stream.GetUHyper();
current++;
}
if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) { if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) {
values[current].fAttribute = FATTR4_SIZE; values[current].fAttribute = FATTR4_SIZE;
values[current].fData.fValue64 = stream.GetUHyper(); values[current].fData.fValue64 = stream.GetUHyper();