nfs4: Add attribute directory related hooks
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user