nfs4: Add attribute directory related hooks

This commit is contained in:
Pawel Dziepak
2012-08-09 02:37:04 +02:00
parent 8ba78bf323
commit f7c35cf464
14 changed files with 199 additions and 30 deletions
@@ -92,6 +92,8 @@ struct OpenDirCookie : public Cookie {
NameCacheEntry* fCurrent;
bool fEOF;
bool fAttrDir;
~OpenDirCookie();
};
@@ -10,6 +10,7 @@
#include "DirectoryCache.h"
#include <fs_cache.h>
#include <NodeMonitor.h>
#include "Inode.h"
@@ -46,10 +47,11 @@ DirectoryCacheSnapshot::~DirectoryCacheSnapshot()
}
DirectoryCache::DirectoryCache(Inode* inode)
DirectoryCache::DirectoryCache(Inode* inode, bool attr)
:
fDirectoryCache(NULL),
fInode(inode),
fAttrDir(attr),
fTrashed(true)
{
mutex_init(&fLock, NULL);
@@ -114,8 +116,12 @@ DirectoryCache::AddEntry(const char* name, ino_t node, bool created)
fDirectoryCache->fEntries.Add(entry);
}
return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name,
node);
if (!fAttrDir) {
return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(),
name, node);
}
return B_OK;
}
void
@@ -153,7 +159,10 @@ DirectoryCache::RemoveEntry(const char* name)
}
}
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), name);
if (!fAttrDir) {
entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
name);
}
}
@@ -231,8 +240,13 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
}
if (!found) {
notify_entry_created(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, newCurrent->fNode);
if (fAttrDir) {
notify_attribute_changed(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, B_ATTR_CREATED);
} else {
notify_entry_created(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, newCurrent->fNode);
}
} else
oldSnapshot->fEntries.Remove(prev, oldCurrent);
@@ -243,8 +257,13 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
oldCurrent = oldIt.Next();
while (oldCurrent != NULL) {
notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
oldCurrent->fName, oldCurrent->fNode);
if (fAttrDir) {
notify_attribute_changed(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, B_ATTR_REMOVED);
} else {
notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
oldCurrent->fName, oldCurrent->fNode);
}
oldCurrent = oldIt.Next();
}
}
@@ -37,7 +37,7 @@ struct DirectoryCacheSnapshot : public KernelReferenceable {
class DirectoryCache : public DoublyLinkedListLinkImpl<DirectoryCache> {
public:
DirectoryCache(Inode* inode);
DirectoryCache(Inode* inode, bool attr = false);
~DirectoryCache();
inline status_t Lock();
@@ -76,6 +76,7 @@ private:
Inode* fInode;
bool fAttrDir;
bool fTrashed;
mutex fLock;
@@ -44,6 +44,8 @@ struct FileInfo {
const char* fName;
const char* fPath;
FileHandle fAttrDir;
inline FileInfo();
inline ~FileInfo();
inline FileInfo(const FileInfo& fi);
@@ -24,6 +24,7 @@ Inode::Inode()
:
fMetaCache(this),
fCache(NULL),
fAttrCache(NULL),
fDelegation(NULL),
fFileCache(NULL),
fMaxFileSize(0),
@@ -93,6 +94,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
if (inode->fType == NF4DIR)
inode->fCache = new DirectoryCache(inode);
inode->fAttrCache = new DirectoryCache(inode, true);
// FATTR4_CHANGE is mandatory
inode->fChange = values[1].fData.fValue64;
@@ -131,6 +133,8 @@ Inode::~Inode()
file_cache_delete(fFileCache);
delete fCache;
delete fAttrCache;
mutex_destroy(&fStateLock);
mutex_destroy(&fFileCacheLock);
rw_lock_destroy(&fDelegationLock);
@@ -82,6 +82,8 @@ public:
status_t ReadDir(void* buffer, uint32 size,
uint32* count, OpenDirCookie* cookie);
status_t OpenAttrDir(OpenDirCookie* cookie);
status_t TestLock(OpenFileCookie* cookie,
struct flock* lock);
status_t AcquireLock(OpenFileCookie* cookie,
@@ -124,6 +126,7 @@ private:
MetadataCache fMetaCache;
DirectoryCache* fCache;
DirectoryCache* fAttrCache;
rw_lock fDelegationLock;
Delegation* fDelegation;
@@ -39,11 +39,36 @@ Inode::OpenDir(OpenDirCookie* cookie)
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
cookie->fAttrDir = false;
return B_OK;
}
status_t
Inode::OpenAttrDir(OpenDirCookie* cookie)
{
cookie->fFileSystem = fFileSystem;
cookie->fSpecial = 0;
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
cookie->fAttrDir = true;
if (fInfo.fAttrDir.fSize == 0) {
FileHandle handle;
status_t result = NFS4Inode::OpenAttrDir(&handle);
if (result != B_OK)
return result;
fInfo.fAttrDir = handle;
}
return B_OK;
}
status_t
Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
uint32 size)
@@ -152,10 +177,13 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
continue;
ino_t id;
if (dirents[i].fAttrCount == 2)
id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
else
id = FileIdToInoT(fFileSystem->AllocFileId());
if (!cookie->fAttrDir) {
if (dirents[i].fAttrCount == 2)
id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
else
id = FileIdToInoT(fFileSystem->AllocFileId());
} else
id = 0;
NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id);
if (entry == NULL || entry->fName == NULL) {
@@ -188,29 +216,30 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
}
status_t result;
DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache;
if (cookie->fSnapshot == NULL) {
fFileSystem->Revalidator().Lock();
if (fCache->Lock() != B_OK) {
fCache->ResetAndLock();
if (cache->Lock() != B_OK) {
cache->ResetAndLock();
} else {
fFileSystem->Revalidator().RemoveDirectory(fCache);
fFileSystem->Revalidator().RemoveDirectory(cache);
}
cookie->fSnapshot = fCache->GetSnapshot();
cookie->fSnapshot = cache->GetSnapshot();
if (cookie->fSnapshot == NULL) {
uint64 change;
result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change);
if (result != B_OK) {
fCache->Unlock();
cache->Unlock();
fFileSystem->Revalidator().Unlock();
return result;
}
fCache->ValidateChangeInfo(change);
fCache->SetSnapshot(cookie->fSnapshot);
cache->ValidateChangeInfo(change);
cache->SetSnapshot(cookie->fSnapshot);
}
cookie->fSnapshot->AcquireReference();
fFileSystem->Revalidator().AddDirectory(fCache);
fCache->Unlock();
fFileSystem->Revalidator().AddDirectory(cache);
cache->Unlock();
fFileSystem->Revalidator().Unlock();
}
@@ -219,7 +248,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
uint32 i = 0;
bool overflow = false;
if (cookie->fSpecial == 0 && i < *_count) {
if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
status_t result;
@@ -235,7 +264,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
return result;
}
if (cookie->fSpecial == 1 && i < *_count) {
if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
status_t result;
@@ -46,6 +46,7 @@ enum Opcode {
OpLookUpUp = 16,
OpNverify = 17,
OpOpen = 18,
OpOpenAttrDir = 19,
OpOpenConfirm = 20,
OpPutFH = 22,
OpPutRootFH = 24,
@@ -817,7 +817,10 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
if (cookie->fAttrDir)
req.PutFH(fInfo.fAttrDir);
else
req.PutFH(fInfo.fHandle);
Attribute dirAttr[] = { FATTR4_CHANGE };
if (*change == 0)
@@ -875,6 +878,37 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
}
status_t
NFS4Inode::OpenAttrDir(FileHandle* handle)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.OpenAttrDir(true);
req.GetFH();
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
result = reply.OpenAttrDir();
if (result != B_OK)
return result;
return reply.GetFH(handle);
} while (true);
}
status_t
NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position,
uint64* length, bool& conflict)
@@ -68,6 +68,8 @@ protected:
OpenDirCookie* cookie, bool* eof, uint64* change,
uint64* dirCookie, uint64* dirCookieVerf);
status_t OpenAttrDir(FileHandle* handle);
status_t TestLock(OpenFileCookie* cookie, LockType* type,
uint64* position, uint64* length, bool& conflict);
status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo,
@@ -84,6 +84,7 @@ public:
status_t Open(uint32* id, uint32* seq, bool* confirm,
OpenDelegationData* delegData,
ChangeInfo* changeInfo = NULL);
inline status_t OpenAttrDir();
status_t OpenConfirm(uint32* stateSeq);
inline status_t PutFH();
inline status_t PutRootFH();
@@ -172,6 +173,13 @@ ReplyInterpreter::LookUpUp()
}
inline status_t
ReplyInterpreter::OpenAttrDir()
{
return _OperationError(OpOpenAttrDir);
}
inline status_t
ReplyInterpreter::Nverify()
{
@@ -445,6 +445,23 @@ RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq)
}
status_t
RequestBuilder::OpenAttrDir(bool create)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpOpenAttrDir);
fRequest->Stream().AddBoolean(create);
fOpCount++;
return B_OK;
}
status_t
RequestBuilder::PutFH(const FileHandle& fh)
{
@@ -56,6 +56,7 @@ public:
uint32 count = 0, bool excl = false,
OpenDelegation delegType
= OPEN_DELEGATE_NONE);
status_t OpenAttrDir(bool create);
status_t OpenConfirm(uint32 seq, const uint32* id,
uint32 stateSeq);
status_t PutFH(const FileHandle& fh);
@@ -610,6 +610,52 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
}
static status_t
nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
{
OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie;
if (cookie == NULL)
return B_NO_MEMORY;
*_cookie = cookie;
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
status_t result = inode->OpenAttrDir(cookie);
if (result != B_OK)
delete cookie;
return result;
}
static status_t
nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
return nfs4_close_attr_dir(volume, vnode, cookie);
}
static status_t
nfs4_free_attr_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
return nfs4_free_dir_cookie(volume, vnode, cookie);
}
static status_t
nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie,
struct dirent* buffer, size_t bufferSize, uint32* _num)
{
return nfs4_read_dir(volume, vnode, cookie, buffer, bufferSize, _num);
}
static status_t
nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
return nfs4_rewind_attr_dir(volume, vnode, cookie);
}
static status_t
nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
struct flock* lock)
@@ -774,11 +820,11 @@ fs_vnode_ops gNFSv4VnodeOps = {
nfs4_rewind_dir,
/* attribute directory operations */
NULL, // open_attr_dir
NULL, // close_attr_dir
NULL, // free_attr_dir_cookie
NULL, // read_attr_dir
NULL, // rewind_attr_dir
nfs4_open_attr_dir,
nfs4_close_attr_dir,
nfs4_free_attr_dir_cookie,
nfs4_read_attr_dir,
nfs4_rewind_attr_dir,
/* attribute operations */
NULL, // create_attr