[haiku-commits] BRANCH pdziepak-github.nfs4 - src/add-ons/kernel/file_systems/nfs4

  • From: pdziepak-github.nfs4 <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 6 Aug 2012 23:49:19 +0200 (CEST)

added 6 changesets to branch 'refs/remotes/pdziepak-github/nfs4'
old head: e2e5f06d6e736c019ed37c475ff4f68e3c4f401c
new head: 224d602294491975618b856227b84120a5e1e0fc

----------------------------------------------------------------------------

2c36184: nfs4: Support delegations of created files

cde3994: nfs4: Return delegation before open upgrade

f1fe25e: nfs4: Repair O_TRUNC support

4121741: nfs4: Add asynchronous work queue

0dff48c: nfs4: Recall all delegations when callback path is down

224d602: nfs4: Add support for CB_GETATTR

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

24 files changed, 614 insertions(+), 43 deletions(-)
.../kernel/file_systems/nfs4/Connection.cpp        |    2 +-
.../kernel/file_systems/nfs4/Delegation.cpp        |    5 +-
src/add-ons/kernel/file_systems/nfs4/Delegation.h  |    2 -
.../kernel/file_systems/nfs4/FileSystem.cpp        |   18 ++
src/add-ons/kernel/file_systems/nfs4/FileSystem.h  |    3 +
src/add-ons/kernel/file_systems/nfs4/Inode.cpp     |   30 ++-
src/add-ons/kernel/file_systems/nfs4/Inode.h       |   26 ++-
.../kernel/file_systems/nfs4/InodeRegular.cpp      |   38 +++-
src/add-ons/kernel/file_systems/nfs4/Jamfile       |    1 +
.../kernel/file_systems/nfs4/MetadataCache.cpp     |   28 ++-
.../kernel/file_systems/nfs4/MetadataCache.h       |    4 +
src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h    |    5 +
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp |   18 +-
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h   |    3 +-
.../kernel/file_systems/nfs4/NFS4Server.cpp        |   83 ++++++-
src/add-ons/kernel/file_systems/nfs4/NFS4Server.h  |    4 +
.../kernel/file_systems/nfs4/RPCCallbackServer.cpp |    4 +-
.../kernel/file_systems/nfs4/ReplyBuilder.cpp      |   34 +++
.../kernel/file_systems/nfs4/ReplyBuilder.h        |    2 +
.../file_systems/nfs4/RequestInterpreter.cpp       |   34 +++
.../kernel/file_systems/nfs4/RequestInterpreter.h  |    1 +
src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp |  184 ++++++++++++++++
src/add-ons/kernel/file_systems/nfs4/WorkQueue.h   |   82 +++++++
.../kernel/file_systems/nfs4/kernel_interface.cpp  |   46 +++-

############################################################################

Commit:      2c36184f198a0511e54da85e20b5bf1379503660

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 14:41:34 2012 UTC

nfs4: Support delegations of created files

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index e5d90c2..68928bf 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -59,7 +59,8 @@ public:
                                        status_t        WriteStat(const struct 
stat* st, uint32 mask);
 
                                        status_t        Create(const char* 
name, int mode, int perms,
-                                                                       
OpenFileCookie* cookie, ino_t* id);
+                                                                       
OpenFileCookie* cookie,
+                                                                       
OpenDelegationData* data, ino_t* id);
                                        status_t        Open(int mode, 
OpenFileCookie* cookie);
                                        status_t        Close(OpenFileCookie* 
cookie);
                                        status_t        Read(OpenFileCookie* 
cookie, off_t pos,
@@ -89,7 +90,8 @@ protected:
                                                                Inode();
 
                                        status_t        CreateState(const char* 
name, int mode,
-                                                                       int 
perms, OpenState* state);
+                                                                       int 
perms, OpenState* state,
+                                                                       
OpenDelegationData* data);
 
                                        status_t        ReadDirUp(struct 
dirent* de, uint32 pos,
                                                                        uint32 
size);
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index 0056512..4526487 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -20,13 +20,14 @@
 
 
 status_t
-Inode::CreateState(const char* name, int mode, int perms, OpenState* state) {
+Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
+       OpenDelegationData* delegationData) {
        uint64 fileID;
        FileHandle handle;
        ChangeInfo changeInfo;
 
        status_t result = CreateFile(name, mode, perms, state, &changeInfo,
-               &fileID, &handle);
+               &fileID, &handle, delegationData);
        if (result != B_OK)
                return result;
 
