[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 03:49:37 +0200 (CEST)

added 7 changesets to branch 'refs/remotes/pdziepak-github/nfs4'
old head: feb15cc63ce6f32dc73e8322c165266d4a11b149
new head: e2e5f06d6e736c019ed37c475ff4f68e3c4f401c

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

5a9212d: nfs4: NFS4Object::HandleErrors needs OpenState or OpenFileCookie object

9909222: nfs4: Use global open owner, check whether delegation was granted

52aaad1: nfs4: Use one open state per inode

e743e24: nfs4: Move cache management inside Inode class

4a15375: nfs4: Return delegations when asked to

bfa2037: nfs4: Reclaim delegations after server reboot

e2e5f06: nfs4: Do not sync too often if delegation is held

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

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

37 files changed, 1267 insertions(+), 418 deletions(-)
.../kernel/file_systems/nfs4/Connection.cpp        |   11 +-
src/add-ons/kernel/file_systems/nfs4/Cookie.cpp    |   93 +-------
src/add-ons/kernel/file_systems/nfs4/Cookie.h      |   26 +--
.../kernel/file_systems/nfs4/Delegation.cpp        |   66 ++++++
src/add-ons/kernel/file_systems/nfs4/Delegation.h  |   58 +++++
src/add-ons/kernel/file_systems/nfs4/FileInfo.h    |   21 ++
.../kernel/file_systems/nfs4/FileSystem.cpp        |   72 ++++--
src/add-ons/kernel/file_systems/nfs4/FileSystem.h  |   48 +++-
src/add-ons/kernel/file_systems/nfs4/Inode.cpp     |  110 +++++++--
src/add-ons/kernel/file_systems/nfs4/Inode.h       |   40 +++-
src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h  |    1 +
.../kernel/file_systems/nfs4/InodeRegular.cpp      |  185 +++++++--------
src/add-ons/kernel/file_systems/nfs4/Jamfile       |    3 +
src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h    |   26 +++
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp |   68 ++++--
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h   |    3 +-
.../kernel/file_systems/nfs4/NFS4Object.cpp        |   28 ++-
src/add-ons/kernel/file_systems/nfs4/NFS4Object.h  |    2 +-
.../kernel/file_systems/nfs4/NFS4Server.cpp        |  130 ++++++-----
src/add-ons/kernel/file_systems/nfs4/NFS4Server.h  |   11 +-
src/add-ons/kernel/file_systems/nfs4/OpenState.cpp |  187 +++++++++++++++-
src/add-ons/kernel/file_systems/nfs4/OpenState.h   |   24 +-
.../kernel/file_systems/nfs4/RPCCallback.cpp       |   11 +-
src/add-ons/kernel/file_systems/nfs4/RPCCallback.h |    4 +
.../file_systems/nfs4/RPCCallbackRequest.cpp       |    6 +
.../kernel/file_systems/nfs4/RPCCallbackServer.cpp |   10 +-
src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp |    2 +-
src/add-ons/kernel/file_systems/nfs4/RPCServer.h   |    3 +
.../kernel/file_systems/nfs4/ReplyBuilder.cpp      |   85 +++++++
.../kernel/file_systems/nfs4/ReplyBuilder.h        |   43 ++++
.../kernel/file_systems/nfs4/ReplyInterpreter.cpp  |   53 ++++-
.../kernel/file_systems/nfs4/ReplyInterpreter.h    |   12 +-
.../kernel/file_systems/nfs4/RequestBuilder.cpp    |   56 +++--
.../kernel/file_systems/nfs4/RequestBuilder.h      |   18 +-
.../file_systems/nfs4/RequestInterpreter.cpp       |   52 +++++
.../kernel/file_systems/nfs4/RequestInterpreter.h  |   54 +++++
.../kernel/file_systems/nfs4/kernel_interface.cpp  |   63 +++---

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

Commit:      5a9212d612306df5df3ca1b2f0eb0112c57e2def

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Sun Aug  5 13:44:16 2012 UTC

nfs4: NFS4Object::HandleErrors needs OpenState or OpenFileCookie object

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
index a95c3b9..cb89881 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
@@ -539,7 +539,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (HandleErrors(reply.NFS4Error(), serv))
+               if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
                        continue;
 
                // Verify if the file we want to open is the file this Inode
@@ -592,7 +592,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* 
state, uint64 position,
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (HandleErrors(reply.NFS4Error(), serv, cookie))
+               if (HandleErrors(reply.NFS4Error(), serv, cookie, state))
                        continue;
 
                reply.PutFH();
@@ -625,7 +625,7 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* 
state, uint64 position,
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (HandleErrors(reply.NFS4Error(), serv, cookie))
+               if (HandleErrors(reply.NFS4Error(), serv, cookie, state))
                        continue;
 
                reply.PutFH();
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
index e5db3e6..73c5e3a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
@@ -15,7 +15,7 @@
 
 bool
 NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
-       OpenFileCookie* cookie)
+       OpenFileCookie* cookie, OpenState* state)
 {
        uint32 leaseTime;
 
@@ -62,8 +62,14 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
                // server has rebooted, reclaim share and try again
                case NFS4ERR_STALE_CLIENTID:
                case NFS4ERR_STALE_STATEID:
-                       
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID);
-                       return true;
+                       if (cookie != NULL) {
+                               
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID);
+                               return true;
+                       } else if (state != NULL) {
+                               
fFileSystem->NFSServer()->ServerRebooted(state->fClientID);
+                               return true;
+                       }
+                       return false;
 
                // FileHandle has expired
                case NFS4ERR_FHEXPIRED:
@@ -82,6 +88,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
                        if (cookie != NULL) {
                                
fFileSystem->NFSServer()->ClientId(cookie->fClientID, true);
                                return true;
+                       } else if (state != NULL) {
+                               
fFileSystem->NFSServer()->ClientId(state->fClientID, true);
+                               return true;
                        }
                        return false;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h
index 7ffcf4b..79df6f1 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h
@@ -19,7 +19,7 @@ class OpenState;
 class NFS4Object {
 public:
        bool            HandleErrors(uint32 nfs4Error, RPC::Server* serv,
-                                       OpenFileCookie* cookie = NULL);
+                                       OpenFileCookie* cookie = NULL, 
OpenState* state = NULL);
 
        status_t        ConfirmOpen(const FileHandle& fileHandle, OpenState* 
state);
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp 
b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
index 26a4df5..4959199 100644
--- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
@@ -101,7 +101,7 @@ OpenState::Close()
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (HandleErrors(reply.NFS4Error(), serv))
+               if (HandleErrors(reply.NFS4Error(), serv, NULL, this))
                        continue;
 
                reply.PutFH();

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

Commit:      990922235b448d860c0dbcf596c21bfdbeab8831

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Sun Aug  5 17:37:58 2012 UTC

nfs4: Use global open owner, check whether delegation was granted

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
index 25ed74b..cc4611b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp
@@ -551,7 +551,7 @@ ConnectionBase::Disconnect()
 
 
 status_t
-ConnectionListener::Listen(ConnectionListener** _listener, uint16 port)
+ConnectionListener::Listen(ConnectionListener** listener, uint16 port)
 {
        int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sock < 0)
@@ -577,16 +577,13 @@ ConnectionListener::Listen(ConnectionListener** 
_listener, uint16 port)
        address.fProtocol = IPPROTO_TCP;
        memset(&address.fAddress, 0, sizeof(address.fAddress));
 
-       ConnectionListener* listener;
-       listener = new(std::nothrow) ConnectionListener(address);
-       if (listener == NULL) {
+       *listener = new(std::nothrow) ConnectionListener(address);
+       if (*listener == NULL) {
                close(sock);
                return B_NO_MEMORY;
        }
 
-       listener->fSocket = sock;
-
-       *_listener = listener;
+       (*listener)->fSocket = sock;
 
        return B_OK;
 }
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
index 95e95ae..f4eb990 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
@@ -27,10 +27,16 @@ FileSystem::FileSystem()
        fPrev(NULL),
        fOpenFiles(NULL),
        fOpenCount(0),
+       fOpenOwnerSequence(0),
        fPath(NULL),
        fRoot(NULL),
        fId(1)
 {
+       fOpenOwner = rand();
+       fOpenOwner <<= 32;
+       fOpenOwner |= rand();
+
+       mutex_init(&fOpenOwnerLock, NULL);
        mutex_init(&fOpenLock, NULL);
 }
 
@@ -40,6 +46,7 @@ FileSystem::~FileSystem()
        NFSServer()->RemoveFileSystem(this);
 
        mutex_destroy(&fOpenLock);
+       mutex_destroy(&fOpenOwnerLock);
 
        free(const_cast<char*>(fPath));
        delete fRoot;
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
index 7b99ef7..4c5df28 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
@@ -51,6 +51,10 @@ public:
        inline  dev_t                           DevId() const;
        inline  InodeIdMap*                     InoIdMap();
 
+       inline  uint64                          OpenOwner() const;
+       inline  uint32                          OpenOwnerSequenceLock();
+       inline  void                            OpenOwnerSequenceUnlock(bool 
increment = true);
+
                        FileSystem*                     fNext;
                        FileSystem*                     fPrev;
 private:
@@ -62,6 +66,10 @@ private:
                        uint32                          fOpenCount;
                        mutex                           fOpenLock;
 
+                       uint64                          fOpenOwner;
+                       uint32                          fOpenOwnerSequence;
+                       mutex                           fOpenOwnerLock;
+
                        uint32                          fExpireType;
                        uint32                          fSupAttrs[2];
 
@@ -163,5 +171,29 @@ FileSystem::InoIdMap()
 }
 
 
+inline uint64
+FileSystem::OpenOwner() const
+{
+       return fOpenOwner;
+}
+
+
+inline uint32
+FileSystem::OpenOwnerSequenceLock()
+{
+       mutex_lock(&fOpenOwnerLock);
+       return fOpenOwnerSequence;
+}
+
+
+inline void
+FileSystem::OpenOwnerSequenceUnlock(bool increment = true)
+{
+       if (increment)
+               fOpenOwnerSequence++;
+       mutex_unlock(&fOpenOwnerLock);
+}
+
+
 #endif // FILESYSTEM_H
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
index c0abd7b..1887ee2 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
@@ -207,11 +207,32 @@ enum OpenClaim {
        CLAIM_DELEGATE_PREV             = 3
 };
 
+enum OpenDelegation {
+       OPEN_DELEGATE_NONE              = 0,
+       OPEN_DELEGATE_READ              = 1,
+       OPEN_DELEGATE_WRITE             = 2
+};
+
+struct OpenDelegationData {
+       OpenDelegation  fType;
+
+       uint32                  fStateSeq;
+       uint32                  fStateID[3];
+
+       bool                    fRecall;
+       uint64                  fSpaceLimit;
+};
+
 enum OpenFlags {
        OPEN4_RESULT_CONFIRM            = 2,
        OPEN4_RESULT_LOCKTYPE_POSIX     = 4
 };
 
+enum {
+       NFS_LIMIT_SIZE          = 1,
+       NFS_LIMIT_BLOCKS        = 2
+};
+
 struct ChangeInfo {
        bool    fAtomic;
        uint64  fBefore;
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
index cb89881..1c6722b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
@@ -389,6 +389,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
        status_t result;
 
        bool badOwner = false;
+       OpenDelegationData delegation;
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                state->fClientID = fFileSystem->NFSServer()->ClientId();
 
@@ -396,8 +398,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
                Request request(serv);
                RequestBuilder& req = request.Builder();
 
-               state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1);
-
                req.PutFH(fInfo.fHandle);
 
                AttrValue cattr[4];
@@ -427,9 +427,9 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
                        i++;
                }
 
-               req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode),
-                       state->fClientID, OPEN4_CREATE, state->fOwnerID, name, 
cattr,
-                       i, (mode & O_EXCL) == O_EXCL);
+               req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
+                       state->fClientID, OPEN4_CREATE, 
fFileSystem->OpenOwner(), name,
+                       cattr, i, (mode & O_EXCL) == O_EXCL);
 
                req.GetFH();
 
@@ -439,22 +439,29 @@ NFS4Inode::CreateFile(const char* name, int mode, int 
perms,
                }
 
                result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter& reply = request.Reply();
 
                if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
+                       fFileSystem->OpenOwnerSequenceUnlock();
+                       sequence = fFileSystem->OpenOwnerSequenceLock();
+
                        badOwner = true;
                        continue;
                }
                if (HandleErrors(reply.NFS4Error(), serv))
                        continue;
 
+               fFileSystem->OpenOwnerSequenceUnlock();
+
                reply.PutFH();
 
                result = reply.Open(state->fStateID, &state->fStateSeq, 
&confirm,
-                       &changeInfo->fBefore, &changeInfo->fAfter, 
&changeInfo->fAtomic);
+                       &delegation, changeInfo);
                if (result != B_OK)
                        return result;
 
@@ -488,8 +495,10 @@ NFS4Inode::CreateFile(const char* name, int mode, int 
perms,
 status_t
 NFS4Inode::OpenFile(OpenState* state, int mode)
 {
+       OpenDelegationData delegation;
        bool confirm;
        status_t result;
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                state->fClientID = fFileSystem->NFSServer()->ClientId();
 
@@ -497,8 +506,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
                Request request(serv);
                RequestBuilder& req = request.Builder();
 
-               state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1);
-
                // Since we are opening the file using a pair (parentFH, name) 
we
                // need to check for race conditions.
                if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
@@ -526,22 +533,27 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
                        attr.fAttribute = FATTR4_SIZE;
                        attr.fFreePointer = false;
                        attr.fData.fValue64 = 0;
-                       req.Open(CLAIM_NULL, state->fSequence++, 
sModeToAccess(mode),
-                               state->fClientID, OPEN4_CREATE, 
state->fOwnerID, fInfo.fName,
-                               &attr, 1, false);
+                       req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
+                               state->fClientID, OPEN4_CREATE, 
fFileSystem->OpenOwner(), 
+                               fInfo.fName, &attr, 1, false);
                } else
-               req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode),
-                       state->fClientID, OPEN4_NOCREATE, state->fOwnerID, 
fInfo.fName);
+               req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), 
state->fClientID,
+                       OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName);
+               req.GetFH();
 
                result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter& reply = request.Reply();
 
                if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
                        continue;
 
+               fFileSystem->OpenOwnerSequenceUnlock();
+
                // Verify if the file we want to open is the file this Inode
                // represents.
                if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
@@ -558,7 +570,12 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
                }
 
                reply.PutFH();
-               result = reply.Open(state->fStateID, &state->fStateSeq, 
&confirm);
+               result = reply.Open(state->fStateID, &state->fStateSeq, 
&confirm,
+                       &delegation);
+
+               FileHandle handle;
+               reply.GetFH(&handle);
+
                if (result != B_OK)
                        return result;
 
@@ -570,6 +587,9 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
        if (confirm)
                return ConfirmOpen(fInfo.fHandle, state);
 
+       if (delegation.fType != OPEN_DELEGATE_NONE)
+               dprintf("GOT A DELEGATION!\n");
+
        return B_OK;
 }
 
@@ -891,6 +911,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, 
uint64* position,
 status_t
 NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
 {
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                MutexLocker ownerLocker(lockInfo->fOwner->fLock);
 
@@ -899,11 +920,13 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* 
lockInfo, bool wait)
                RequestBuilder& req = request.Builder();
 
                req.PutFH(fInfo.fHandle);
-               req.Lock(cookie, lockInfo);
+               req.Lock(cookie, lockInfo, sequence);
 
                status_t result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter &reply = request.Reply();
 
@@ -912,13 +935,16 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* 
lockInfo, bool wait)
 
                ownerLocker.Unlock();
                if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
+                       fFileSystem->OpenOwnerSequenceUnlock();
                        snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
                                B_RELATIVE_TIMEOUT);
+                       sequence = fFileSystem->OpenOwnerSequenceLock();
                        continue;
                }
                if (HandleErrors(reply.NFS4Error(), serv, cookie))
                        continue;
 
+               fFileSystem->OpenOwnerSequenceUnlock();
                if (result != B_OK)
                        return result;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
index 73c5e3a..073fd01 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
@@ -103,6 +103,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* 
serv,
 status_t
 NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state)
 {
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                RPC::Server* serv = fFileSystem->Server();
                Request request(serv);
@@ -110,17 +111,21 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* 
state)
                RequestBuilder& req = request.Builder();
 
                req.PutFH(fh);
-               req.OpenConfirm(state->fSequence++, state->fStateID, 
state->fStateSeq);
+               req.OpenConfirm(sequence, state->fStateID, state->fStateSeq);
 
                status_t result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter& reply = request.Reply();
 
                if (HandleErrors(reply.NFS4Error(), serv))
                        continue;
 
+               fFileSystem->OpenOwnerSequenceUnlock();
+
                reply.PutFH();
                result = reply.OpenConfirm(&state->fStateSeq);
                if (result != B_OK)
diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp 
b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
index 4959199..236ff7c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp
@@ -15,11 +15,8 @@
 #include "Request.h"
 
 
-vint64 OpenState::fLastOwnerID = 0;
-
 OpenState::OpenState()
        :
-       fSequence(0),
        fOpened(false)
 {
        mutex_init(&fLock, NULL);
@@ -46,27 +43,34 @@ OpenState::Reclaim(uint64 newClientID)
        fClientID = newClientID;
 
        bool confirm;
+       OpenDelegationData delegation;
+
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                RPC::Server* server = fFileSystem->Server();
                Request request(server);
                RequestBuilder& req = request.Builder();
 
                req.PutFH(fInfo.fHandle);
-               req.Open(CLAIM_PREVIOUS, fSequence++, sModeToAccess(fMode), 
newClientID,
-                       OPEN4_NOCREATE, fOwnerID, NULL);
+               req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), 
newClientID,
+                       OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL);
 
                status_t result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter& reply = request.Reply();
 
                if (HandleErrors(reply.NFS4Error(), server))
                        continue;
 
+               fFileSystem->OpenOwnerSequenceUnlock();
+
                reply.PutFH();
 
-               result = reply.Open(fStateID, &fStateSeq, &confirm);
+               result = reply.Open(fStateID, &fStateSeq, &confirm, 
&delegation);
                if (result != B_OK)
                        return result;
        } while (true);
@@ -87,24 +91,29 @@ OpenState::Close()
        MutexLocker _(fLock);
        fOpened = false;
 
+       uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
        do {
                RPC::Server* serv = fFileSystem->Server();
                Request request(serv);
                RequestBuilder& req = request.Builder();
 
                req.PutFH(fInfo.fHandle);
-               req.Close(fSequence++, fStateID, fStateSeq);
+               req.Close(sequence, fStateID, fStateSeq);
 
                status_t result = request.Send();
-               if (result != B_OK)
+               if (result != B_OK) {
+                       fFileSystem->OpenOwnerSequenceUnlock(false);
                        return result;
+               }
 
                ReplyInterpreter& reply = request.Reply();
 
                if (HandleErrors(reply.NFS4Error(), serv, NULL, this))
                        continue;
+               fFileSystem->OpenOwnerSequenceUnlock();
 
                reply.PutFH();
+
                return reply.Close();
        } while (true);
 }
diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h 
b/src/add-ons/kernel/file_systems/nfs4/OpenState.h
index 00da687..ecf10a8 100644
--- a/src/add-ons/kernel/file_systems/nfs4/OpenState.h
+++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h
@@ -28,14 +28,8 @@ struct OpenState : public NFS4Object, public 
KernelReferenceable {
                        uint32                  fStateID[3];
                        uint32                  fStateSeq;
 
-                       uint32                  fSequence;
-
-                       uint64                  fOwnerID;
-       static  vint64                  fLastOwnerID;
-
                        bool                    fOpened;
 
-
                        status_t                Reclaim(uint64 newClientID);
 
                        status_t                Close();
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
index 651ccc5..5a64700 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
@@ -287,6 +287,7 @@ CallbackServer::ListenerThread()
 {
        while (fThreadRunning) {
                Connection* connection;
+
                status_t result = fListener->AcceptConnection(&connection);
                if (result != B_OK) {
                        fThreadRunning = false;
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp 
b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
index 56ba582..2b74de3 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
@@ -266,8 +266,8 @@ ReplyInterpreter::LockU(LockInfo* linfo)
 
 
 status_t
-ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before,
-       uint64* _after, bool* _atomic)
+ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm,
+       OpenDelegationData* delegData, ChangeInfo* changeInfo)
 {
        status_t res = _OperationError(OpOpen);
        if (res != B_OK)
@@ -280,14 +280,13 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* 
confirm, uint64* _before,
 
        // change info
        bool atomic = fReply->Stream().GetBoolean();
-       if (_atomic != NULL)
-               *_atomic = atomic;
        uint64 before = fReply->Stream().GetUHyper();
-       if (_before != NULL)
-               *_before = before;
        uint64 after = fReply->Stream().GetUHyper();
-       if (_after != NULL)
-               *_after = after;
+       if (changeInfo != NULL) {
+               changeInfo->fAtomic = atomic;
+               changeInfo->fBefore = before;
+               changeInfo->fAfter = after;
+       }
 
        uint32 flags = fReply->Stream().GetUInt();
        *confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM;
@@ -298,7 +297,41 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* 
confirm, uint64* _before,
                fReply->Stream().GetUInt();
 
        // delegation info
+       uint32 delegation = fReply->Stream().GetUInt();
+       if (delegation == OPEN_DELEGATE_NONE) {
+               delegData->fType = OPEN_DELEGATE_NONE;
+               return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
+       }
+
+       delegData->fStateSeq = fReply->Stream().GetUInt();
+       delegData->fStateID[0] = fReply->Stream().GetUInt();
+       delegData->fStateID[1] = fReply->Stream().GetUInt();
+       delegData->fStateID[2] = fReply->Stream().GetUInt();
+
+       delegData->fRecall = fReply->Stream().GetBoolean();
+
+       switch (delegation) {
+               case OPEN_DELEGATE_READ:
+                       delegData->fType = OPEN_DELEGATE_READ;
+                       break;
+               case OPEN_DELEGATE_WRITE:
+                       delegData->fType = OPEN_DELEGATE_WRITE;
+
+                       int32 limitBy = fReply->Stream().GetInt();
+                       if (limitBy == NFS_LIMIT_SIZE)
+                               delegData->fSpaceLimit = 
fReply->Stream().GetUHyper();
+                       else if (limitBy == NFS_LIMIT_BLOCKS) {
+                               uint32 numBlocks = fReply->Stream().GetUInt();
+                               delegData->fSpaceLimit = 
fReply->Stream().GetUInt() * numBlocks;
+                       }
+                       break;
+       }
+
+       // ACE data
+       fReply->Stream().GetUInt();
        fReply->Stream().GetUInt();
+       fReply->Stream().GetUInt();
+       fReply->Stream().GetOpaque(NULL);
 
        return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
 }
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h 
b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
index ed3a269..892e34c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
@@ -81,8 +81,8 @@ public:
        inline  status_t        LookUpUp();
        inline  status_t        Nverify();
                        status_t        Open(uint32* id, uint32* seq, bool* 
confirm,
-                                                       uint64* before = NULL, 
uint64* after = NULL,
-                                                       bool* atomic = NULL);
+                                                       OpenDelegationData* 
delegData,
+                                                       ChangeInfo* changeInfo 
= NULL);
                        status_t        OpenConfirm(uint32* stateSeq);
        inline  status_t        PutFH();
        inline  status_t        PutRootFH();
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
index c9d2408..c6a0e80 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
@@ -186,7 +186,8 @@ RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
 
 
 status_t
-RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
+RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence,
+       bool reclaim)
 {
        if (fProcedure != ProcCompound)
                return B_BAD_VALUE;
@@ -213,7 +214,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* 
lock, bool reclaim)
                else
                        state = cookie->fWriteState;
 
-               fRequest->Stream().AddUInt(state->fSequence++);
+               fRequest->Stream().AddUInt(sequence);
                fRequest->Stream().AddUInt(state->fStateSeq);
                fRequest->Stream().AddUInt(state->fStateID[0]);
                fRequest->Stream().AddUInt(state->fStateID[1]);
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h 
b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
index a8f2d76..13db57d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
@@ -41,7 +41,8 @@ public:
                        status_t                                GetFH();
                        status_t                                Link(const 
char* name);
                        status_t                                
Lock(OpenFileCookie* cookie,
-                                                                               
LockInfo* lock, bool reclaim = false);
+                                                                               
LockInfo* lock, uint32 sequence,
+                                                                               
bool reclaim = false);
                        status_t                                LockT(LockType 
type, uint64 pos,
                                                                                
uint64 len, OpenFileCookie* cookie);
                        status_t                                LockU(LockInfo* 
lock);

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

Commit:      52aaad172fd93ba9b286d237dd299746e6458e1b

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Sun Aug  5 20:07:44 2012 UTC

nfs4: Use one open state per inode

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp
index 83d0336..a2970b7 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp
@@ -161,7 +161,6 @@ OpenFileCookie::GetLockOwner(uint32 owner)
        if (current == NULL)
                return NULL;
 
-       current->fClientId = fClientID;
        current->fNext = fLockOwners;
        if (fLockOwners != NULL)
                fLockOwners->fPrev = current;
diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h 
b/src/add-ons/kernel/file_systems/nfs4/Cookie.h
index baeca67..4af8899 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h
@@ -71,10 +71,7 @@ struct Cookie {
 };
 
 struct OpenFileCookie : public Cookie {
-                       uint64                  fClientID;
-
-                       OpenState*              fReadState;
-                       OpenState*              fWriteState;
+                       OpenState*              fOpenState;
 
                        uint32                  fMode;
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h 
b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
new file mode 100644
index 0000000..31fea04
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+#ifndef DELEGATION_H
+#define DELEGATION_H
+
+
+#include <lock.h>
+#include <SupportDefs.h>
+
+#include "NFS4Object.h"
+
+
+class Delegation : public NFS4Object {
+public:
+                                               Delegation(OpenDelegationData 
data, Inode* inode,
+                                                       uint64 clientID);
+                                               ~Delegation();
+
+       status_t                        Write(void* buffer, uint32* size);
+       status_t                        Read(void* buffer, uint32* size);
+
+       // TODO: locks
+
+       status_t                        Reclaim(uint64 newClientID);
+
+       status_t                        GiveUp(bool flush);
+
+private:
+       uint64                          fClientID;
+       OpenDelegationData      fData;
+       Inode*                          fInode;
+
+       rw_lock                         fLock;
+};
+
+
+#endif // DELEGATION_H
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index 007890e..edfbddf 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -24,8 +24,7 @@ Inode::Inode()
        :
        fCache(NULL),
        fFileCache(NULL),
-       fWriteState(NULL),
-       fReadState(NULL),
+       fOpenState(NULL),
        fWriteDirty(false)
 {
        mutex_init(&fStateLock, NULL);
@@ -530,7 +529,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
        }
 
        MutexLocker stateLocker(fStateLock);
-       result = NFS4Inode::WriteStat(fWriteState, attr, i);
+       result = NFS4Inode::WriteStat(fOpenState, attr, i);
        stateLocker.Unlock();
 
        fMetaCache.InvalidateStat();
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index e4bfa9a..58250e7 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -14,6 +14,8 @@
 #include "OpenState.h"
 
 
+class Delegation;
+
 class Inode : public NFS4Inode {
 public:
        static                  status_t        CreateInode(FileSystem* fs, 
const FileInfo& fi,
@@ -25,6 +27,8 @@ public:
        inline                  const char*     Name() const;
        inline                  FileSystem*     GetFileSystem() const;
 
+       inline                  void            SetOpenState(OpenState* state);
+
        inline                  void*           FileCache();
                                        status_t        RevalidateFileCache();
 
@@ -93,17 +97,20 @@ protected:
 
        static inline   ino_t           FileIdToInoT(uint64 fileid);
 
+private:
                                        uint32          fType;
 
                                        MetadataCache   fMetaCache;
                                        DirectoryCache* fCache;
 
+                                       rw_lock         fDelegationLock;
+                                       Delegation*     fDelegation;
+
                                        uint64          fChange;
                                        void*           fFileCache;
                                        mutex           fFileCacheLock;
 
-                                       OpenState*      fWriteState;
-                                       OpenState*      fReadState;
+                                       OpenState*      fOpenState;
                                        mutex           fStateLock;
 
                                        bool            fWriteDirty;
@@ -156,5 +163,13 @@ Inode::FileCache()
 }
 
 
+inline void
+Inode::SetOpenState(OpenState* state)
+{
+       MutexLocker _(fStateLock);
+       fOpenState = state;
+}
+
+
 #endif // INODE_H
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h 
b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h
index 63ec1b0..2a29e07 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h
@@ -52,6 +52,7 @@ inline status_t
 InodeIdMap::AddEntry(const FileInfo& fi, ino_t id)
 {
        MutexLocker _(fLock);
+       fMap.Remove(id);
        return fMap.Insert(id, fi);
 }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index 51d4122..c82c507 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -70,44 +70,19 @@ Inode::Create(const char* name, int mode, int perms, 
OpenFileCookie* cookie,
        cookie->fLocks = NULL;
 
        MutexLocker _(fStateLock);
-       int openMode = mode & O_RWMASK;
 
-       if (openMode == O_WRONLY || openMode == O_RDWR) {
-               OpenState* state = new OpenState;
-               status_t result = CreateState(name, O_WRONLY, perms, state);
-               if (result != B_OK)
-                       return result;
-
-               fWriteState = state;
-               *id = FileIdToInoT(cookie->fWriteState->fInfo.fFileId);
-               cookie->fWriteState = fWriteState;
-       }
-
-       if (openMode == O_RDONLY || openMode == O_RDWR) {
-               OpenState* state = new OpenState;
-               state->fInfo = fInfo;
-               state->fFileSystem = fFileSystem;
-
-               status_t result;
-               if (openMode == O_RDWR)
-                       result = OpenFile(state, O_RDONLY);
-               else
-                       result = CreateState(name, O_RDONLY, perms, state);
+       OpenState* state = new OpenState;
+       status_t result = CreateState(name, mode, perms, state);
+       if (result != B_OK)
+               return result;
 
-               if (result != B_OK) {
-                       if (fWriteState != NULL)
-                               if (fWriteState->ReleaseReference() == 1)
-                                       fWriteState = NULL;
-                       return result;
-               }
+       cookie->fOpenState = state;
+       fOpenState = state;
 
-               fReadState = state;
-               *id = FileIdToInoT(cookie->fReadState->fInfo.fFileId);
-               cookie->fReadState = fReadState;
-       }
+       *id = FileIdToInoT(state->fInfo.fFileId);
+       cookie->fOpenState = fOpenState;
 
        cookie->fFileSystem = fFileSystem;
-       cookie->fClientID = fFileSystem->NFSServer()->ClientId();
 
        fFileSystem->AddOpenFile(cookie);
        fFileSystem->Root()->MakeInfoInvalid();
@@ -120,55 +95,33 @@ status_t
 Inode::Open(int mode, OpenFileCookie* cookie)
 {
        MutexLocker _(fStateLock);
-       int openMode = mode & O_RWMASK;
 
-       if (openMode == O_WRONLY || openMode == O_RDWR) {
-               if (fWriteState == NULL) {
-                       OpenState* state = new OpenState;
-                       if (state == NULL)
-                               return B_NO_MEMORY;
+       if (fOpenState == NULL) {
+               OpenState* state = new OpenState;
+               if (state == NULL)
+                       return B_NO_MEMORY;
+
+               state->fInfo = fInfo;
+               state->fFileSystem = fFileSystem;
+               status_t result = OpenFile(state, mode, NULL);
+               if (result != B_OK)
+                       return result;
 
-                       state->fInfo = fInfo;
-                       state->fFileSystem = fFileSystem;
-                       status_t result = OpenFile(state, O_WRONLY);
+               fOpenState = state;
+       } else {
+               int newMode = mode & O_RWMASK;
+               int oldMode = fOpenState->fMode & O_RWMASK;
+               if (oldMode != newMode && oldMode != O_RDWR) {
+                       status_t result = OpenFile(fOpenState, O_RDWR, NULL);
                        if (result != B_OK)
                                return result;
-
-                       fWriteState = state;
-               } else
-                       fWriteState->AcquireReference();
-
-               cookie->fWriteState = fWriteState;
+                       fOpenState->fMode = O_RDWR;
+               }
+               fOpenState->AcquireReference();
        }
 
-       if (openMode == O_RDONLY || openMode == O_RDWR) {
-               if (fReadState == NULL) {
-                       OpenState* state = new OpenState;
-                       if (state == NULL) {
-                               if (fWriteState != NULL)
-                                       if (fWriteState->ReleaseReference() == 
1)
-                                               fWriteState = NULL;
-                               return B_NO_MEMORY;
-                       }
-
-                       state->fInfo = fInfo;
-                       state->fFileSystem = fFileSystem;
-                       status_t result = OpenFile(state, O_RDONLY);
-                       if (result != B_OK) {
-                               if (fWriteState != NULL)
-                                       if (fWriteState->ReleaseReference() == 
1)
-                                               fWriteState = NULL;
-                               return result;
-                       }
-
-                       fReadState = state;
-               } else
-                       fReadState->AcquireReference();
+       cookie->fOpenState = fOpenState;
 
-               cookie->fReadState = fReadState;
-       }
-
-       cookie->fClientID = fFileSystem->NFSServer()->ClientId();
        cookie->fFileSystem = fFileSystem;
        cookie->fMode = mode;
        cookie->fLocks = NULL;
@@ -185,13 +138,9 @@ Inode::Close(OpenFileCookie* cookie)
        fFileSystem->RemoveOpenFile(cookie);
 
        MutexLocker _(fStateLock);
-       if (cookie->fWriteState != NULL)
-               if (cookie->fWriteState->ReleaseReference() == 1)
-                       fWriteState = NULL;
-
-       if (cookie->fReadState != NULL)
-               if (cookie->fReadState->ReleaseReference() == 1)
-                       fReadState = NULL;
+       if (cookie->fOpenState != NULL)
+               if (cookie->fOpenState->ReleaseReference() == 1)
+                       fOpenState = NULL;
 
        return B_OK;
 }
@@ -207,7 +156,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* 
buffer, size_t* _length,
        status_t result;
        while (size < *_length && !*eof) {
                uint32 len = *_length - size;
-               result = ReadFile(cookie, fReadState, pos + size, &len,
+               result = ReadFile(cookie, fOpenState, pos + size, &len,
                        reinterpret_cast<char*>(buffer) + size, eof);
                if (result != B_OK) {
                        if (size == 0)
@@ -236,7 +185,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* 
_buffer,
 
        while (size < *_length) {
                uint32 len = *_length - size;
-               status_t result = WriteFile(cookie, fWriteState, pos + size, 
&len,
+               status_t result = WriteFile(cookie, fOpenState, pos + size, 
&len,
                        buffer + size);
                if (result != B_OK) {
                        if (size == 0)
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
index 1c6722b..c2208fb 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp
@@ -493,9 +493,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
 
 
 status_t
-NFS4Inode::OpenFile(OpenState* state, int mode)
+NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
 {
-       OpenDelegationData delegation;
        bool confirm;
        status_t result;
        uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
@@ -571,7 +570,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
 
                reply.PutFH();
                result = reply.Open(state->fStateID, &state->fStateSeq, 
&confirm,
-                       &delegation);
+                       delegation);
 
                FileHandle handle;
                reply.GetFH(&handle);
@@ -587,9 +586,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
        if (confirm)
                return ConfirmOpen(fInfo.fHandle, state);
 
-       if (delegation.fType != OPEN_DELEGATE_NONE)
-               dprintf("GOT A DELEGATION!\n");
-
        return B_OK;
 }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
index 027f6a4..dbcf90a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
@@ -33,7 +33,7 @@ protected:
                        status_t        LookUp(const char* name, uint64* 
change, uint64* fileID,
                                                        FileHandle* handle);
 
-                       status_t        Link(Inode* dir, const char* name,
+                       status_t        Link(Inode* dir, const char* name,s
                                                        ChangeInfo* changeInfo);
 
        static  status_t        Rename(Inode* from, Inode* to, const char* 
fromName,
@@ -47,7 +47,8 @@ protected:
                        status_t        CreateFile(const char* name, int mode, 
int perms,
                                                        OpenState* state, 
ChangeInfo* changeInfo,
                                                        uint64* fileID, 
FileHandle* handle);
-                       status_t        OpenFile(OpenState* state, int mode);
+                       status_t        OpenFile(OpenState* state, int mode,
+                                                       OpenDelegationData* 
delegation);
 
                        status_t        ReadFile(OpenFileCookie* cookie, 
OpenState* state,
                                                        uint64 position, 
uint32* length, void* buffer,
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
index 073fd01..327c075 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp
@@ -19,6 +19,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
 {
        uint32 leaseTime;
 
+       if (cookie != NULL)
+               state = cookie->fOpenState;
+
        switch (nfs4Error) {
                case NFS4_OK:
                        return false;
@@ -62,10 +65,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
                // server has rebooted, reclaim share and try again
                case NFS4ERR_STALE_CLIENTID:
                case NFS4ERR_STALE_STATEID:
-                       if (cookie != NULL) {
-                               
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID);
-                               return true;
-                       } else if (state != NULL) {
+                       if (state != NULL) {
                                
fFileSystem->NFSServer()->ServerRebooted(state->fClientID);
                                return true;
                        }
@@ -85,10 +85,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
 
                // lease has expired
                case NFS4ERR_EXPIRED:
-                       if (cookie != NULL) {
-                               
fFileSystem->NFSServer()->ClientId(cookie->fClientID, true);
-                               return true;
-                       } else if (state != NULL) {
+                       if (state != NULL) {
                                
fFileSystem->NFSServer()->ClientId(state->fClientID, true);
                                return true;
                        }
@@ -121,7 +118,7 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* 
state)
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (HandleErrors(reply.NFS4Error(), serv))
+               if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
                        continue;
 
                fFileSystem->OpenOwnerSequenceUnlock();
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index 412a653..ec38c3a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -59,7 +59,6 @@ NFS4Server::ServerRebooted(uint64 clientId)
        while (fs != NULL) {
                OpenFileCookie* current = fs->OpenFilesLock();
                while (current != NULL) {
-                       current->fClientID = fClientId;
                        _ReclaimOpen(current);
                        _ReclaimLocks(current);
                        current = current->fNext;
@@ -75,10 +74,8 @@ NFS4Server::ServerRebooted(uint64 clientId)
 status_t
 NFS4Server::_ReclaimOpen(OpenFileCookie* cookie)
 {
-       if (cookie->fWriteState != NULL)
-               cookie->fWriteState->Reclaim(fClientId);
-       if (cookie->fReadState != NULL)
-               cookie->fReadState->Reclaim(fClientId);
+       if (cookie->fOpenState != NULL)
+               cookie->fOpenState->Reclaim(fClientId);
 
        return B_OK;
 }
@@ -100,10 +97,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
                        Request request(fServer);
                        RequestBuilder& req = request.Builder();
 
-                       if (cookie->fWriteState != NULL)
-                               req.PutFH(cookie->fWriteState->fInfo.fHandle);
-                       else
-                               req.PutFH(cookie->fReadState->fInfo.fHandle);
+                       req.PutFH(cookie->fOpenState->fInfo.fHandle);
                        req.Lock(cookie, linfo, true);
 
                        status_t result = request.Send();
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp 
b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
index 2b74de3..b26082d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp
@@ -298,6 +298,10 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* 
confirm,
 
        // delegation info
        uint32 delegation = fReply->Stream().GetUInt();
+       OpenDelegationData data;
+       if (delegData == NULL)
+               delegData = &data;
+
        if (delegation == OPEN_DELEGATE_NONE) {
                delegData->fType = OPEN_DELEGATE_NONE;
                return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
index c6a0e80..c05b873 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
@@ -173,14 +173,11 @@ void
 RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
        OpenFileCookie* cookie, LockOwner* owner)
 {
-       stream.AddUHyper(cookie->fClientID);
+       stream.AddUHyper(cookie->fOpenState->fClientID);
 
        uint64 lockOwner[2];
        lockOwner[0] = owner->fOwner;
-       if (cookie->fWriteState != NULL)
-               lockOwner[1] = cookie->fWriteState->fInfo.fFileId;
-       else
-               lockOwner[1] = cookie->fReadState->fInfo.fFileId;
+       lockOwner[1] = cookie->fOpenState->fInfo.fFileId;
        stream.AddOpaque(lockOwner, sizeof(lockOwner));
 }
 
@@ -208,11 +205,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* 
lock, uint32 sequence,
                fRequest->Stream().AddBoolean(true);                    // new 
lock owner
 
                // open seq stateid
-               OpenState* state;
-               if (lock->fType == READ_LT || lock->fType == READW_LT)
-                       state = cookie->fReadState;
-               else
-                       state = cookie->fWriteState;
+               OpenState* state = cookie->fOpenState;
 
                fRequest->Stream().AddUInt(sequence);
                fRequest->Stream().AddUInt(state->fStateSeq);
@@ -258,7 +251,7 @@ RequestBuilder::LockT(LockType type, uint64 pos, uint64 len,
        fRequest->Stream().AddUHyper(pos);
        fRequest->Stream().AddUHyper(len);
 
-       fRequest->Stream().AddUHyper(cookie->fClientID);
+       fRequest->Stream().AddUHyper(cookie->fOpenState->fClientID);
 
        uint32 owner = find_thread(NULL);
        fRequest->Stream().AddOpaque(&owner, sizeof(owner));
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 95b8bd8..d1a447b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -400,10 +400,24 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* 
name, int openMode,
                return result;
        }
 
-       void* ptr;
-       result = get_vnode(volume, *_newVnodeID, &ptr);
-       if (result != B_OK)
-               delete cookie;
+       Inode* child;
+       result = get_vnode(volume, *_newVnodeID, 
reinterpret_cast<void**>(&child));
+       if (result != B_OK) {
+               result = inode->GetFileSystem()->GetInode(*_newVnodeID, &child);
+               if (result != B_OK) {
+                       delete cookie;
+                       return result;
+               }
+
+               result = new_vnode(volume, *_newVnodeID, child, 
&gNFSv4VnodeOps);
+               if (result != B_OK) {
+                       delete child;
+                       delete cookie;
+                       return result;
+               }
+       }
+
+       child->SetOpenState(cookie->fOpenState);
 
        return result;
 }

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

Commit:      e743e243206509ccb41281a1aab140597bfb40b7

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Sun Aug  5 20:49:44 2012 UTC

nfs4: Move cache management inside Inode class

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index edfbddf..a573f49 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -24,6 +24,7 @@ Inode::Inode()
        :
        fCache(NULL),
        fFileCache(NULL),
+       fMaxFileSize(0),
        fOpenState(NULL),
        fWriteDirty(false)
 {
@@ -638,6 +639,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct 
flock* lock,
 status_t
 Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
 {
+       file_cache_sync(fFileCache);
+       Commit();
+
        LockInfo* prev = NULL;
 
        thread_info info;
@@ -673,6 +677,9 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct 
flock* lock)
 status_t
 Inode::ReleaseAllLocks(OpenFileCookie* cookie)
 {
+       file_cache_sync(fFileCache);
+       Commit();
+
        MutexLocker _(cookie->fLocksLock);
        LockInfo* linfo = cookie->fLocks;
        while (linfo != NULL) {
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index 58250e7..a44c12b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -32,6 +32,8 @@ public:
        inline                  void*           FileCache();
                                        status_t        RevalidateFileCache();
 
+       inline                  uint64          MaxFileSize();
+
                                        status_t        LookUp(const char* 
name, ino_t* id);
 
                                        status_t        Access(int mode);
@@ -57,10 +59,15 @@ public:
                                        status_t        Open(int mode, 
OpenFileCookie* cookie);
                                        status_t        Close(OpenFileCookie* 
cookie);
                                        status_t        Read(OpenFileCookie* 
cookie, off_t pos,
-                                                                       void* 
buffer, size_t* length, bool* eof);
+                                                                       void* 
buffer, size_t* length);
                                        status_t        Write(OpenFileCookie* 
cookie, off_t pos,
                                                                        const 
void* buffer, size_t *_length);
 
+                                       status_t        
ReadDirect(OpenFileCookie* cookie, off_t pos,
+                                                                       void* 
buffer, size_t* length, bool* eof);
+                                       status_t        
WriteDirect(OpenFileCookie* cookie, off_t pos,
+                                                                       const 
void* buffer, size_t *_length);
+
                                        status_t        CreateDir(const char* 
name, int mode);
                                        status_t        OpenDir(OpenDirCookie* 
cookie);
                                        status_t        ReadDir(void* buffer, 
uint32 size,
@@ -109,6 +116,7 @@ private:
                                        uint64          fChange;
                                        void*           fFileCache;
                                        mutex           fFileCacheLock;
+                                       uint64          fMaxFileSize;
 
                                        OpenState*      fOpenState;
                                        mutex           fStateLock;
@@ -171,5 +179,12 @@ Inode::SetOpenState(OpenState* state)
 }
 
 
+inline uint64
+Inode::MaxFileSize()
+{
+       return fMaxFileSize;
+}
+
+
 #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 c82c507..34ca35e 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -135,6 +135,9 @@ Inode::Open(int mode, OpenFileCookie* cookie)
 status_t
 Inode::Close(OpenFileCookie* cookie)
 {
+       file_cache_sync(fFileCache);
+       Commit();
+
        fFileSystem->RemoveOpenFile(cookie);
 
        MutexLocker _(fStateLock);
@@ -147,12 +150,15 @@ Inode::Close(OpenFileCookie* cookie)
 
 
 status_t
-Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length,
+Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* 
_length,
        bool* eof)
 {
        *eof = false;
        uint32 size = 0;
 
+       uint32 ioSize = fFileSystem->Root()->IOSize();
+       *_length = min_c(ioSize, *_length);
+
        status_t result;
        while (size < *_length && !*eof) {
                uint32 len = *_length - size;
@@ -175,12 +181,25 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* 
buffer, size_t* _length,
 
 
 status_t
-Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
+Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
+{
+       bool eof = false;
+       if ((cookie->fMode & O_NOCACHE) != 0)
+               return ReadDirect(cookie, pos, buffer, _length, &eof);
+       return file_cache_read(fFileCache, cookie, pos, buffer, _length);
+}
+
+
+status_t
+Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer,
        size_t *_length)
 {
        uint32 size = 0;
        const char* buffer = reinterpret_cast<const char*>(_buffer);
 
+       uint32 ioSize = fFileSystem->Root()->IOSize();
+       *_length = min_c(ioSize, *_length);
+
        fWriteDirty = true;
 
        while (size < *_length) {
@@ -207,6 +226,34 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const 
void* _buffer,
 
 
 status_t
+Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
+       size_t *_length)
+{
+       struct stat st;
+       status_t result = Stat(&st);
+       if (result != B_OK)
+               return result;
+
+       if ((cookie->fMode & O_APPEND) != 0)
+               pos = st.st_size;
+
+       uint64 fileSize = max_c(st.st_size, pos + *_length);
+       fMaxFileSize = max_c(fMaxFileSize, fileSize);
+
+       if ((cookie->fMode & O_NOCACHE) != 0) {
+               WriteDirect(cookie, pos, _buffer, _length);
+               Commit();
+       }
+
+       result = file_cache_set_size(fFileCache, fileSize);
+       if (result != B_OK)
+               return result;
+
+       return file_cache_write(fFileCache, cookie, pos, _buffer, _length);
+}
+
+
+status_t
 Inode::Commit()
 {
        if (!fWriteDirty)
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
index dbcf90a..968e670 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h
@@ -33,7 +33,7 @@ protected:
                        status_t        LookUp(const char* name, uint64* 
change, uint64* fileID,
                                                        FileHandle* handle);
 
-                       status_t        Link(Inode* dir, const char* name,s
+                       status_t        Link(Inode* dir, const char* name,
                                                        ChangeInfo* changeInfo);
 
        static  status_t        Rename(Inode* from, Inode* to, const char* 
fromName,
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 d1a447b..4804c6c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -230,7 +230,7 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* 
_cookie, off_t pos,
 
                do {
                        size_t bytesRead = bytesLeft;
-                       result = inode->Read(cookie, pos, buffer, &bytesRead, 
&eof);
+                       result = inode->ReadDirect(cookie, pos, buffer, 
&bytesRead, &eof);
                        if (result != B_OK)
                                return result;
 
@@ -255,15 +255,17 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
 
        status_t result;
-       uint32 ioSize = inode->GetFileSystem()->Root()->IOSize();
        for (size_t i = 0; i < count; i++) {
-               size_t bytesLeft = vecs[i].iov_len;
+               uint64 bytesLeft = vecs[i].iov_len;
+               if (pos + bytesLeft > inode->MaxFileSize())
+                       bytesLeft = inode->MaxFileSize() - pos;
+
                char* buffer = reinterpret_cast<char*>(vecs[i].iov_base);
 
                do {
-                       size_t bytesWritten = min_c(ioSize, bytesLeft);
+                       size_t bytesWritten = bytesLeft;
 
-                       result = inode->Write(cookie, pos, buffer, 
&bytesWritten);
+                       result = inode->WriteDirect(cookie, pos, buffer, 
&bytesWritten);
                        if (result != B_OK)
                                return result;
 
@@ -468,8 +470,6 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* 
_cookie)
                return B_OK;
 
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
-       file_cache_sync(inode->FileCache());
-       inode->Commit();
 
        inode->Close(cookie);
        delete cookie;
@@ -479,7 +479,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* 
_cookie)
 
 
 static status_t
-nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, off_t pos,
+nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
        void* buffer, size_t* length)
 {
        Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
@@ -490,7 +490,9 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, 
off_t pos,
        if (inode->Type() == S_IFLNK)
                return B_BAD_VALUE;
 
-       return file_cache_read(inode->FileCache(), cookie, pos, buffer, length);
+       OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
+
+       return inode->Read(cookie, pos, buffer, length);
 }
 
 
@@ -508,17 +510,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* 
_cookie, off_t pos,
 
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
 
-       struct stat stat;
-       status_t result = inode->Stat(&stat);
-       if (result != B_OK)
-               return result;
-
-       uint64 fileSize = max_c(stat.st_size, pos + *length);
-       result = file_cache_set_size(inode->FileCache(), fileSize);
-       if (result != B_OK)
-               return result;
-
-       return file_cache_write(inode->FileCache(), cookie, pos, _buffer, 
length);
+       return inode->Write(cookie, pos, _buffer, length);
 }
 
 
@@ -627,9 +619,6 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* 
_cookie,
 
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
 
-       file_cache_sync(inode->FileCache());
-       inode->Commit();
-
        if (lock != NULL)
                return inode->ReleaseLock(cookie, lock);
        else

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

Commit:      4a153753100503cf374d01079fb29ca83d3ac44b

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 00:03:28 2012 UTC

nfs4: Return delegations when asked to

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
new file mode 100644
index 0000000..299cf21
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+
+
+#include "Delegation.h"
+
+#include "Inode.h"
+#include "Request.h"
+
+
+Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
+       uint64 clientID)
+       :
+       fClientID(clientID),
+       fData(data),
+       fInode(inode)
+{
+       rw_lock_init(&fLock, NULL);
+}
+
+
+Delegation::~Delegation()
+{
+       rw_lock_destroy(&fLock);
+}
+
+status_t
+Delegation::GiveUp(bool truncate)
+{
+       if (!truncate) {
+               // save buffers
+       }
+
+       ReturnDelegation();
+
+       return B_OK;
+}
+
+
+status_t
+Delegation::ReturnDelegation()
+{
+       do {
+               RPC::Server* serv = fFileSystem->Server();
+               Request request(serv);
+               RequestBuilder& req = request.Builder();
+
+               req.PutFH(fInfo.fHandle);
+               req.DelegReturn(fData.fStateID, fData.fStateSeq);
+
+               status_t result = request.Send();
+               if (result != B_OK)
+                       return result;
+
+               ReplyInterpreter& reply = request.Reply();
+
+               if (HandleErrors(reply.NFS4Error(), serv))
+                       continue;
+
+               reply.PutFH();
+
+               return reply.DelegReturn();
+       } while (true);
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h 
b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
index 31fea04..d54da15 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h
@@ -15,9 +15,12 @@
 #include "NFS4Object.h"
 
 
-class Delegation : public NFS4Object {
+class Inode;
+
+class Delegation : public NFS4Object,
+       public DoublyLinkedListLinkImpl<Delegation> {
 public:
-                                               Delegation(OpenDelegationData 
data, Inode* inode,
+                                               Delegation(const 
OpenDelegationData& data, Inode* inode,
                                                        uint64 clientID);
                                                ~Delegation();
 
@@ -28,7 +31,12 @@ public:
 
        status_t                        Reclaim(uint64 newClientID);
 
-       status_t                        GiveUp(bool flush);
+       status_t                        GiveUp(bool truncate);
+
+       inline  Inode*          GetInode();
+
+protected:
+       status_t                        ReturnDelegation();
 
 private:
        uint64                          fClientID;
@@ -39,5 +47,12 @@ private:
 };
 
 
+inline Inode*
+Delegation::GetInode()
+{
+       return fInode;
+}
+
+
 #endif // DELEGATION_H
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h 
b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h
index 28b5412..5cd0f2a 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h
+++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h
@@ -24,6 +24,9 @@ struct FileHandle {
        inline                          FileHandle();
        inline                          FileHandle(const FileHandle& fh);
        inline  FileHandle&     operator=(const FileHandle& fh);
+
+       inline  bool            operator>(const FileHandle& handle) const;
+       inline  bool            operator<(const FileHandle& handle) const;
 };
 
 
@@ -87,6 +90,24 @@ FileHandle::operator=(const FileHandle& fh)
 }
 
 
+inline bool
+FileHandle::operator>(const FileHandle& handle) const
+{
+       if (fSize > handle.fSize)
+               return true;
+       return memcmp(fData, handle.fData, fSize) > 0;
+}
+
+
+inline bool
+FileHandle::operator<(const FileHandle& handle) const
+{
+       if (fSize < handle.fSize)
+               return true;
+       return memcmp(fData, handle.fData, fSize) < 0;
+}
+
+
 inline
 FileInfo::FileInfo()
        :
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
index f4eb990..d5e3d8b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp
@@ -38,6 +38,7 @@ FileSystem::FileSystem()
 
        mutex_init(&fOpenOwnerLock, NULL);
        mutex_init(&fOpenLock, NULL);
+       mutex_init(&fDelegationLock, NULL);
 }
 
 
@@ -45,6 +46,7 @@ FileSystem::~FileSystem()
 {
        NFSServer()->RemoveFileSystem(this);
 
+       mutex_destroy(&fDelegationLock);
        mutex_destroy(&fOpenLock);
        mutex_destroy(&fOpenOwnerLock);
 
@@ -308,3 +310,43 @@ FileSystem::RemoveOpenFile(OpenFileCookie* cookie)
        NFSServer()->DecUsage();
 }
 
+
+void
+FileSystem::AddDelegation(Delegation* delegation)
+{
+       MutexLocker _(fDelegationLock);
+
+       fOpenDelegations.InsertBefore(fOpenDelegations.Head(), delegation);
+
+       fHandleToDelegation.Remove(delegation->fInfo.fHandle);
+       fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation);
+
+       NFSServer()->IncUsage();
+}
+
+
+void
+FileSystem::RemoveDelegation(Delegation* delegation)
+{
+       MutexLocker _(fDelegationLock);
+
+       fOpenDelegations.Remove(delegation);
+       fHandleToDelegation.Remove(delegation->fInfo.fHandle);
+
+       NFSServer()->DecUsage();
+}
+
+
+Delegation*
+FileSystem::GetDelegation(const FileHandle& handle)
+{
+       MutexLocker _(fDelegationLock);
+
+       AVLTreeMap<FileHandle, Delegation*>::Iterator it;
+       it = fHandleToDelegation.Find(handle);
+       if (!it.HasCurrent())
+               return NULL;
+
+       return it.Current();
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h 
b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
index 4c5df28..7814f8e 100644
--- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
+++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h
@@ -10,6 +10,7 @@
 
 
 #include "CacheRevalidator.h"
+#include "Delegation.h"
 #include "InodeIdMap.h"
 #include "NFS4Defs.h"
 #include "NFS4Server.h"
@@ -35,6 +36,12 @@ public:
                        void                            
AddOpenFile(OpenFileCookie* cookie);
                        void                            
RemoveOpenFile(OpenFileCookie* cookie);
 
+                       OpenFileCookie*         DelegationsLock();
+                       void                            DelegationsUnlock();
+                       void                            
AddDelegation(Delegation* delegation);
+                       void                            
RemoveDelegation(Delegation* delegation);
+                       Delegation*                     GetDelegation(const 
FileHandle& handle);
+
        inline  CacheRevalidator&       Revalidator();
 
        inline  bool                            IsAttrSupported(Attribute attr) 
const;
@@ -62,6 +69,10 @@ private:
 
                        CacheRevalidator        fCacheRevalidator;
 
+                       DoublyLinkedList<Delegation> fOpenDelegations;
+                       mutex                           fDelegationLock;
+                       AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation;
+
                        OpenFileCookie*         fOpenFiles;
                        uint32                          fOpenCount;
                        mutex                           fOpenLock;
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index a573f49..0f0846e 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -23,11 +23,13 @@
 Inode::Inode()
        :
        fCache(NULL),
+       fDelegation(NULL),
        fFileCache(NULL),
        fMaxFileSize(0),
        fOpenState(NULL),
        fWriteDirty(false)
 {
+       rw_lock_init(&fDelegationLock, NULL);
        mutex_init(&fStateLock, NULL);
        mutex_init(&fFileCacheLock, NULL);
 }
@@ -121,12 +123,16 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, 
Inode** _inode)
 
 Inode::~Inode()
 {
+       if (fDelegation != NULL)
+               RecallDelegation();
+
        if (fFileCache != NULL)
                file_cache_delete(fFileCache);
 
        delete fCache;
        mutex_destroy(&fStateLock);
        mutex_destroy(&fFileCacheLock);
+       rw_lock_destroy(&fDelegationLock);
 }
 
 
@@ -721,3 +727,26 @@ Inode::ChildAdded(const char* name, uint64 fileID,
        return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
 }
 
+
+void
+Inode::SetDelegation(Delegation* delegation)
+{
+       WriteLocker _(fDelegationLock);
+       fDelegation = delegation;
+       fFileSystem->AddDelegation(delegation);
+}
+
+
+void
+Inode::RecallDelegation(bool truncate)
+{
+       WriteLocker _(fDelegationLock);
+       if (fDelegation == NULL)
+               return;
+
+       fDelegation->GiveUp(truncate);
+       fFileSystem->RemoveDelegation(fDelegation);
+       delete fDelegation;
+       fDelegation = NULL;
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index a44c12b..4c56e75 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();
 
+                                       void            
SetDelegation(Delegation* delegation);
+                                       void            RecallDelegation(bool 
truncate = false);
+
                                        status_t        LookUp(const char* 
name, ino_t* id);
 
                                        status_t        Access(int mode);
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index 34ca35e..9208215 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -96,6 +96,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
 {
        MutexLocker _(fStateLock);
 
+       OpenDelegationData data;
+       data.fType = OPEN_DELEGATE_NONE;
        if (fOpenState == NULL) {
                OpenState* state = new OpenState;
                if (state == NULL)
@@ -103,7 +105,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
 
                state->fInfo = fInfo;
                state->fFileSystem = fFileSystem;
-               status_t result = OpenFile(state, mode, NULL);
+               status_t result = OpenFile(state, mode, &data);
                if (result != B_OK)
                        return result;
 
@@ -112,7 +114,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
                int newMode = mode & O_RWMASK;
                int oldMode = fOpenState->fMode & O_RWMASK;
                if (oldMode != newMode && oldMode != O_RDWR) {
-                       status_t result = OpenFile(fOpenState, O_RDWR, NULL);
+                       status_t result = OpenFile(fOpenState, O_RDWR, &data);
                        if (result != B_OK)
                                return result;
                        fOpenState->fMode = O_RDWR;
@@ -128,6 +130,16 @@ Inode::Open(int mode, OpenFileCookie* cookie)
 
        fFileSystem->AddOpenFile(cookie);
 
+       if (data.fType != OPEN_DELEGATE_NONE) {
+               Delegation* delegation
+                       = new(std::nothrow) Delegation(data, this, 
fOpenState->fClientID);
+               if (delegation != NULL) {
+                       delegation->fInfo = fOpenState->fInfo;
+                       delegation->fFileSystem = fFileSystem;
+                       SetDelegation(delegation);
+               }
+       }
+
        return B_OK;
 }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile 
b/src/add-ons/kernel/file_systems/nfs4/Jamfile
index b6aeed8..a3a4194 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Jamfile
+++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile
@@ -7,6 +7,7 @@ KernelAddon nfs4 :
        CacheRevalidator.cpp
        Cookie.cpp
        Connection.cpp
+       Delegation.cpp
        DirectoryCache.cpp
        FileInfo.cpp
        FileSystem.cpp
@@ -20,9 +21,11 @@ KernelAddon nfs4 :
        NFS4Object.cpp
        NFS4Server.cpp
        OpenState.cpp
+       ReplyBuilder.cpp
        ReplyInterpreter.cpp
        Request.cpp
        RequestBuilder.cpp
+       RequestInterpreter.cpp
        RootInode.cpp
        RPCAuth.cpp
        RPCCall.cpp
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
index 1887ee2..c162462 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h
@@ -25,11 +25,16 @@ enum CallbackProcedure {
        CallbackProcCompound    = 1
 };
 
+enum CallbackOpcode {
+       OpCallbackRecall                = 4
+};
+
 enum Opcode {
        OpAccess                                = 3,
        OpClose                                 = 4,
        OpCommit                                = 5,
        OpCreate                                = 6,
+       OpDelegReturn                   = 8,
        OpGetAttr                               = 9,
        OpGetFH                                 = 10,
        OpLink                                  = 11,
diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp 
b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
index ec38c3a..88fbce1 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp
@@ -315,3 +315,71 @@ NFS4Server::_RenewalThreadStart(void* ptr)
        return server->_Renewal();
 }
 
+
+status_t
+NFS4Server::ProcessCallback(RPC::CallbackRequest* request,
+       Connection* connection)
+{
+       RequestInterpreter req(request);
+       ReplyBuilder reply(request->XID());
+
+       status_t result;
+       uint32 count = req.OperationCount();
+
+       for (uint32 i = 0; i < count; i++) {
+               switch (req.Operation()) {
+                       case OpCallbackRecall:
+                               result = CallbackRecall(&req, &reply);
+                               break;
+                       default:
+                               result = B_NOT_SUPPORTED;
+               }
+
+               if (result != B_OK)
+                       break;
+       }
+
+       XDR::WriteStream& stream = reply.Reply()->Stream();
+       connection->Send(stream.Buffer(), stream.Size());
+
+       return B_OK;
+}
+
+
+status_t
+NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply)
+{
+       uint32 stateID[3];
+       uint32 stateSeq;
+       bool truncate;
+       FileHandle handle;
+
+       status_t result = request->Recall(&handle, truncate, &stateSeq, 
stateID);
+       if (result != B_OK)
+               return result;
+
+       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->Recall(B_FILE_NOT_FOUND);
+               return B_FILE_NOT_FOUND;
+       }
+
+       // TODO: should be asynchronous
+       delegation->GetInode()->RecallDelegation(truncate);
+
+       reply->Recall(B_OK);
+       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 46134e8..4d37a96 100644
--- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
+++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h
@@ -11,6 +11,8 @@
 
 #include <lock.h>
 
+#include "ReplyBuilder.h"
+#include "RequestInterpreter.h"
 #include "RPCServer.h"
 
 
@@ -34,6 +36,12 @@ public:
                        uint64                  ClientId(uint64 prevId = 0, 
bool forceNew = false);
 
        inline  uint32                  LeaseTime();
+
+       virtual status_t                ProcessCallback(RPC::CallbackRequest* 
request,
+                                                               Connection* 
connection);
+
+                       status_t                
CallbackRecall(RequestInterpreter* request,
+                                                               ReplyBuilder* 
reply);
 private:
                        status_t                _ReclaimOpen(OpenFileCookie* 
cookie);
                        status_t                _ReclaimLocks(OpenFileCookie* 
cookie);
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp
index 70da61c..ddf5b63 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp
@@ -10,15 +10,22 @@
 #include "RPCCallback.h"
 
 #include "RPCCallbackRequest.h"
+#include "RPCServer.h"
 
 
 using namespace RPC;
 
 
+Callback::Callback(Server* server)
+       :
+       fServer(server)
+{
+}
+
+
 status_t
 Callback::EnqueueRequest(CallbackRequest* request, Connection* connection)
 {
-       dprintf("GOT A CALLBACK REQUEST %x\n", (int)request->XID());
-       return B_OK;
+       return fServer->PrivateData()->ProcessCallback(request, connection);
 }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h
index 66d60ac..b729156 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h
@@ -15,9 +15,12 @@
 namespace RPC {
 
 class CallbackRequest;
+class Server;
 
 class Callback {
 public:
+                                               Callback(Server* server);
+
        inline  void            SetID(int32 id);
        inline  int32           ID();
 
@@ -25,6 +28,7 @@ public:
                                                        Connection* connection);
 
 private:
+                       Server*         fServer;
                        int32           fID;
 };
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp
index 4b10efb..90fce4d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp
@@ -45,7 +45,10 @@ CallbackRequest::CallbackRequest(void *buffer, int size)
 
        fProcedure = fStream.GetUInt();
 
+       fStream.GetUInt();
        fStream.GetOpaque(NULL);
+
+       fStream.GetUInt();
        fStream.GetOpaque(NULL);
 
        if (fProcedure == CallbackProcCompound) {
@@ -54,6 +57,9 @@ CallbackRequest::CallbackRequest(void *buffer, int size)
                        return;
 
                fID = fStream.GetUInt();
+
+               fRPCError = SUCCESS;
+               fError = B_OK;
        } else if (fProcedure == CallbackProcNull) {
                fRPCError = SUCCESS;
                fError = B_OK;
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp
index 5a64700..b007a3b 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);
@@ -68,7 +68,7 @@ CallbackServer::RegisterCallback(Callback* callback)
                for (uint32 i = fArraySize; i < newSize; i++)
                        array[i].fNext = i + 1;
 
-               array[fArraySize * 2 - 1].fNext = -1;
+               array[newSize - 1].fNext = -1;
 
                fCallbackArray = array;
                fFreeSlot = fArraySize;
@@ -240,7 +240,7 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry)
                if (request == NULL || request->Error() != B_OK) {
                        free(buffer);
                        continue;
-               } else if (request != NULL) {
+               } else if (request != NULL && request->Error() != B_OK) {
                        reply = CallbackReply::Create(request->XID(), 
request->RPCError());
                        if (reply != NULL) {
                                connection->Send(reply->Stream().Buffer(),
@@ -251,7 +251,6 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry)
                        continue;
                }
 
-
                switch (request->Procedure()) {
                        case CallbackProcCompound:
                                
GetCallback(request->ID())->EnqueueRequest(request, connection);
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp
index fce6f5a..70876f6 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp
@@ -228,7 +228,7 @@ Server::GetCallback()
 {
        MutexLocker _(fCallbackLock);
        if (fCallback == NULL) {
-               fCallback = new Callback;
+               fCallback = new(std::nothrow) Callback(this);
                gRPCCallbackServer->RegisterCallback(fCallback);
        }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h 
b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h
index ddcb80e..f4afd7f 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h
+++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h
@@ -48,6 +48,9 @@ private:
 
 class ProgramData {
 public:
+       virtual status_t        ProcessCallback(CallbackRequest* request,
+                                                       Connection* connection) 
= 0;
+
        virtual                         ~ProgramData() { }
 };
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp 
b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp
new file mode 100644
index 0000000..e18a4a6
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+
+
+#include "ReplyBuilder.h"
+
+#include "NFS4Defs.h"
+#include "RPCCallbackReply.h"
+
+
+ReplyBuilder::ReplyBuilder(uint32 xid)
+       :
+       fStatus(B_OK),
+       fOpCount(0),
+       fReply(RPC::CallbackReply::Create(xid))
+{
+       _InitHeader();
+}
+
+
+ReplyBuilder::~ReplyBuilder()
+{
+       delete fReply;
+}
+
+
+void
+ReplyBuilder::_InitHeader()
+{
+       fStatusPosition = fReply->Stream().Current();
+       fReply->Stream().AddUInt(0);
+
+       fReply->Stream().AddOpaque(NULL, 0);
+
+       fOpCountPosition = fReply->Stream().Current();
+       fReply->Stream().AddUInt(0);
+
+}
+
+
+RPC::CallbackReply*
+ReplyBuilder::Reply()
+{
+       fReply->Stream().InsertUInt(fStatusPosition, 
_HaikuErrorToNFS4(fStatus));
+       fReply->Stream().InsertUInt(fOpCountPosition, fOpCount);
+
+       if (fReply == NULL || fReply->Stream().Error() == B_OK)
+               return fReply;
+       else
+               return NULL;
+}
+
+
+status_t
+ReplyBuilder::Recall(status_t status)
+{
+       if (fStatus != B_OK)
+               return B_ERROR;
+
+       fReply->Stream().AddUInt(OpCallbackRecall);
+       fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus));
+       fStatus = status;
+
+       fOpCount++;
+
+       return B_OK;
+}
+
+
+uint32
+ReplyBuilder::_HaikuErrorToNFS4(status_t error)
+{
+       switch (error) {
+               case B_OK:                              return NFS4_OK;
+               case B_FILE_NOT_FOUND:  return NFS4ERR_BADHANDLE;
+               case B_NOT_SUPPORTED:   return NFS4ERR_OP_ILLEGAL;
+               default:                                return NFS4ERR_RESOURCE;
+       }
+}
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h 
b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h
new file mode 100644
index 0000000..be85416
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+#ifndef REPLYBUILDER_H
+#define REPLYBUILDER_H
+
+
+#include <SupportDefs.h>
+
+#include "RPCCallbackReply.h"
+#include "XDR.h"
+
+
+class ReplyBuilder {
+public:
+                                                                       
ReplyBuilder(uint32 xid);
+                                                                       
~ReplyBuilder();
+
+                       RPC::CallbackReply*             Reply();
+
+                       status_t                                Recall(status_t 
status);
+
+private:
+                       void                                    _InitHeader();
+
+       static  uint32                                  
_HaikuErrorToNFS4(status_t error);
+
+                       status_t                                fStatus;
+                       XDR::Stream::Position   fStatusPosition;
+
+                       uint32                                  fOpCount;
+                       XDR::Stream::Position   fOpCountPosition;
+
+                       RPC::CallbackReply*             fReply;
+};
+
+
+#endif // REPLYBUILDER_H
+
diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h 
b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
index 892e34c..986fcd8 100644
--- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
+++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h
@@ -71,6 +71,7 @@ public:
                        status_t        Close();
                        status_t        Commit();
                        status_t        Create(uint64* before, uint64* after, 
bool& atomic);
+       inline  status_t        DelegReturn();
                        status_t        GetAttr(AttrValue** attrs, uint32* 
count);
                        status_t        GetFH(FileHandle* fh);
                        status_t        Link(uint64* before, uint64* after, 
bool& atomic);
@@ -151,6 +152,13 @@ ReplyInterpreter::NFS4Error()
 
 
 inline status_t
+ReplyInterpreter::DelegReturn()
+{
+       return _OperationError(OpDelegReturn);
+}
+
+
+inline status_t
 ReplyInterpreter::LookUp()
 {
        return _OperationError(OpLookUp);
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
index c05b873..17d8259 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp
@@ -138,6 +138,27 @@ RequestBuilder::Create(FileType type, const char* name, 
AttrValue* attr,
 
 
 status_t
+RequestBuilder::DelegReturn(const uint32* id, uint32 seq)
+{
+       if (fProcedure != ProcCompound)
+               return B_BAD_VALUE;
+       if (fRequest == NULL)
+               return B_NO_MEMORY;
+
+       fRequest->Stream().AddUInt(OpDelegReturn);
+
+       fRequest->Stream().AddUInt(seq);
+       fRequest->Stream().AddUInt(id[0]);
+       fRequest->Stream().AddUInt(id[1]);
+       fRequest->Stream().AddUInt(id[2]);
+
+       fOpCount++;
+
+       return B_OK;
+}
+
+
+status_t
 RequestBuilder::GetAttr(Attribute* attrs, uint32 count)
 {
        if (fProcedure != ProcCompound)
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h 
b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
index 13db57d..d850c3c 100644
--- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h
@@ -37,6 +37,7 @@ public:
                        status_t                                Create(FileType 
type, const char* name,
                                                                                
AttrValue* attr, uint32 count,
                                                                                
const char* path = NULL);
+                       status_t                                
DelegReturn(const uint32* id, uint32 seq);
                        status_t                                
GetAttr(Attribute* attrs, uint32 count);
                        status_t                                GetFH();
                        status_t                                Link(const 
char* name);
diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp 
b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp
new file mode 100644
index 0000000..c129cde
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Paweł Dziepak, pdziepak@xxxxxxxxxxx
+ */
+
+
+#include "RequestInterpreter.h"
+
+#include <string.h>
+
+#include <util/kernel_cpp.h>
+
+
+RequestInterpreter::RequestInterpreter(RPC::CallbackRequest* request)
+       :
+       fRequest(request)
+{
+       fOperationCount = fRequest->Stream().GetUInt();
+}
+
+

[ *** diff truncated: 88 lines dropped *** ]


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

Commit:      bfa20379a3d5756dda6f3ebab0dcf52b6f4ca749

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Aug  6 01:18:46 2012 UTC

nfs4: Reclaim delegations after server reboot

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

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

Commit:      e2e5f06d6e736c019ed37c475ff4f68e3c4f401c

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

nfs4: Do not sync too often if delegation is held

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


Other related posts: