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