@@ -64,7 +65,7 @@ Inode::CreateState(const char* name, int mode, int perms, 
OpenState* state) {
 
 status_t
 Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
-       ino_t* id)
+       OpenDelegationData* data, ino_t* id)
 {
        cookie->fMode = mode;
        cookie->fLocks = NULL;
@@ -72,7 +73,7 @@ Inode::Create(const char* name, int mode, int perms, 
OpenFileCookie* cookie,
        MutexLocker _(fStateLock);
 
        OpenState* state = new OpenState;
-       status_t result = CreateState(name, mode, perms, state);
+       status_t result = CreateState(name, mode, perms, state, data);
        if (result != B_OK)
                return result;
 
@@ -99,6 +100,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
        OpenDelegationData data;
        data.fType = OPEN_DELEGATE_NONE;
        if (fOpenState == NULL) {
+               // TODO: revalidate cache
+
                OpenState* state = new OpenState;
                if (state == NULL)
                        return B_NO_MEMORY;
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
index e45f08f..67649d9 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
@@ -381,15 +381,14 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* 
fromName,
 
 
 status_t
-NFS4Inode::CreateFile(const char* name, int mode, int perms,
-       OpenState* state, ChangeInfo* changeInfo, uint64* fileID,
-       FileHandle* handle)
+NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state,
+       ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
+       OpenDelegationData* delegation)
 {
        bool confirm;
        status_t result;
 
        bool badOwner = false;
-       OpenDelegationData delegation;
        uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                state->fClientID = fFileSystem->NFSServer()->ClientId();
@@ -461,7 +460,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
                reply.PutFH();
 
                result = reply.Open(state->fStateID, &state->fStateSeq, 
&confirm,
-                       &delegation, changeInfo);
+                       delegation, changeInfo);
                if (result != B_OK)
                        return result;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
index 968e670..3e1bedb 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
@@ -46,7 +46,8 @@ protected:
 
                        status_t        CreateFile(const char* name, int mode, 
int perms,
                                                        OpenState* state, 
ChangeInfo* changeInfo,
-                                                       uint64* fileID, 
FileHandle* handle);
+                                                       uint64* fileID, 
FileHandle* handle,
+                                                       OpenDelegationData* 
delegation);
                        status_t        OpenFile(OpenState* state, int mode,
                                                        OpenDelegationData* 
delegation);
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp 
b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
index 6da6cd1..9a9f8b9 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -392,7 +392,10 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* 
name, int openMode,
        *_cookie = cookie;
 
        Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
-       status_t result = inode->Create(name, openMode, perms, cookie, 
_newVnodeID);
+
+       OpenDelegationData data;
+       status_t result = inode->Create(name, openMode, perms, cookie, &data,
+               _newVnodeID);
        if (result != B_OK) {
                delete cookie;
                return result;
@@ -417,6 +420,17 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* 
name, int openMode,
 
        child->SetOpenState(cookie->fOpenState);
 
+       if (data.fType != OPEN_DELEGATE_NONE) {
+               Delegation* delegation
+                       = new(std::nothrow) Delegation(data, child,
+                               cookie->fOpenState->fClientID);
+               if (delegation != NULL) {
+                       delegation->fInfo = cookie->fOpenState->fInfo;
+                       delegation->fFileSystem = child->GetFileSystem();
+                       child->SetDelegation(delegation);
+               }
+       }
+
        return result;
 }
 

############################################################################

Commit:      cde3994e6907eaa3324ce4918b259b65da290c84

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 16:14:55 2012 UTC

nfs4: Return delegation before open upgrade

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
index 7d64adb..80aeb43 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
@@ -26,12 +26,9 @@ Delegation::Delegation(const OpenDelegationData& data, 
Inode* inode,
 status_t
 Delegation::GiveUp(bool truncate)
 {
-       if (!truncate) {
+       if (!truncate)
                fInode->SyncAndCommit(true);
 
-               // TODO: claim locks
-       }
-
        ReturnDelegation();
 
        return B_OK;
diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h 
b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
index 9d67afb..19afcfb 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
@@ -23,8 +23,6 @@ public:
                                                Delegation(const 
OpenDelegationData& data, Inode* inode,
                                                        uint64 clientID);
 
-       // TODO: locks
-
        status_t                        GiveUp(bool truncate = false);
 
        inline  Inode*          GetInode();
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index e2362da..1121a6e 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -139,6 +139,9 @@ Inode::~Inode()
 status_t
 Inode::RevalidateFileCache()
 {
+       if (fDelegation != NULL)
+               return B_OK;
+
        uint64 change;
        status_t result = GetChangeInfo(&change);
        if (result != B_OK)
@@ -153,8 +156,7 @@ Inode::RevalidateFileCache()
        if (result != B_OK)
                return result;
 
-       file_cache_sync(fFileCache);
-       Commit();
+       SyncAndCommit(true);
        file_cache_delete(fFileCache);
 
        fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size);
@@ -760,6 +762,12 @@ void
 Inode::SetDelegation(Delegation* delegation)
 {
        WriteLocker _(fDelegationLock);
+
+       fMetaCache.InvalidateStat();
+       struct stat st;
+       Stat(&st);
+       fMetaCache.LockValid(); 
+
        fDelegation = delegation;
        fOpenState->AcquireReference();
        fOpenState->fDelegation = delegation;
@@ -773,6 +781,24 @@ Inode::RecallDelegation(bool truncate)
        WriteLocker _(fDelegationLock);
        if (fDelegation == NULL)
                return;
+       ReturnDelegation(truncate);
+}
+
+
+void
+Inode::RecallReadDelegation()
+{
+       WriteLocker _(fDelegationLock);
+       if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ)
+               return;
+       ReturnDelegation(false);
+}
+
+
+void
+Inode::ReturnDelegation(bool truncate)
+{
+       fMetaCache.UnlockValid();
 
        fDelegation->GiveUp(truncate);
        fFileSystem->RemoveDelegation(fDelegation);
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index 68928bf..d2bafcf 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -36,6 +36,7 @@ public:
 
                                        void            
SetDelegation(Delegation* delegation);
                                        void            RecallDelegation(bool 
truncate = false);
+                                       void            RecallReadDelegation();
 
                                        status_t        LookUp(const char* 
name, ino_t* id);
 
@@ -93,6 +94,8 @@ protected:
                                                                        int 
perms, OpenState* state,
                                                                        
OpenDelegationData* data);
 
+                                       void            ReturnDelegation(bool 
truncate);
+
                                        status_t        ReadDirUp(struct 
dirent* de, uint32 pos,
                                                                        uint32 
size);
                                        status_t        FillDirEntry(struct 
dirent* de, ino_t id,
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index 4526487..cc53d1d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -95,12 +95,12 @@ Inode::Create(const char* name, int mode, int perms, 
OpenFileCookie* cookie,
 status_t
 Inode::Open(int mode, OpenFileCookie* cookie)
 {
-       MutexLocker _(fStateLock);
+       MutexLocker locker(fStateLock);
 
        OpenDelegationData data;
        data.fType = OPEN_DELEGATE_NONE;
        if (fOpenState == NULL) {
-               // TODO: revalidate cache
+               RevalidateFileCache();
 
                OpenState* state = new OpenState;
                if (state == NULL)
@@ -114,16 +114,28 @@ Inode::Open(int mode, OpenFileCookie* cookie)
 
                fFileSystem->AddOpenFile(state);
                fOpenState = state;
+               locker.Unlock();
        } else {
+               fOpenState->AcquireReference();
+               locker.Unlock();
+
                int newMode = mode & O_RWMASK;
                int oldMode = fOpenState->fMode & O_RWMASK;
                if (oldMode != newMode && oldMode != O_RDWR) {
+                       if (oldMode == O_RDONLY)
+                               RecallReadDelegation();
+
                        status_t result = OpenFile(fOpenState, O_RDWR, &data);
-                       if (result != B_OK)
+                       if (result != B_OK) {
+                               locker.Lock();
+                               if (fOpenState->ReleaseReference() == 1) {
+                                       fFileSystem->RemoveOpenFile(fOpenState);
+                                       fOpenState = NULL;
+                               }
                                return result;
+                       }
                        fOpenState->fMode = O_RDWR;
                }
-               fOpenState->AcquireReference();
        }
 
        cookie->fOpenState = fOpenState;
diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp 
b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp
index d8ba4be..058ce24 100644
--- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp
@@ -12,7 +12,8 @@
 
 MetadataCache::MetadataCache()
        :
-       fExpire(0)
+       fExpire(0),
+       fForceValid(false)
 {
        mutex_init(&fLock, NULL);
 }
@@ -28,7 +29,7 @@ status_t
 MetadataCache::GetStat(struct stat* st)
 {
        MutexLocker _(fLock);
-       if (fExpire > time(NULL)) {
+       if (fForceValid || fExpire > time(NULL)) {
                // Do not touch other members of struct stat
                st->st_size = fStatCache.st_size;
                st->st_mode = fStatCache.st_mode;
@@ -97,3 +98,26 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed)
        fAccessCache.Insert(uid, entry);
 }
 
+
+status_t
+MetadataCache::LockValid()
+{
+       MutexLocker _(fLock);
+       if (fForceValid || fExpire > time(NULL)) {
+               fForceValid = true;
+               return B_OK;
+       }
+
+       return B_ERROR;
+}
+
+
+void
+MetadataCache::UnlockValid()
+{
+       MutexLocker _(fLock);
+       fExpire = time(NULL) + kExpirationTime;
+       fForceValid = false;
+}
+
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h 
b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h
index ecf12e7..4622c9e 100644
--- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h
+++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h
@@ -32,6 +32,9 @@ public:
                                        status_t        GetAccess(uid_t uid, 
uint32* allowed);
                                        void            SetAccess(uid_t uid, 
uint32 allowed);
 
+                                       status_t        LockValid();
+                                       void            UnlockValid();
+
        inline                  void            InvalidateStat();
        inline                  void            InvalidateAccess();
 
@@ -41,6 +44,7 @@ public:
 private:
                                        struct stat     fStatCache;
                                        time_t          fExpire;
+                                       bool            fForceValid;
 
                                        AVLTreeMap<uid_t, AccessEntry>  
fAccessCache;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index 05c8503..274ac6a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -332,6 +332,7 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, 
ReplyBuilder* reply)
        delegation->GetInode()->RecallDelegation(truncate);
 
        reply->Recall(B_OK);
+
        return B_OK;
 }
 

############################################################################

Commit:      f1fe25e50864bd85cf8443b891d29dfa190b8c32

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 16:30:02 2012 UTC

nfs4: Repair O_TRUNC support

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index cc53d1d..f132762 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -138,6 +138,13 @@ Inode::Open(int mode, OpenFileCookie* cookie)
                }
        }
 
+       if ((mode & O_TRUNC) == O_TRUNC) {
+               struct stat st;
+               st.st_size = 0;
+               WriteStat(&st, B_STAT_SIZE);
+               file_cache_set_size(fFileCache, 0);
+       }
+
        cookie->fOpenState = fOpenState;
 
        cookie->fFileSystem = fFileSystem;
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
index 67649d9..a424350 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
@@ -526,15 +526,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode, 
OpenDelegationData* delegation)
                }
 
                req.PutFH(fInfo.fParent);
-               if ((mode & O_TRUNC) == O_TRUNC) {
-                       AttrValue attr;
-                       attr.fAttribute = FATTR4_SIZE;
-                       attr.fFreePointer = false;
-                       attr.fData.fValue64 = 0;
-                       req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
-                               state->fClientID, OPEN4_CREATE, 
fFileSystem->OpenOwner(), 
-                               fInfo.fName, &attr, 1, false);
-               } else
                req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), 
state->fClientID,
                        OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName);
                req.GetFH();

############################################################################

Commit:      412174162e796c3208a93041f33b7de45425c847

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 20:41:20 2012 UTC

nfs4: Add asynchronous work queue

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
index cc4611b..322ef47 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
@@ -163,7 +163,7 @@ ServerAddress::InAddr() const
 status_t
 ServerAddress::ResolveName(const char* name, ServerAddress* address)
 {
-       address->fProtocol = IPPROTO_TCP;
+       address->fProtocol = IPPROTO_UDP;
 
        // getaddrinfo() is very expensive when called from kernel, so we do not
        // want to call it unless there is no other choice.
diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile 
b/src/add-ons/kernel/file_systems/nfs4/Jamfile
index a3a4194..246ba99 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Jamfile
+++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile
@@ -35,6 +35,7 @@ KernelAddon nfs4 :
        RPCCallbackServer.cpp
        RPCReply.cpp
        RPCServer.cpp
+       WorkQueue.cpp
        XDR.cpp
 ;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index 274ac6a..9ea450b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -11,6 +11,7 @@
 #include "Inode.h"
 #include "NFS4Server.h"
 #include "Request.h"
+#include "WorkQueue.h"
 
 
 NFS4Server::NFS4Server(RPC::Server* serv)
@@ -247,6 +248,9 @@ NFS4Server::_Renewal()
                request.Send();
 
                switch (request.Reply().NFS4Error()) {
+                       case NFS4ERR_CB_PATH_DOWN:
+                               RecallAll();
+                               break;
                        case NFS4ERR_STALE_CLIENTID:
                                ServerRebooted(clientId);
                                break;
@@ -328,11 +332,40 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, 
ReplyBuilder* reply)
                return B_FILE_NOT_FOUND;
        }
 
-       // TODO: should be asynchronous
-       delegation->GetInode()->RecallDelegation(truncate);
+       DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs;
+       args->fDelegation = delegation;
+       args->fTruncate = truncate;
+       gWorkQueue->EnqueueJob(DelegationRecall, args);
 
        reply->Recall(B_OK);
 
        return B_OK;
 }
 
+
+status_t
+NFS4Server::RecallAll()
+{
+#if 0
+       MutexLocker locker(fFSLock);
+
+       Delegation* delegation = NULL;
+       FileSystem* current = fFileSystems;
+       while (current != NULL) {
+               delegation = current->GetDelegation(handle);
+               if (delegation != NULL)
+                       break;
+
+               current = current->fNext;
+       }
+       locker.Unlock();
+
+       DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs;
+       DelegationRecallArgs* args;
+       args->fDelegation = delegation;
+       args->fTruncate = truncate;
+       gWorkQueue->EnqueueJob(DelegationRecall, args);
+#endif
+       return B_OK;
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
index d312018..fe159b3 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
@@ -42,6 +42,7 @@ public:
 
                        status_t                
CallbackRecall(RequestInterpreter* request,
                                                                ReplyBuilder* 
reply);
+                       status_t                RecallAll();
 private:
                        status_t                _GetLeaseTime();
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
index b007a3b..54fd3d3 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
@@ -26,7 +26,7 @@ CallbackServer::CallbackServer()
        fConnectionList(NULL),
        fListener(NULL),
        fThreadRunning(false),
-       //fCallbackArray(NULL),
+       fCallbackArray(NULL),
        fArraySize(0),
        fFreeSlot(-1)
 {
@@ -40,7 +40,7 @@ CallbackServer::~CallbackServer()
 {
        StopServer();
 
-       //free(fCallbackArray);
+       free(fCallbackArray);
        rw_lock_destroy(&fArrayLock);
        mutex_destroy(&fThreadLock);
        mutex_destroy(&fConnectionLock);
diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp 
b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp
new file mode 100644
index 0000000..9d38724
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+
+
+#include "WorkQueue.h"
+
+#include <io_requests.h>
+
+
+WorkQueue*             gWorkQueue              = NULL;
+
+
+WorkQueue::WorkQueue()
+       :
+       fQueueSemaphore(create_sem(0, NULL)),
+       fThreadCancel(create_sem(0, NULL))
+{
+       mutex_init(&fQueueLock, NULL);
+
+       fThread = spawn_kernel_thread(&WorkQueue::LaunchWorkingThread,
+               "NFSv4 Work Queue", B_NORMAL_PRIORITY, this);
+       if (fThread < B_OK) {
+               fInitError = fThread;
+               return;
+       }
+
+       status_t result = resume_thread(fThread);
+       if (result != B_OK) {
+               kill_thread(fThread);
+               fInitError = result;
+               return;
+       }
+
+       fInitError = B_OK;
+}
+
+
+WorkQueue::~WorkQueue()
+{
+       release_sem(fThreadCancel);
+
+       status_t result;
+       wait_for_thread(fThread, &result);
+
+       mutex_destroy(&fQueueLock);
+       delete_sem(fThreadCancel);
+       delete_sem(fQueueSemaphore);
+}
+
+
+status_t
+WorkQueue::EnqueueJob(JobType type, void* args)
+{
+       WorkQueueEntry* entry = new(std::nothrow) WorkQueueEntry;
+       if (entry == NULL)
+               return B_NO_MEMORY;
+
+       entry->fType = type;
+       entry->fArguments = args;
+       MutexLocker locker(fQueueLock);
+       fQueue.InsertAfter(fQueue.Tail(), entry);
+       locker.Unlock();
+
+       release_sem(fQueueSemaphore);
+       return B_OK;
+}
+
+
+status_t
+WorkQueue::LaunchWorkingThread(void* object)
+{
+       WorkQueue* queue = reinterpret_cast<WorkQueue*>(object);
+       return queue->WorkingThread();
+}
+
+
+status_t
+WorkQueue::WorkingThread()
+{
+       while (true) {
+               object_wait_info object[2];
+               object[0].object = fThreadCancel;
+               object[0].type = B_OBJECT_TYPE_SEMAPHORE;
+               object[0].events = B_EVENT_ACQUIRE_SEMAPHORE;
+
+               object[1].object = fQueueSemaphore;
+               object[1].type = B_OBJECT_TYPE_SEMAPHORE;
+               object[1].events = B_EVENT_ACQUIRE_SEMAPHORE;
+
+               status_t result = wait_for_objects(object, 2);
+
+               if (result < B_OK ||
+                       (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) {
+                       return result;
+               } else if ((object[1].events & B_EVENT_ACQUIRE_SEMAPHORE) == 0)
+                       continue;
+
+               acquire_sem(fQueueSemaphore);
+
+               DequeueJob();
+       }
+
+       return B_OK;
+}
+
+
+void
+WorkQueue::DequeueJob()
+{
+       MutexLocker locker(fQueueLock);
+
+       WorkQueueEntry* entry = fQueue.RemoveHead();
+
+       void* args = entry->fArguments;
+       switch (entry->fType) {
+               case DelegationRecall:
+                       
JobRecall(reinterpret_cast<DelegationRecallArgs*>(args));
+                       break;
+               case IORequest:
+                       JobIO(reinterpret_cast<IORequestArgs*>(args));
+                       break;
+       }
+
+       delete entry;
+}
+
+
+void
+WorkQueue::JobRecall(DelegationRecallArgs* args)
+{
+       args->fDelegation->GetInode()->RecallDelegation(args->fTruncate);
+}
+
+
+void
+WorkQueue::JobIO(IORequestArgs* args)
+{
+       uint64 offset = io_request_offset(args->fRequest);
+       uint64 length = io_request_length(args->fRequest);
+
+       char* buffer = reinterpret_cast<char*>(malloc(length));
+       if (buffer == NULL) {
+               notify_io_request(args->fRequest, B_NO_MEMORY);
+               return;
+       }
+
+       bool eof = false;
+       uint64 size = 0;
+       status_t result;
+       if (io_request_is_write(args->fRequest)) {
+               result = read_from_io_request(args->fRequest, buffer, length);
+
+               do {
+                       size_t bytesWritten = length - size;
+                       result = args->fInode->WriteDirect(NULL, offset + size,
+                               buffer + size, &bytesWritten);
+                       size += bytesWritten;
+               } while (size < length && result == B_OK);
+       } else {
+               do {
+                       size_t bytesRead = length - size;
+                       result = args->fInode->ReadDirect(NULL, offset + size, 
buffer,
+                               &bytesRead, &eof);
+                       if (result != B_OK)
+                               break;
+
+                       result = write_to_io_request(args->fRequest, buffer, 
bytesRead);
+                       if (result != B_OK)
+                               break;
+
+                       size += bytesRead;
+               } while (size < length && result == B_OK && !eof);
+               
+       }
+       free(buffer);
+
+       notify_io_request(args->fRequest, result);
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h 
b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h
new file mode 100644
index 0000000..954d011
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+#ifndef WORKQUEUE_H
+#define WORKQUEUE_H
+
+
+#include <io_requests.h>
+#include <lock.h>
+#include <SupportDefs.h>
+#include <util/DoublyLinkedList.h>
+
+#include "Delegation.h"
+#include "Inode.h"
+
+
+enum JobType {
+       DelegationRecall,
+       IORequest
+};
+
+struct DelegationRecallArgs {
+       Delegation*             fDelegation;
+       bool                    fTruncate;
+};
+
+struct IORequestArgs {
+       io_request*             fRequest;
+       Inode*                  fInode;
+};
+
+struct WorkQueueEntry : public DoublyLinkedListLinkImpl<WorkQueueEntry> {
+       JobType                 fType;
+       void*                   fArguments;
+};
+
+class WorkQueue {
+public:
+                                               WorkQueue();
+                                               ~WorkQueue();
+
+       inline  status_t        InitStatus();
+
+                       status_t        EnqueueJob(JobType type, void* args);
+
+protected:
+       static  status_t        LaunchWorkingThread(void* object);
+                       status_t        WorkingThread();
+
+                       void            DequeueJob();
+
+                       void            JobRecall(DelegationRecallArgs* args);
+                       void            JobIO(IORequestArgs* args);
+
+private:
+                       status_t        fInitError;
+
+                       sem_id          fQueueSemaphore;
+                       mutex           fQueueLock;
+                       DoublyLinkedList<WorkQueueEntry>        fQueue;
+
+                       sem_id          fThreadCancel;
+                       thread_id       fThread;        
+};
+
+
+inline status_t
+WorkQueue::InitStatus()
+{
+       return fInitError;
+}
+
+
+extern WorkQueue*              gWorkQueue;
+
+
+#endif // WORKQUEUE_H
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp 
b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
index 9a9f8b9..f396be2 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -22,6 +22,7 @@
 #include "RootInode.h"
 #include "RPCCallbackServer.h"
 #include "RPCServer.h"
+#include "WorkQueue.h"
 
 
 extern fs_volume_ops gNFSv4VolumeOps;
@@ -282,8 +283,21 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
 static status_t
 nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request)
 {
-       // no asynchronous calls yet
-       return B_UNSUPPORTED;
+       Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
+
+       IORequestArgs* args = new(std::nothrow) IORequestArgs;
+       if (args == NULL) {
+               notify_io_request(request, B_NO_MEMORY);
+               return B_NO_MEMORY;
+       }
+       args->fRequest = request;
+       args->fInode = inode;
+
+       status_t result = gWorkQueue->EnqueueJob(IORequest, args);
+       if (result != B_OK)
+               notify_io_request(request, result);
+
+       return result;
 }
 
 
@@ -651,10 +665,19 @@ nfs4_init()
                return B_NO_MEMORY;
        }
 
+       gWorkQueue = new(std::nothrow) WorkQueue;
+       if (gWorkQueue == NULL || gWorkQueue->InitStatus() != B_OK) {
+               delete gWorkQueue;
+               delete gIdMapper;
+               delete gRPCServerManager;
+               return B_NO_MEMORY;
+       }
+
        gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer;
        if (gRPCCallbackServer == NULL) {
-               delete gRPCServerManager;
                delete gIdMapper;
+               delete gWorkQueue;
+               delete gRPCServerManager;
                return B_NO_MEMORY;
        }
 
@@ -669,6 +692,7 @@ nfs4_uninit()
 
        delete gRPCCallbackServer;
        delete gIdMapper;
+       delete gWorkQueue;
        delete gRPCServerManager;
 
        return B_OK;

############################################################################

Commit:      0dff48c7ea15e3ee52598682f5da108558987c20

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 20:52:35 2012 UTC

nfs4: Recall all delegations when callback path is down

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
index 9379f3e..ecc56b2 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
@@ -311,11 +311,28 @@ FileSystem::RemoveOpenFile(OpenState* state)
 }
 
 
+DoublyLinkedList<Delegation>&
+FileSystem::DelegationsLock()
+{
+       mutex_lock(&fDelegationLock);
+       return fDelegationList;
+}
+
+
+void
+FileSystem::DelegationsUnlock()
+{
+       mutex_unlock(&fDelegationLock);
+}
+
+
 void
 FileSystem::AddDelegation(Delegation* delegation)
 {
        MutexLocker _(fDelegationLock);
 
+       fDelegationList.InsertBefore(fDelegationList.Head(), delegation);
+
        fHandleToDelegation.Remove(delegation->fInfo.fHandle);
        fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation);
 
@@ -328,6 +345,7 @@ FileSystem::RemoveDelegation(Delegation* delegation)
 {
        MutexLocker _(fDelegationLock);
 
+       fDelegationList.Remove(delegation);
        fHandleToDelegation.Remove(delegation->fInfo.fHandle);
 
        NFSServer()->DecUsage();
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
index 0bd634d..adfea0a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
@@ -36,6 +36,8 @@ public:
                        void                            AddOpenFile(OpenState* 
state);
                        void                            
RemoveOpenFile(OpenState* state);
 
+                       DoublyLinkedList<Delegation>&   DelegationsLock();
+                       void                            DelegationsUnlock();
                        void                            
AddDelegation(Delegation* delegation);
                        void                            
RemoveDelegation(Delegation* delegation);
                        Delegation*                     GetDelegation(const 
FileHandle& handle);
@@ -68,6 +70,7 @@ private:
                        CacheRevalidator        fCacheRevalidator;
 
                        mutex                           fDelegationLock;
+                       DoublyLinkedList<Delegation>    fDelegationList;
                        AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation;
 
                        OpenState*                      fOpenFiles;
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index 9ea450b..9dea65c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -346,26 +346,26 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, 
ReplyBuilder* reply)
 status_t
 NFS4Server::RecallAll()
 {
-#if 0
-       MutexLocker locker(fFSLock);
+       MutexLocker _(fFSLock);
+       FileSystem* fs = fFileSystems;
+       while (fs != NULL) {
+               DoublyLinkedList<Delegation>& list = fs->DelegationsLock();
+               DoublyLinkedList<Delegation>::Iterator iterator = 
list.GetIterator();
 
-       Delegation* delegation = NULL;
-       FileSystem* current = fFileSystems;
-       while (current != NULL) {
-               delegation = current->GetDelegation(handle);
-               if (delegation != NULL)
-                       break;
+               Delegation* current = iterator.Next();
+               while (current != NULL) {
+                       DelegationRecallArgs* args = new(std::nothrow) 
DelegationRecallArgs;
+                       args->fDelegation = current;
+                       args->fTruncate = false;
+                       gWorkQueue->EnqueueJob(DelegationRecall, args);
 
-               current = current->fNext;
+                       current = iterator.Next();
+               }       
+               fs->DelegationsUnlock();
+
+               fs = fs->fNext;
        }
-       locker.Unlock();
 
-       DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs;
-       DelegationRecallArgs* args;
-       args->fDelegation = delegation;
-       args->fTruncate = truncate;
-       gWorkQueue->EnqueueJob(DelegationRecall, args);
-#endif
        return B_OK;
 }
 

############################################################################

Commit:      224d602294491975618b856227b84120a5e1e0fc

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 21:26:37 2012 UTC

nfs4: Add support for CB_GETATTR

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index d2bafcf..6dce7ba 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -34,6 +34,9 @@ public:
 
        inline                  uint64          MaxFileSize();
 
+       inline                  uint64          Change();
+       inline                  bool            Dirty();
+
                                        void            
SetDelegation(Delegation* delegation);
                                        void            RecallDelegation(bool 
truncate = false);
                                        void            RecallReadDelegation();
@@ -195,5 +198,19 @@ Inode::MaxFileSize()
 }
 
 
+inline uint64
+Inode::Change()
+{
+       return fChange;
+}
+
+
+inline bool
+Inode::Dirty()
+{
+       return fWriteDirty;
+}
+
+
 #endif // INODE_H
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index f132762..a4dcd76 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -31,6 +31,8 @@ Inode::CreateState(const char* name, int mode, int perms, 
OpenState* state,
        if (result != B_OK)
                return result;
 
+       RevalidateFileCache();
+
        FileInfo fi;
        fi.fFileId = fileID;
        fi.fHandle = handle;
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
index c162462..e60b45c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
@@ -26,6 +26,7 @@ enum CallbackProcedure {
 };
 
 enum CallbackOpcode {
+       OpCallbackGetAttr               = 3,
        OpCallbackRecall                = 4
 };
 
@@ -135,6 +136,10 @@ enum Attribute {
        FATTR4_MAXIMUM_ATTR_ID
 };
 
+enum CallbackAttr {
+       CallbackAttrSize                        = 1,
+       CallbackAttrChange                      = 2
+};
 
 static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap,
        uint32 count)
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index 9dea65c..07acb75 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -284,6 +284,9 @@ NFS4Server::ProcessCallback(RPC::CallbackRequest* request,
 
        for (uint32 i = 0; i < count; i++) {
                switch (req.Operation()) {
+                       case OpCallbackGetAttr:
+                               result = CallbackGetAttr(&req, &reply);
+                               break;
                        case OpCallbackRecall:
                                result = CallbackRecall(&req, &reply);
                                break;
@@ -344,6 +347,48 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, 
ReplyBuilder* reply)
 
 
 status_t
+NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply)
+{
+       FileHandle handle;
+       int mask;
+
+       status_t result = request->GetAttr(&handle, &mask);
+       if (result != B_OK)
+               return result;
+       return B_OK;
+
+       MutexLocker locker(fFSLock);
+
+       Delegation* delegation = NULL;
+       FileSystem* current = fFileSystems;
+       while (current != NULL) {
+               delegation = current->GetDelegation(handle);
+               if (delegation != NULL)
+                       break;
+
+               current = current->fNext;
+       }
+       locker.Unlock();
+
+       if (delegation == NULL) {
+               reply->GetAttr(B_FILE_NOT_FOUND, 0, 0, 0);
+               return B_FILE_NOT_FOUND;
+       }
+
+       struct stat st;
+       delegation->GetInode()->Stat(&st);
+
+       uint64 change;
+       change = delegation->GetInode()->Change();
+       if (delegation->GetInode()->Dirty())
+               change++;
+       reply->GetAttr(B_OK, mask, st.st_size, change);
+
+       return B_OK;
+}
+
+
+status_t
 NFS4Server::RecallAll()
 {
        MutexLocker _(fFSLock);
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
index fe159b3..4fe2dcc 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
@@ -43,6 +43,9 @@ public:
                        status_t                
CallbackRecall(RequestInterpreter* request,
                                                                ReplyBuilder* 
reply);
                        status_t                RecallAll();
+
+                       status_t                
CallbackGetAttr(RequestInterpreter* request,
+                                                               ReplyBuilder* 
reply);
 private:
                        status_t                _GetLeaseTime();
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp 
b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp
index e18a4a6..152d5de 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp
@@ -57,6 +57,40 @@ ReplyBuilder::Reply()
 
 
 status_t
+ReplyBuilder::GetAttr(status_t status, int mask, uint64 size, uint64 change)
+{
+       if (fStatus != B_OK)
+               return B_ERROR;
+
+       fReply->Stream().AddUInt(OpCallbackGetAttr);
+       fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus));
+       fStatus = status;
+
+       if (status == B_OK) {
+               uint32 bitmap = 0;
+               if ((mask & CallbackAttrChange) != 0)
+                       bitmap |= 1 << FATTR4_CHANGE;
+               if ((mask & CallbackAttrSize) != 0)
+                       bitmap |= 1 << FATTR4_SIZE;
+               fReply->Stream().AddUInt(1);
+               fReply->Stream().AddUInt(bitmap);
+
+               XDR::WriteStream str;
+               if ((mask & CallbackAttrChange) != 0)
+                       str.AddUHyper(change);
+
+               if ((mask & CallbackAttrSize) != 0)
+                       str.AddUHyper(size);
+               fReply->Stream().AddOpaque(str);
+       }
+
+       fOpCount++;
+
+       return B_OK;
+}
+
+
+status_t
 ReplyBuilder::Recall(status_t status)
 {
        if (fStatus != B_OK)
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h 
b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h
index be85416..2a12a0d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h
@@ -22,6 +22,8 @@ public:
 
                        RPC::CallbackReply*             Reply();
 
+                       status_t                                
GetAttr(status_t status, int mask,
+                                                                               
uint64 size, uint64 change);
                        status_t                                Recall(status_t 
status);
 
 private:
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp
index c129cde..11ca0a2 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp
@@ -29,6 +29,40 @@ RequestInterpreter::~RequestInterpreter()
 
 
 status_t
+RequestInterpreter::GetAttr(FileHandle* handle, int* _mask)
+{
+       if (fLastOperation != OpCallbackGetAttr)
+               return B_BAD_VALUE;
+
+       uint32 size;
+       const void* ptr = fRequest->Stream().GetOpaque(&size);
+       handle->fSize = size;
+       memcpy(handle->fData, ptr, size);
+
+       uint32 count = fRequest->Stream().GetUInt();
+       if (count < 1) {
+               *_mask = 0;
+               return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
+       }
+
+       uint32 bitmap = fRequest->Stream().GetUInt();
+       uint32 mask = 0;
+
+       if ((bitmap & (1 << FATTR4_CHANGE)) != 0)
+               mask |= CallbackAttrChange;
+       if ((bitmap & (1 << FATTR4_SIZE)) != 0)
+               mask |= CallbackAttrSize;
+
+       *_mask = mask;
+
+       for (uint32 i = 1; i < count; i++)
+               fRequest->Stream().GetUInt();
+
+       return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
+}
+
+
+status_t
 RequestInterpreter::Recall(FileHandle* handle, bool& truncate, uint32* 
stateSeq,
        uint32* stateID)
 {
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h 
b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h
index 5febb48..a17f2ce 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h
@@ -24,6 +24,7 @@ public:
        inline  uint32          OperationCount();
        inline  uint32          Operation();
 
+                       status_t        GetAttr(FileHandle* handle, int* mask);
                        status_t        Recall(FileHandle* handle, bool& 
truncate,
                                                        uint32* stateSeq, 
uint32* stateID);
 


Other related posts: