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

  • From: pdziepak-github.nfs4 <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 4 Aug 2012 03:49:14 +0200 (CEST)

added 5 changesets to branch 'refs/remotes/pdziepak-github/nfs4'
old head: 36577ed54ba11c2e9b1a61f66cc2a704e2af7697
new head: eeabdab19f7fe5d1a704d21cf0dbb67c0c80c8a7

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

d4a75b9: nfs4: Use existing write cookie, do not send COMMIT if not necessary

13a90e3: nfs4: Revalidate cache before locks

0dbff36: nfs4: Move low level NFS4 code to Inode's base class

7efb4c9: nfs4: Add ACCESS cache

eeabdab: nfs4: Do not open too much files on server

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

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

21 files changed, 2085 insertions(+), 1621 deletions(-)
src/add-ons/kernel/file_systems/nfs4/Cookie.cpp    |    5 +-
src/add-ons/kernel/file_systems/nfs4/Cookie.h      |   15 +-
.../kernel/file_systems/nfs4/DirectoryCache.h      |    2 +-
src/add-ons/kernel/file_systems/nfs4/Inode.cpp     | 1208 ++++------------
src/add-ons/kernel/file_systems/nfs4/Inode.h       |   73 +-
src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp  |  232 +--
.../kernel/file_systems/nfs4/InodeRegular.cpp      |  503 ++-----
src/add-ons/kernel/file_systems/nfs4/Jamfile       |    4 +
.../kernel/file_systems/nfs4/MetadataCache.cpp     |   99 ++
.../kernel/file_systems/nfs4/MetadataCache.h       |   76 +
src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h    |    6 +
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp |  962 ++++++++++++
src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h   |   78 +
.../kernel/file_systems/nfs4/NFS4Object.cpp        |  123 ++
src/add-ons/kernel/file_systems/nfs4/NFS4Object.h  |   32 +
.../kernel/file_systems/nfs4/NFS4Server.cpp        |   51 +-
src/add-ons/kernel/file_systems/nfs4/OpenState.cpp |  111 ++
src/add-ons/kernel/file_systems/nfs4/OpenState.h   |   46 +
.../kernel/file_systems/nfs4/RequestBuilder.cpp    |   25 +-
src/add-ons/kernel/file_systems/nfs4/RootInode.cpp |    9 +-
.../kernel/file_systems/nfs4/kernel_interface.cpp  |   46 +-

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

Commit:      d4a75b9c9f2d3d77613ee8f0acb66cabf2238377

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Fri Aug  3 17:12:22 2012 UTC

nfs4: Use existing write cookie, do not send COMMIT if not necessary

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index 607df77..68ed4e7 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -24,7 +24,9 @@ Inode::Inode()
        :
        fAttrCacheExpire(0),
        fCache(NULL),
-       fFileCache(NULL)
+       fFileCache(NULL),
+       fWriteCookie(NULL),
+       fWriteDirty(false)
 {
        mutex_init(&fAttrCacheLock, NULL);
 }
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index 692bfec..30e0623 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -31,6 +31,8 @@ public:
        inline                  FileSystem*     GetFileSystem() const;
 
        inline                  void*           FileCache();
+       inline                  OpenFileCookie* WriteCookie();
+       inline                  void            SetWriteCookie(OpenFileCookie* 
cookie);
 
                                        status_t        GetChangeInfo(uint64* 
change);
 
@@ -116,6 +118,9 @@ protected:
 
                                        DirectoryCache* fCache;
                                        void*           fFileCache;
+                                       OpenFileCookie* fWriteCookie;
+
+                                       bool            fWriteDirty;
 };
 
 
@@ -165,5 +170,19 @@ Inode::FileCache()
 }
 
 
+inline OpenFileCookie*
+Inode::WriteCookie()
+{
+       return fWriteCookie;
+}
+
+
+inline void
+Inode::SetWriteCookie(OpenFileCookie* cookie)
+{
+       fWriteCookie = cookie;
+}
+
+
 #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 c1f6bf8..df49273 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -384,6 +384,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* 
_buffer,
        uint64 fileSize;
        const char* buffer = reinterpret_cast<const char*>(_buffer);
 
+       fWriteDirty = true;
+
        while (size < *_length) {
                do {
                        RPC::Server* serv = fFileSystem->Server();
@@ -460,6 +462,9 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* 
_buffer,
 status_t
 Inode::Commit()
 {
+       if (!fWriteDirty)
+               return B_OK;
+
        do {
                RPC::Server* serv = fFileSystem->Server();
                Request request(serv);
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 b1d0bd6..fd0307b 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -221,6 +221,7 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* 
_cookie, off_t pos,
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
 
        status_t result;
+       size_t totalRead = 0;
        bool eof = false;
        for (size_t i = 0; i < count && !eof; i++) {
                size_t bytesLeft = vecs[i].iov_len;
@@ -232,12 +233,15 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
                        if (result != B_OK)
                                return result;
 
+                       totalRead += bytesRead;
                        pos += bytesRead;
                        buffer += bytesRead;
                        bytesLeft -= bytesRead;
                } while (bytesLeft > 0 && !eof);
        }
 
+       *_numBytes = totalRead;
+
        return B_OK;
 }
 
@@ -247,21 +251,12 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
        const iovec* vecs, size_t count, size_t* _numBytes)
 {
        Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
-       bool freeCookie = false;
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
 
        if (cookie == NULL) {
-               cookie = new OpenFileCookie;
+               cookie = inode->WriteCookie();
                if (cookie == NULL)
-                       return B_NO_MEMORY;
-
-               status_t result = inode->Open(O_WRONLY, cookie);
-               if (result != B_OK) {
-                       delete cookie;
-                       return result;
-               }
-
-               freeCookie = true;
+                       return B_BAD_VALUE;
        }
 
        status_t result;
@@ -274,13 +269,8 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
                        size_t bytesWritten = min_c(ioSize, bytesLeft);
 
                        result = inode->Write(cookie, pos, buffer, 
&bytesWritten);
-                       if (result != B_OK) {
-                               if (freeCookie) {
-                                       inode->Close(cookie);
-                                       delete cookie;
-                               }
+                       if (result != B_OK)
                                return result;
-                       }
 
                        bytesLeft -= bytesWritten;
                        pos += bytesWritten;
@@ -288,11 +278,6 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, 
void* _cookie, off_t pos,
                } while (bytesLeft > 0);
        }
 
-       if (freeCookie) {
-               inode->Close(cookie);
-               delete cookie;
-       }
-
        return B_OK;
 }
 
@@ -326,7 +311,11 @@ static status_t
 nfs4_fsync(fs_volume* volume, fs_vnode* vnode)
 {
        Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
-       return file_cache_sync(inode->FileCache());
+       status_t result = file_cache_sync(inode->FileCache());
+       if (result != B_OK)
+               return result;
+
+       return inode->Commit();
 }
 
 
@@ -473,6 +462,10 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* 
_cookie)
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
        file_cache_sync(inode->FileCache());
        inode->Commit();
+
+       if (inode->WriteCookie() == cookie)
+               inode->SetWriteCookie(NULL);
+
        inode->Close(cookie);
        delete cookie;
 
@@ -520,6 +513,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* 
_cookie, off_t pos,
        if (result != B_OK)
                return result;
 
+       inode->SetWriteCookie(cookie);
        return file_cache_write(inode->FileCache(), cookie, pos, _buffer, 
length);
 }
 

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

Commit:      13a90e37953e4551e39dbe51feb6c1c92635c4d7

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Fri Aug  3 17:37:32 2012 UTC

nfs4: Revalidate cache before locks

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index 68ed4e7..039da2d 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -29,6 +29,7 @@ Inode::Inode()
        fWriteDirty(false)
 {
        mutex_init(&fAttrCacheLock, NULL);
+       mutex_init(&fFileCacheLock, NULL);
 }
 
 
@@ -55,8 +56,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, 
Inode** _inode)
 
                req.PutFH(inode->fInfo.fHandle);
 
-               Attribute attr[] = { FATTR4_TYPE, FATTR4_SIZE, FATTR4_FSID,
-                       FATTR4_FILEID };
+               Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE,
+                       FATTR4_FSID, FATTR4_FILEID };
                req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
 
                status_t result = request.Send();
@@ -73,14 +74,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, 
Inode** _inode)
                AttrValue* values;
                uint32 count;
                result = reply.GetAttr(&values, &count);
-               if (result != B_OK || count < 3)
+               if (result != B_OK || count < 4)
                        return result;
 
                if (fi.fFileId == 0) {
-                       if (count < 4 || values[3].fAttribute != FATTR4_FILEID)
+                       if (count < 5 || values[4].fAttribute != FATTR4_FILEID)
                                inode->fInfo.fFileId = fs->AllocFileId();
                        else
-                               inode->fInfo.fFileId = values[3].fData.fValue64;
+                               inode->fInfo.fFileId = values[4].fData.fValue64;
                } else
                        inode->fInfo.fFileId = fi.fFileId;
 
@@ -90,12 +91,15 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, 
Inode** _inode)
                if (inode->fType == NF4DIR)
                        inode->fCache = new DirectoryCache(inode);
 
+               // FATTR4_CHANGE is mandatory
+               inode->fChange = values[1].fData.fValue64;
+
                // FATTR4_SIZE is mandatory
-               size = values[1].fData.fValue64;
+               size = values[2].fData.fValue64;
 
                // FATTR4_FSID is mandatory
                FileSystemId* fsid =
-                       
reinterpret_cast<FileSystemId*>(values[2].fData.fPointer);
+                       
reinterpret_cast<FileSystemId*>(values[3].fData.fPointer);
                if (*fsid != fs->FsId()) {
                        delete[] values;
                        return B_ENTRY_NOT_FOUND;
@@ -121,11 +125,40 @@ Inode::~Inode()
                file_cache_delete(fFileCache);
 
        delete fCache;
+       mutex_destroy(&fFileCacheLock);
        mutex_destroy(&fAttrCacheLock);
 }
 
 
 status_t
+Inode::RevalidateFileCache()
+{
+       uint64 change;
+       status_t result = GetChangeInfo(&change);
+       if (result != B_OK)
+               return result;
+
+       MutexLocker _(fFileCacheLock);
+       if (change == fChange)
+               return B_OK;
+
+       result = _UpdateAttrCache(true);
+       if (result != B_OK)
+               return result;
+
+       file_cache_sync(fFileCache);
+       Commit();
+       file_cache_delete(fFileCache);
+
+       fFileCache = file_cache_create(fFileSystem->DevId(), ID(),
+               fAttrCache.st_size);
+
+       change = fChange;
+       return B_OK;
+}
+
+
+status_t
 Inode::GetChangeInfo(uint64* change)
 {
        do {
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index 30e0623..2385063 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -31,6 +31,8 @@ public:
        inline                  FileSystem*     GetFileSystem() const;
 
        inline                  void*           FileCache();
+                                       status_t        RevalidateFileCache();
+
        inline                  OpenFileCookie* WriteCookie();
        inline                  void            SetWriteCookie(OpenFileCookie* 
cookie);
 
@@ -117,8 +119,11 @@ protected:
                                        FileSystem*     fFileSystem;
 
                                        DirectoryCache* fCache;
+
+                                       uint64          fChange;
                                        void*           fFileCache;
                                        OpenFileCookie* fWriteCookie;
+                                       mutex           fFileCacheLock;
 
                                        bool            fWriteDirty;
 };
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 fd0307b..560a7a9 100644
--- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
@@ -429,7 +429,6 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, 
void** _cookie)
                return B_NO_MEMORY;
        *_cookie = cookie;
 
-
        status_t result = inode->Open(openMode, cookie);
        if (result != B_OK)
                delete cookie;
@@ -605,6 +604,9 @@ nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* 
_cookie,
 {
        Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
+
+       inode->RevalidateFileCache();
+
        return inode->AcquireLock(cookie, lock, wait);
 }
 
@@ -619,6 +621,10 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, 
void* _cookie,
                return B_OK;
 
        OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
+
+       file_cache_sync(inode->FileCache());
+       inode->Commit();
+
        if (lock != NULL)
                return inode->ReleaseLock(cookie, lock);
        else

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

Commit:      0dbff361721c31a831a7adda62f198b6e6960b23

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Fri Aug  3 22:00:25 2012 UTC

nfs4: Move low level NFS4 code to Inode's base class

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

diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp 
b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
index 039da2d..53394cd 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp
@@ -66,7 +66,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, 
Inode** _inode)
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (inode->_HandleErrors(reply.NFS4Error(), serv))
+               if (inode->HandleErrors(reply.NFS4Error(), serv))
                        continue;
 
                reply.PutFH();
@@ -142,7 +142,7 @@ Inode::RevalidateFileCache()
        if (change == fChange)
                return B_OK;
 
-       result = _UpdateAttrCache(true);
+       result = UpdateAttrCache(true);
        if (result != B_OK)
                return result;
 
@@ -159,45 +159,6 @@ Inode::RevalidateFileCache()
 
 
 status_t
-Inode::GetChangeInfo(uint64* change)
-{
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               Attribute attr[] = { FATTR4_CHANGE };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK || count < 1)
-                       return result;
-
-               // FATTR4_CHANGE is mandatory
-               *change = values[0].fData.fValue64;
-               delete[] values;
-
-               return B_OK;
-       } while (true);
-}
-
-
-status_t
 Inode::LookUp(const char* name, ino_t* id)
 {
        if (fType != NF4DIR)
@@ -208,472 +169,179 @@ Inode::LookUp(const char* name, ino_t* id)
                return B_OK;
        }
 
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               Attribute dirAttr[] = { FATTR4_CHANGE };
-               req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
-
-               if (!strcmp(name, ".."))
-                       req.LookUpUp();
-               else
-                       req.LookUp(name);
-
-               req.GetFH();
-
-               Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               uint64 change = values[0].fData.fValue64;
-               delete[] values;
-
-               if (!strcmp(name, ".."))
-                       result = reply.LookUpUp();
-               else
-                       result = reply.LookUp();
-               if (result != B_OK)
-                       return result;
-
-               FileHandle fh;
-               reply.GetFH(&fh);
-
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               // FATTR4_FSID is mandatory
-               FileSystemId* fsid =
-                       
reinterpret_cast<FileSystemId*>(values[0].fData.fPointer);
-               if (*fsid != fFileSystem->FsId()) {
-                       delete[] values;
-                       return B_ENTRY_NOT_FOUND;
-               }
-
-               uint64 fileId;
-               if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
-                       fileId = fFileSystem->AllocFileId();
-               else
-                       fileId = values[1].fData.fValue64;
-               delete[] values;
+       uint64 change;
+       uint64 fileID;
+       FileHandle handle;
+       status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle);
+       if (result != B_OK)
+               return result;
 
-               *id = _FileIdToInoT(fileId);
+       *id = FileIdToInoT(fileID);
 
-               result = _ChildAdded(name, fileId, fh);
-               if (result != B_OK)
-                       return result;
+       result = ChildAdded(name, fileID, handle);
+       if (result != B_OK)
+               return result;
 
-               fFileSystem->Revalidator().Lock();
-               if (fCache->Lock() != B_OK) {
-                       fCache->ResetAndLock();
-                       fCache->SetChangeInfo(change);
-               } else {
-                       fFileSystem->Revalidator().RemoveDirectory(fCache);
-                       fCache->ValidateChangeInfo(change);
-               }
+       fFileSystem->Revalidator().Lock();
+       if (fCache->Lock() != B_OK) {
+               fCache->ResetAndLock();
+               fCache->SetChangeInfo(change);
+       } else {
+               fFileSystem->Revalidator().RemoveDirectory(fCache);
+               fCache->ValidateChangeInfo(change);
+       }
 
-               fCache->AddEntry(name, *id);
-               fFileSystem->Revalidator().AddDirectory(fCache);
-               fCache->Unlock();
-               fFileSystem->Revalidator().Unlock();
+       fCache->AddEntry(name, *id);
+       fFileSystem->Revalidator().AddDirectory(fCache);
+       fCache->Unlock();
+       fFileSystem->Revalidator().Unlock();
 
-               return B_OK;
-       } while (true);
+       return B_OK;
 }
 
 
 status_t
 Inode::Link(Inode* dir, const char* name)
 {
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.SaveFH();
-               req.PutFH(dir->fInfo.fHandle);
-               req.Link(name);
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               // FileHandle has expired
-               if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) {
-                       fInfo.UpdateFileHandles(fFileSystem);
-                       dir->fInfo.UpdateFileHandles(dir->fFileSystem);
-                       continue;
-               }
-
-               // filesystem has been moved
-               if (reply.NFS4Error() == NFS4ERR_MOVED) {
-                       fFileSystem->Migrate(serv);
-                       continue;
-               }
+       ChangeInfo changeInfo;
+       status_t result = NFS4Inode::Link(dir, name, &changeInfo);
+       if (result != B_OK)
+               return result;
 
-               reply.PutFH();
-               reply.SaveFH();
-               reply.PutFH();
+       fFileSystem->Root()->MakeInfoInvalid();
 
-               uint64 before, after;
-               bool atomic;
-               result = reply.Link(&before, &after, atomic);
-               if (result != B_OK)
-                       return result;
+       FileInfo fi = fInfo;
+       fi.fParent = dir->fInfo.fHandle;
+       free(const_cast<char*>(fi.fName));
+       fi.fName = strdup(name);
+       if (fi.fName == NULL)
+               return B_NO_MEMORY;
 
-               fFileSystem->Root()->MakeInfoInvalid();
+       char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
+               strlen(fInfo.fPath)));
+       if (path == NULL)
+               return B_NO_MEMORY;
 
-               FileInfo fi = fInfo;
-               fi.fParent = dir->fInfo.fHandle;
-               free(const_cast<char*>(fi.fName));
-               fi.fName = strdup(name);
-               if (fi.fName == NULL)
-                       return B_NO_MEMORY;
+       strcpy(path, dir->fInfo.fPath);
+       strcat(path, "/");
+       strcat(path, name);
+       free(const_cast<char*>(fi.fPath));
+       fi.fPath = path;
 
-               char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
-                       strlen(fInfo.fPath)));
-               if (path == NULL)
-                       return B_NO_MEMORY;
+       fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId);
 
-               strcpy(path, dir->fInfo.fPath);
-               strcat(path, "/");
-               strcat(path, name);
-               free(const_cast<char*>(fi.fPath));
-               fi.fPath = path;
-
-               fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId);
-
-               if (dir->fCache->Lock() == B_OK) {
-                       if (atomic && dir->fCache->ChangeInfo() == before) {
-                               dir->fCache->AddEntry(name, fInfo.fFileId, 
true);
-                               dir->fCache->SetChangeInfo(after);
-                       } else if (dir->fCache->ChangeInfo() != before)
-                               dir->fCache->Trash();
-                       dir->fCache->Unlock();
-               }
+       if (dir->fCache->Lock() == B_OK) {
+               if (changeInfo.fAtomic
+                       && dir->fCache->ChangeInfo() == changeInfo.fBefore) {
+                       dir->fCache->AddEntry(name, fInfo.fFileId, true);
+                       dir->fCache->SetChangeInfo(changeInfo.fAfter);
+               } else if (dir->fCache->ChangeInfo() != changeInfo.fBefore)
+                       dir->fCache->Trash();
+               dir->fCache->Unlock();
+       }
 
-               return B_OK;
-       } while (true);
+       return B_OK;
 }
 
 
-// May cause problem similar to Rename (described below). When node's is has
-// more than one hard link and we delete the name it stores for FileHandle
-// restoration node will inocorectly become unavailable.
 status_t
 Inode::Remove(const char* name, FileType type)
 {
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.LookUp(name);
-               AttrValue attr;
-               attr.fAttribute = FATTR4_TYPE;
-               attr.fFreePointer = false;
-               attr.fData.fValue32 = NF4DIR;
-               if (type == NF4DIR)
-                       req.Verify(&attr, 1);
-               else
-                       req.Nverify(&attr, 1);
-
-               req.PutFH(fInfo.fHandle);
-               req.Remove(name);
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-               result = reply.LookUp();
-               if (result != B_OK)
-                       return result;
-
-               if (type == NF4DIR)
-                       result = reply.Verify();
-               else
-                       result = reply.Nverify();
-
-               if (result == NFS4ERR_SAME && type != NF4DIR)
-                       return B_IS_A_DIRECTORY;
-               if (result == NFS4ERR_NOT_SAME && type == NF4DIR)
-                       return B_NOT_A_DIRECTORY;
-               if (result != B_OK)
-                       return result;
-
-               reply.PutFH();
+       ChangeInfo changeInfo;
+       status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo);
+       if (result != B_OK)
+               return result;
 
-               uint64 before, after;
-               bool atomic;
-               result = reply.Remove(&before, &after, atomic);
-
-               if (fCache->Lock() == B_OK) {
-                       if (atomic && fCache->ChangeInfo() == before) {
-                               fCache->RemoveEntry(name);
-                               fCache->SetChangeInfo(after);
-                       } else if (fCache->ChangeInfo() != before)
-                               fCache->Trash();
-                       fCache->Unlock();
-               }
+       if (fCache->Lock() == B_OK) {
+               if (changeInfo.fAtomic
+                       && fCache->ChangeInfo() == changeInfo.fBefore) {
+                       fCache->RemoveEntry(name);
+                       fCache->SetChangeInfo(changeInfo.fAfter);
+               } else if (fCache->ChangeInfo() != changeInfo.fBefore)
+                       fCache->Trash();
+               fCache->Unlock();
+       }
 
-               fFileSystem->Root()->MakeInfoInvalid();
+       fFileSystem->Root()->MakeInfoInvalid();
 
-               return result;
-       } while (true);
+       return B_OK;
 }
 
 
-// Rename may cause some problems if FileHandles are volatile and local Inode
-// object exists for renamed node. It's stored filename will become invalid
-// and, consequnetly, FileHandle restoration will fail. Probably, it will
-// be much easier to solve this problem if more metadata is cached.
 status_t
 Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName)
 {
        if (from->fFileSystem != to->fFileSystem)
                return B_DONT_DO_THAT;
 
-       do {
-               RPC::Server* serv = from->fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(from->fInfo.fHandle);
-               req.SaveFH();
-               req.PutFH(to->fInfo.fHandle);
-               req.Rename(fromName, toName);
-
-               Attribute attr[] = { FATTR4_FILEID };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-               req.LookUp(toName);
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               // FileHandle has expired
-               if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) {
-                       from->fInfo.UpdateFileHandles(from->fFileSystem);
-                       to->fInfo.UpdateFileHandles(to->fFileSystem);
-                       continue;
-               }
-
-               // filesystem has been moved
-               if (reply.NFS4Error() == NFS4ERR_MOVED) {
-                       from->fFileSystem->Migrate(serv);
-                       continue;
-               }
-
-               reply.PutFH();
-               reply.SaveFH();
-               reply.PutFH();
-
-               uint64 fromBefore, fromAfter, toBefore, toAfter;
-               bool fromAtomic, toAtomic;
-               result = reply.Rename(&fromBefore, &fromAfter, fromAtomic, 
&toBefore,
-                       &toAfter, toAtomic);
-               if (result != B_OK)
-                       return result;
-
-               result = reply.LookUp();
-               if (result != B_OK)
-                       return result;
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               uint32 fileID;
-               if (count == 0)
-                       fileID = from->fFileSystem->AllocFileId();
-               else
-                       fileID = values[1].fData.fValue64;
+       ChangeInfo fromChange, toChange;
+       uint64 fileID;
+       status_t result = NFS4Inode::Rename(from, to, fromName, toName, 
&fromChange,
+               &toChange, &fileID);
+       if (result != B_OK)
+               return result;
 
-               from->fFileSystem->Root()->MakeInfoInvalid();
+       from->fFileSystem->Root()->MakeInfoInvalid();
 
-               if (from->fCache->Lock() == B_OK) {
-                       if (fromAtomic && from->fCache->ChangeInfo() == 
fromBefore) {
-                               from->fCache->RemoveEntry(fromName);
-                               from->fCache->SetChangeInfo(fromAfter);
-                       } else if (from->fCache->ChangeInfo() != fromBefore)
-                               from->fCache->Trash();
-                       from->fCache->Unlock();
-               }
+       if (from->fCache->Lock() == B_OK) {
+               if (fromChange.fAtomic
+                       && from->fCache->ChangeInfo() == fromChange.fBefore) {
+                       from->fCache->RemoveEntry(fromName);
+                       from->fCache->SetChangeInfo(fromChange.fAfter);
+               } else if (from->fCache->ChangeInfo() != fromChange.fBefore)
+                       from->fCache->Trash();
+               from->fCache->Unlock();
+       }
 
-               if (to->fCache->Lock() == B_OK) {
-                       if (toAtomic && to->fCache->ChangeInfo() == toBefore) {
-                               to->fCache->AddEntry(toName, fileID, true);
-                               to->fCache->SetChangeInfo(toAfter);
-                       } else if (to->fCache->ChangeInfo() != toBefore)
-                               to->fCache->Trash();
-                       to->fCache->Unlock();
-               }
+       if (to->fCache->Lock() == B_OK) {
+               if (toChange.fAtomic
+                       && to->fCache->ChangeInfo() == toChange.fBefore) {
+                       to->fCache->AddEntry(toName, fileID, true);
+                       to->fCache->SetChangeInfo(toChange.fAfter);
+               } else if (to->fCache->ChangeInfo() != toChange.fBefore)
+                       to->fCache->Trash();
+               to->fCache->Unlock();
+       }
 
-               return B_OK;
-       } while (true);
+       return B_OK;
 }
 
 
 status_t
 Inode::CreateLink(const char* name, const char* path, int mode)
 {
-       bool badOwner = false;
-
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               uint32 i = 0;
-               AttrValue cattr[3];
-               cattr[i].fAttribute = FATTR4_MODE;
-               cattr[i].fFreePointer = false;
-               cattr[i].fData.fValue32 = mode;
-               i++;
-
-               if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) {
-                       cattr[i].fAttribute = FATTR4_OWNER;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid());
-                       i++;
-               }
-
-               if (!badOwner && 
fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) {
-                       cattr[i].fAttribute = FATTR4_OWNER_GROUP;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = 
gIdMapper->GetOwnerGroup(getgid());
-                       i++;
-               }
-
-               req.Create(NF4LNK, name, cattr, i, path);
-
-               req.GetFH();
-               Attribute attr[] = { FATTR4_FILEID };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
-                       badOwner = true;
-                       continue;
-               }
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               uint64 before, after;
-               bool atomic;
-               result = reply.Create(&before, &after, atomic);
-               if (result != B_OK)
-                       return result;
-
-               FileHandle handle;
-               reply.GetFH(&handle);
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               uint32 fileID;
-               if (count == 0)
-                       fileID = fFileSystem->AllocFileId();
-               else
-                       fileID = values[0].fData.fValue64;
-
-               fFileSystem->Root()->MakeInfoInvalid();
-
-               result = _ChildAdded(name, fileID, handle);
-               if (result != B_OK)
-                       return B_OK;
-
-               if (fCache->Lock() == B_OK) {
-                       if (atomic && fCache->ChangeInfo() == before) {
-                               fCache->AddEntry(name, fileID, true);
-                               fCache->SetChangeInfo(after);
-                       } else if (fCache->ChangeInfo() != before)
-                               fCache->Trash();
-                       fCache->Unlock();
-               }
-
-               return B_OK;
-       } while (true);
+       return CreateObject(name, path, mode, NF4LNK);
 }
 
 
 status_t
-Inode::ReadLink(void* buffer, size_t* length)
+Inode::CreateObject(const char* name, const char* path, int mode, FileType 
type)
 {
-       if (fType != NF4LNK)
-               return B_BAD_VALUE;
-
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.ReadLink(); 
+       ChangeInfo changeInfo;
+       uint64 fileID;
+       FileHandle handle;
 
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
+       status_t result = NFS4Inode::CreateObject(name, path, mode, type, 
&changeInfo,
+               &fileID, &handle);
+       if (result != B_OK)
+               return B_OK;
 
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
+       fFileSystem->Root()->MakeInfoInvalid();
 
-               reply.PutFH();
+       result = ChildAdded(name, fileID, handle);
+       if (result != B_OK)
+               return B_OK;
 
-               uint32 size;
-               result = reply.ReadLink(buffer, &size, *length);
-               *length = static_cast<size_t>(size);
+       if (fCache->Lock() == B_OK) {
+               if (changeInfo.fAtomic && fCache->ChangeInfo() == 
changeInfo.fBefore) {
+                       fCache->AddEntry(name, fileID, true);
+                       fCache->SetChangeInfo(changeInfo.fAfter);
+               } else if (fCache->ChangeInfo() != changeInfo.fBefore)
+                       fCache->Trash();
+               fCache->Unlock();
+       }
 
-               return result;
-       } while (true);
+       return B_OK;
 }
 
 
@@ -682,69 +350,22 @@ Inode::Access(int mode)
 {
        int acc = 0;
 
-       if (fFileSystem->IsAttrSupported(FATTR4_MODE)) {
-               status_t result = _UpdateAttrCache();
-               if (result != B_OK)
-                       return result;
-
-               // Root squashing and owner mapping problems may make this 
function
-               // return false values. However, since due to race condition it 
can
-               // not be used for anything critical, it is not a serius 
problem.
-
-               mode_t nodeMode = fAttrCache.st_mode;
-               uint8 userMode = (nodeMode & S_IRWXU) >> 6;
-               uint8 groupMode = (nodeMode & S_IRWXG) >> 3;
-               uint8 otherMode = (nodeMode & S_IRWXO);
-
-               uid_t uid = geteuid();
-               if (uid == 0)
-                       acc = userMode | groupMode | otherMode | R_OK | W_OK;
-               else if (uid == fAttrCache.st_uid)
-                       acc = userMode;
-               else if (getegid() == fAttrCache.st_gid)
-                       acc = groupMode;
-               else
-                       acc = otherMode;
-       } else {
-               do {
-                       RPC::Server* serv = fFileSystem->Server();
-                       Request request(serv);
-                       RequestBuilder& req = request.Builder();
-
-                       req.PutFH(fInfo.fHandle);
-                       req.Access();
-
-                       status_t result = request.Send();
-                       if (result != B_OK)
-                               return result;
-
-                       ReplyInterpreter& reply = request.Reply();
-
-                       if (_HandleErrors(reply.NFS4Error(), serv))
-                               continue;
-
-                       reply.PutFH();
-
-                       uint32 allowed;
-                       result = reply.Access(NULL, &allowed);
-                       if (result != B_OK)
-                               return result;
-
-                       if ((allowed & ACCESS4_READ) != 0)
-                               acc |= R_OK;
+       uint32 allowed;
+       status_t result = NFS4Inode::Access(&allowed);
+       if (result != B_OK)
+               return result;
 
-                       if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0)
-                               acc |= X_OK | R_OK;
+       if ((allowed & ACCESS4_READ) != 0)
+               acc |= R_OK;
 
-                       if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0)
-                               acc |= X_OK;
+       if ((allowed & ACCESS4_LOOKUP) != 0)
+               acc |= X_OK | R_OK;
 
-                       if ((allowed & ACCESS4_MODIFY) != 0)
-                               acc |= W_OK;
+       if ((allowed & ACCESS4_EXECUTE) != 0)
+               acc |= X_OK;
 
-                       break;
-               } while (true);
-       }
+       if ((allowed & ACCESS4_MODIFY) != 0)
+               acc |= W_OK;
 
        if ((mode & acc) != mode)
                return B_NOT_ALLOWED;
@@ -756,7 +377,7 @@ Inode::Access(int mode)
 status_t
 Inode::Stat(struct stat* st)
 {
-       status_t result = _UpdateAttrCache();
+       status_t result = UpdateAttrCache();
        if (result != B_OK)
                return result;
 
@@ -776,7 +397,7 @@ Inode::Stat(struct stat* st)
 
 
 status_t
-Inode::_UpdateAttrCache(bool force)
+Inode::UpdateAttrCache(bool force)
 {
        if (!force && fAttrCacheExpire > time(NULL))
                return B_OK;
@@ -786,135 +407,85 @@ Inode::_UpdateAttrCache(bool force)
        if (fAttrCacheExpire > time(NULL))
                return B_OK;
 
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS,
-                                                       FATTR4_OWNER, 
FATTR4_OWNER_GROUP,
-                                                       FATTR4_TIME_ACCESS, 
FATTR4_TIME_CREATE,
-                                                       FATTR4_TIME_METADATA, 
FATTR4_TIME_MODIFY };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               // FATTR4_SIZE is mandatory
-               if (count < 1 || values[0].fAttribute != FATTR4_SIZE) {
-                       delete[] values;
-                       return B_BAD_VALUE;
-               }
-               fAttrCache.st_size = values[0].fData.fValue64;
-
-               uint32 next = 1;
-               fAttrCache.st_mode = Type();
-               if (count >= next && values[next].fAttribute == FATTR4_MODE) {
-                       fAttrCache.st_mode |= values[next].fData.fValue32;
-                       next++;
-               } else {
-                       // Try to guess using ACCESS request
-                       request.Reset();
-                       request.Builder().PutFH(fInfo.fHandle);
-                       request.Builder().Access();
-                       result = request.Send();
-                       if (result != B_OK)
-                               return result;
-                       request.Reply().PutFH();
-                       uint32 prvl;
-                       result = request.Reply().Access(NULL, &prvl);
-                       if (result != B_OK)
-                               return result;
-
-                       if ((prvl & ACCESS4_READ) != 0)
-                               fAttrCache.st_mode |= S_IRUSR | S_IRGRP | 
S_IROTH;
-
-                       if ((prvl & ACCESS4_MODIFY) != 0)
-                               fAttrCache.st_mode |= S_IWUSR | S_IWGRP | 
S_IWOTH;
-
-                       if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0)
-                               fAttrCache.st_mode |= S_IXUSR | S_IXGRP | 
S_IXOTH;
-
-                       if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0)
-                               fAttrCache.st_mode |= S_IXUSR | S_IXGRP | 
S_IXOTH;
-               }
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_NUMLINKS) {
-                       fAttrCache.st_nlink = values[next].fData.fValue32;
-                       next++;
-               } else
-                       fAttrCache.st_nlink = 1;
-
-               if (count >= next && values[next].fAttribute == FATTR4_OWNER) {
-                       char* owner = 
reinterpret_cast<char*>(values[next].fData.fPointer);
-                       if (owner != NULL && isdigit(owner[0]))
-                               fAttrCache.st_uid = atoi(owner);
-                       else
-                               fAttrCache.st_uid = gIdMapper->GetUserId(owner);
-                       next++;
-               } else
-                       fAttrCache.st_uid = 0;
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_OWNER_GROUP) {
-                       char* group = 
reinterpret_cast<char*>(values[next].fData.fPointer);
-                       if (group != NULL && isdigit(group[0]))
-                               fAttrCache.st_gid = atoi(group);
-                       else
-                               fAttrCache.st_gid = 
gIdMapper->GetGroupId(group);
-                       next++;
-               } else
-                       fAttrCache.st_gid = 0;
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_TIME_ACCESS) {
-                       memcpy(&fAttrCache.st_atim, values[next].fData.fPointer,
-                               sizeof(timespec));
-                       next++;
-               } else
-                       memset(&fAttrCache.st_atim, 0, sizeof(timespec));
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_TIME_CREATE) {
-                       memcpy(&fAttrCache.st_crtim, 
values[next].fData.fPointer,
-                               sizeof(timespec));
-                       next++;
-               } else
-                       memset(&fAttrCache.st_crtim, 0, sizeof(timespec));
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_TIME_METADATA) {
-                       memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer,
-                               sizeof(timespec));
-                       next++;
-               } else
-                       memset(&fAttrCache.st_ctim, 0, sizeof(timespec));
-
-               if (count >= next && values[next].fAttribute == 
FATTR4_TIME_MODIFY) {
-                       memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer,
-                               sizeof(timespec));
-                       next++;
-               } else
-                       memset(&fAttrCache.st_mtim, 0, sizeof(timespec));
+       AttrValue* values;
+       uint32 count;
+       status_t result = GetStat(&values, &count);
+       if (result != B_OK)
+               return result;
 
+       // FATTR4_SIZE is mandatory
+       if (count < 1 || values[0].fAttribute != FATTR4_SIZE) {
                delete[] values;
+               return B_BAD_VALUE;
+       }
+       fAttrCache.st_size = values[0].fData.fValue64;
+
+       uint32 next = 1;
+       fAttrCache.st_mode = Type();
+       if (count >= next && values[next].fAttribute == FATTR4_MODE) {
+               fAttrCache.st_mode |= values[next].fData.fValue32;
+               next++;
+       } else
+               fAttrCache.st_mode = 777;
+
+       if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) {
+               fAttrCache.st_nlink = values[next].fData.fValue32;
+               next++;
+       } else
+               fAttrCache.st_nlink = 1;
+
+       if (count >= next && values[next].fAttribute == FATTR4_OWNER) {
+               char* owner = 
reinterpret_cast<char*>(values[next].fData.fPointer);
+               if (owner != NULL && isdigit(owner[0]))
+                       fAttrCache.st_uid = atoi(owner);
+               else
+                       fAttrCache.st_uid = gIdMapper->GetUserId(owner);
+               next++;
+       } else
+               fAttrCache.st_uid = 0;
+
+       if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) {
+               char* group = 
reinterpret_cast<char*>(values[next].fData.fPointer);
+               if (group != NULL && isdigit(group[0]))
+                       fAttrCache.st_gid = atoi(group);
+               else
+                       fAttrCache.st_gid = gIdMapper->GetGroupId(group);
+               next++;
+       } else
+               fAttrCache.st_gid = 0;
+
+       if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) {
+               memcpy(&fAttrCache.st_atim, values[next].fData.fPointer,
+                       sizeof(timespec));
+               next++;
+       } else
+               memset(&fAttrCache.st_atim, 0, sizeof(timespec));
+
+       if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) {
+               memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer,
+                       sizeof(timespec));
+               next++;
+       } else
+               memset(&fAttrCache.st_crtim, 0, sizeof(timespec));
+
+       if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) {
+               memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer,
+                       sizeof(timespec));
+               next++;
+       } else
+               memset(&fAttrCache.st_ctim, 0, sizeof(timespec));
+
+       if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) {
+               memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer,
+                       sizeof(timespec));
+               next++;
+       } else
+               memset(&fAttrCache.st_mtim, 0, sizeof(timespec));
+       delete[] values;
+
+       fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime;
 
-               fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime;
-
-               return B_OK;
-       } while (true);
+       return B_OK;
 }
 
 
@@ -981,51 +552,21 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
                i++;
        }
 
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               if ((mask & B_STAT_SIZE) != 0)
-                       req.SetAttr(cookie->fStateId, cookie->fStateSeq, attr, 
i);
-               else
-                       req.SetAttr(NULL, 0, attr, i);
-
-               status_t result = request.Send();
-               if (result != B_OK) {
-                       Close(cookie);
-                       delete cookie;
-                       return result;
-               }
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
+       result = NFS4Inode::WriteStat(cookie, attr, i);
 
-               reply.PutFH();
-               result = reply.SetAttr();
-
-               if ((mask & B_STAT_SIZE) != 0) {
-                       Close(cookie);
-                       delete cookie;
-               }
-
-               if (result != B_OK)
-                       return result;
-
-               break;
-       } while (true);
+       if ((mask & B_STAT_SIZE) != 0) {
+               Close(cookie);
+               delete cookie;
+       }
 
-       _UpdateAttrCache(true);
+       UpdateAttrCache(true);
 
-       return B_OK;
+       return result;
 }
 
 
 inline status_t
-Inode::_CheckLockType(short ltype, uint32 mode)
+Inode::CheckLockType(short ltype, uint32 mode)
 {
        switch (ltype) {
                case F_UNLCK:
@@ -1046,62 +587,43 @@ Inode::_CheckLockType(short ltype, uint32 mode)
        }
 }
 
-
 status_t
 Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
 {
        if (lock->l_type == F_UNLCK)
                return B_OK;
 
-       status_t result = _CheckLockType(lock->l_type, cookie->fMode);
+       status_t result = CheckLockType(lock->l_type, cookie->fMode);
        if (result != B_OK)
                return result;
 
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.LockT(sGetLockType(lock->l_type, false), lock->l_start,
-                       lock->l_len, cookie);
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter &reply = request.Reply();
-               if (_HandleErrors(reply.NFS4Error(), serv, cookie))
-                       continue;
-
-               reply.PutFH();
-               LockType ltype;
-               uint64 pos, len;
-               result = reply.LockT(&pos, &len, &ltype);
-               if (reply.NFS4Error() == NFS4ERR_DENIED) {
-                       lock->l_type = sLockTypeToHaiku(ltype);
-                       lock->l_start = static_cast<off_t>(pos);
-                       if (len >= OFF_MAX)
-                               lock->l_len = OFF_MAX;
-                       else
-                               lock->l_len = static_cast<off_t>(len);
-
-                       result = B_OK;
-               } else if (reply.NFS4Error() == NFS4_OK)
-                       lock->l_type = F_UNLCK;
+       LockType ltype = sGetLockType(lock->l_type, false);
+       uint64 position = lock->l_start;
+       uint64 length = lock->l_len;
+       bool conflict;
 
+       result = NFS4Inode::TestLock(cookie, &ltype, &position, &length, 
conflict);
+       if (result != B_OK)
                return result;
-       } while (true);
+
+       if (conflict) {
+               lock->l_type = sLockTypeToHaiku(ltype);
+               lock->l_start = static_cast<off_t>(position);
+               if (length >= OFF_MAX)
+                       lock->l_len = OFF_MAX;
+               else
+                       lock->l_len = static_cast<off_t>(length);
+       } else
+               lock->l_type = F_UNLCK;
 
        return B_OK;
 }
 
-
 status_t
 Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
        bool wait)
 {
-       status_t result = _CheckLockType(lock->l_type, cookie->fMode);
+       status_t result = CheckLockType(lock->l_type, cookie->fMode);
        if (result != B_OK)
                return result;
 
@@ -1125,42 +647,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct 
flock* lock,
                linfo->fLength = lock->l_len;
        linfo->fType = sGetLockType(lock->l_type, wait);
 
-       do {
-               MutexLocker ownerLocker(linfo->fOwner->fLock);
-
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.Lock(cookie, linfo);
-
-               status_t result = request.Send();
-               if (result != B_OK) {
-                       cookie->DeleteLock(linfo);
-                       return result;
-               }
-
-               ReplyInterpreter &reply = request.Reply();
-
-               reply.PutFH();
-               result = reply.Lock(linfo);
-
-               ownerLocker.Unlock();
-               if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
-                       snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
-                               B_RELATIVE_TIMEOUT);
-                       continue;
-               }
-               if (_HandleErrors(reply.NFS4Error(), serv, cookie))
-                       continue;
-
-               if (result != B_OK) {
-                       cookie->DeleteLock(linfo);
-                       return result;
-               }
-               break;
-       } while (true);
+       result = NFS4Inode::AcquireLock(cookie, linfo, wait);
+       if (result != B_OK)
+               return result;
 
        MutexLocker _(cookie->fLocksLock);
        cookie->AddLock(linfo);
@@ -1194,38 +683,9 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct 
flock* lock)
        if (linfo == NULL)
                return B_BAD_VALUE;
 
-       do {
-               MutexLocker ownerLocker(linfo->fOwner->fLock);
-
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.LockU(linfo);
-
-               status_t result = request.Send();
-               if (result != B_OK) {
-                       cookie->DeleteLock(linfo);
-                       return result;
-               }
-
-               ReplyInterpreter &reply = request.Reply();
-
-               reply.PutFH();
-               result = reply.LockU(linfo);
-
-               ownerLocker.Unlock();
-               if (_HandleErrors(reply.NFS4Error(), serv, cookie))
-                       continue;
-
-               if (result != B_OK) {
-                       cookie->DeleteLock(linfo);
-                       return result;
-               }
-
-               break;
-       } while (true);
+       status_t result = NFS4Inode::ReleaseLock(cookie, linfo);
+       if (result != B_OK)
+               return result;
 
        cookie->DeleteLock(linfo);
 
@@ -1239,32 +699,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
        MutexLocker _(cookie->fLocksLock);
        LockInfo* linfo = cookie->fLocks;
        while (linfo != NULL) {
-               do {
-                       MutexLocker ownerLocker(linfo->fOwner->fLock);
-
-                       RPC::Server* serv = fFileSystem->Server();
-                       Request request(serv);
-                       RequestBuilder& req = request.Builder();
-
-                       req.PutFH(fInfo.fHandle);
-                       req.LockU(linfo);
-
-                       status_t result = request.Send();
-                       if (result != B_OK)
-                               break;
-
-                       ReplyInterpreter& reply = request.Reply();
-
-                       reply.PutFH();
-                       reply.LockU(linfo);
-
-                       ownerLocker.Unlock();
-                       if (_HandleErrors(reply.NFS4Error(), serv, cookie))
-                               continue;
-
-                       break;
-               } while (true);
-       
+               MutexLocker ownerLocker(linfo->fOwner->fLock);
+               NFS4Inode::ReleaseLock(cookie, linfo);
                cookie->RemoveLock(linfo, NULL);
                cookie->DeleteLock(linfo);
 
@@ -1275,86 +711,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
 }
 
 
-bool
-Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
-       OpenFileCookie* cookie)
-{
-       uint32 leaseTime;
-
-       switch (nfs4Error) {
-               case NFS4_OK:
-                       return false;
-
-               // server needs more time, we need to wait
-               case NFS4ERR_LOCKED:
-               case NFS4ERR_DELAY:
-                       if (cookie == NULL) {
-                               snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
-                                       B_RELATIVE_TIMEOUT);
-                               return true;
-                       } else if ((cookie->fMode & O_NONBLOCK) == 0) {
-                               status_t result = 
acquire_sem_etc(cookie->fSnoozeCancel, 1,
-                                       B_RELATIVE_TIMEOUT, sSecToBigTime(5));
-                               if (result != B_TIMED_OUT) {
-                                       release_sem(cookie->fSnoozeCancel);
-                                       return false;
-                               }
-                               return true;
-                       }
-                       return false;
-
-               // server is in grace period, we need to wait
-               case NFS4ERR_GRACE:
-                       leaseTime = fFileSystem->NFSServer()->LeaseTime();
-                       if (cookie == NULL) {
-                               snooze_etc(sSecToBigTime(leaseTime) / 3, 
B_SYSTEM_TIMEBASE,
-                                       B_RELATIVE_TIMEOUT);
-                               return true;
-                       } else if ((cookie->fMode & O_NONBLOCK) == 0) {
-                               status_t result = 
acquire_sem_etc(cookie->fSnoozeCancel, 1,
-                                       B_RELATIVE_TIMEOUT, 
sSecToBigTime(leaseTime) / 3);
-                               if (result != B_TIMED_OUT) {
-                                       release_sem(cookie->fSnoozeCancel);
-                                       return false;
-                               }
-                               return true;
-                       }
-                       return false;
-
-               // server has rebooted, reclaim share and try again
-               case NFS4ERR_STALE_CLIENTID:
-               case NFS4ERR_STALE_STATEID:
-                       
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientId);
-                       return true;
-
-               // FileHandle has expired
-               case NFS4ERR_FHEXPIRED:
-                       if (fInfo.UpdateFileHandles(fFileSystem) == B_OK)
-                               return true;
-                       return false;
-
-               // filesystem has been moved
-               case NFS4ERR_LEASE_MOVED:
-               case NFS4ERR_MOVED:
-                       fFileSystem->Migrate(serv);
-                       return true;
-
-               // lease has expired
-               case NFS4ERR_EXPIRED:
-                       if (cookie != NULL) {
-                               
fFileSystem->NFSServer()->ClientId(cookie->fClientId, true);
-                               return true;
-                       }
-                       return false;
-
-               default:
-                       return false;
-       }
-}
-
-
 status_t
-Inode::_ChildAdded(const char* name, uint64 fileID,
+Inode::ChildAdded(const char* name, uint64 fileID,
        const FileHandle& fileHandle)
 {
        fFileSystem->Root()->MakeInfoInvalid();
@@ -1377,6 +735,6 @@ Inode::_ChildAdded(const char* name, uint64 fileID,
        strcat(path, name);
        fi.fPath = path;
 
-       return fFileSystem->InoIdMap()->AddEntry(fi, _FileIdToInoT(fileID));
+       return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
 }
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h 
b/src/add-ons/kernel/file_systems/nfs4/Inode.h
index 2385063..0581251 100644
--- a/src/add-ons/kernel/file_systems/nfs4/Inode.h
+++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h
@@ -9,17 +9,10 @@
 #define INODE_H
 
 
-#include <sys/stat.h>
+#include "NFS4Inode.h"
 
-#include <SupportDefs.h>
 
-#include "Cookie.h"
-#include "FileSystem.h"
-#include "NFS4Defs.h"
-#include "ReplyInterpreter.h"
-
-
-class Inode {
+class Inode : public NFS4Inode {
 public:
        static                  status_t        CreateInode(FileSystem* fs, 
const FileInfo& fi,
                                                                        Inode** 
inode);
@@ -36,22 +29,23 @@ public:
        inline                  OpenFileCookie* WriteCookie();
        inline                  void            SetWriteCookie(OpenFileCookie* 
cookie);
 
-                                       status_t        GetChangeInfo(uint64* 
change);
+                                       status_t        LookUp(const char* 
name, ino_t* id);
+
+                                       status_t        Access(int mode);
 
                                        status_t        Commit();
 
-                                       status_t        LookUp(const char* 
name, ino_t* id);
+                                       status_t        CreateObject(const 
char* name, const char* path,
+                                                                       int 
mode, FileType type);
 
                                        status_t        CreateLink(const char* 
name, const char* path,
                                                                        int 
mode);
-                                       status_t        ReadLink(void* buffer, 
size_t* length);
 
                                        status_t        Link(Inode* dir, const 
char* name);
                                        status_t        Remove(const char* 
name, FileType type);
        static                  status_t        Rename(Inode* from, Inode* to,
                                                                        const 
char* fromName, const char* toName);
 
-                                       status_t        Access(int mode);
                                        status_t        Stat(struct stat* st);
                                        status_t        WriteStat(const struct 
stat* st, uint32 mask);
 
@@ -77,46 +71,32 @@ public:
                                                                        const 
struct flock* lock);
                                        status_t        
ReleaseAllLocks(OpenFileCookie* cookie);
 
-
 protected:
                                                                Inode();
 
-                                       bool            _HandleErrors(uint32 
nfs4Error,
-                                                                       
RPC::Server* serv,
-                                                                       
OpenFileCookie* cookie = NULL);
-
-                                       status_t        _ConfirmOpen(const 
FileHandle& fh,
-                                                                       
OpenFileCookie* cookie);
-
-                                       status_t        _ReadDirOnce(DirEntry** 
dirents, uint32* count,
-                                                                       
OpenDirCookie* cookie, bool* eof,
-                                                                       uint64* 
change, uint64* dirCookie,
-                                                                       uint64* 
dirCookieVerf);
-                                       status_t        _FillDirEntry(struct 
dirent* de, ino_t id,
-                                                                       const 
char* name, uint32 pos, uint32 size);
-                                       status_t        _ReadDirUp(struct 
dirent* de, uint32 pos,
+                                       status_t        ReadDirUp(struct 
dirent* de, uint32 pos,
                                                                        uint32 
size);
-                                       status_t        
_GetDirSnapshot(DirectoryCacheSnapshot**
+                                       status_t        FillDirEntry(struct 
dirent* de, ino_t id,
+                                                                       const 
char* name, uint32 pos, uint32 size);
+                                       status_t        
GetDirSnapshot(DirectoryCacheSnapshot**
                                                                        
_snapshot, OpenDirCookie* cookie,
                                                                        uint64* 
_change);
 
-                                       status_t        _ChildAdded(const char* 
name, uint64 fileID,
+                                       status_t        ChildAdded(const char* 
name, uint64 fileID,
                                                                        const 
FileHandle& fileHandle);
 
-       static inline   status_t        _CheckLockType(short ltype, uint32 
mode);
+                                       status_t        UpdateAttrCache(bool 
force = false);
 
-       static inline   ino_t           _FileIdToInoT(uint64 fileid);
+       static inline   status_t        CheckLockType(short ltype, uint32 mode);
+
+       static inline   ino_t           FileIdToInoT(uint64 fileid);
+
+                                       uint32          fType;
 
                                        struct stat     fAttrCache;
                                        mutex           fAttrCacheLock;
                                        time_t          fAttrCacheExpire;
        static const    time_t          kAttrCacheExpirationTime        = 60;
-                                       status_t        _UpdateAttrCache(bool 
force = false);
-
-                                       uint32          fType;
-
-                                       FileInfo        fInfo;
-                                       FileSystem*     fFileSystem;
 
                                        DirectoryCache* fCache;
 
@@ -130,7 +110,7 @@ protected:
 
 
 inline ino_t
-Inode::_FileIdToInoT(uint64 fileid)
+Inode::FileIdToInoT(uint64 fileid)
 {
        if (sizeof(ino_t) >= sizeof(uint64))
                return fileid;
@@ -143,7 +123,7 @@ Inode::_FileIdToInoT(uint64 fileid)
 inline ino_t
 Inode::ID() const
 {
-       return _FileIdToInoT(fInfo.fFileId);
+       return FileIdToInoT(fInfo.fFileId);
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp
index e12ab4c..c303678 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp
@@ -20,95 +20,7 @@
 status_t
 Inode::CreateDir(const char* name, int mode)
 {
-       bool badOwner = false;
-
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               uint32 i = 0;
-               AttrValue cattr[3];
-               cattr[i].fAttribute = FATTR4_MODE;
-               cattr[i].fFreePointer = false;
-               cattr[i].fData.fValue32 = mode;
-               i++;
-
-               if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) {
-                       cattr[i].fAttribute = FATTR4_OWNER;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid());
-                       i++;
-               }
-
-               if (!badOwner && 
fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) {
-                       cattr[i].fAttribute = FATTR4_OWNER_GROUP;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = 
gIdMapper->GetOwnerGroup(getgid());
-                       i++;
-               }
-
-               req.Create(NF4DIR, name, cattr, i);
-
-               req.GetFH();
-               Attribute attr[] = { FATTR4_FILEID };
-               req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
-                       badOwner = true;
-                       continue;
-               }
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               uint64 before, after;
-               bool atomic;
-               result = reply.Create(&before, &after, atomic);
-               if (result != B_OK)
-                       return result;
-
-               FileHandle handle;
-               result = reply.GetFH(&handle);
-               if (result != B_OK)
-                       return result;
-
-               AttrValue* values;
-               uint32 count;
-               result = reply.GetAttr(&values, &count);
-               if (result != B_OK)
-                       return result;
-
-               uint32 fileID;
-               if (count == 0)
-                       fileID = fFileSystem->AllocFileId();
-               else
-                       fileID = values[0].fData.fValue64;
-
-               result = _ChildAdded(name, fileID, handle);
-               if (result != B_OK)
-                       return B_OK;
-
-               if (fCache->Lock() == B_OK) {
-                       if (atomic && fCache->ChangeInfo() == before) {
-                               fCache->AddEntry(name, fileID, true);
-                               fCache->SetChangeInfo(after);
-                       } else if (fCache->ChangeInfo() != before)
-                               fCache->Trash();
-                       fCache->Unlock();
-               }
-
-               return B_OK;
-       } while (true);
+       return CreateObject(name, NULL, mode, NF4DIR);
 }
 
 
@@ -118,116 +30,22 @@ Inode::OpenDir(OpenDirCookie* cookie)
        if (fType != NF4DIR)
                return B_NOT_A_DIRECTORY;
 
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.Access();
+       status_t result = Access(R_OK);
+       if (result != B_OK)
+               return result;
 
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
+       cookie->fFileSystem = fFileSystem;
+       cookie->fSpecial = 0;
+       cookie->fSnapshot = NULL;
+       cookie->fCurrent = NULL;
+       cookie->fEOF = false;
 
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               uint32 allowed;
-               result = reply.Access(NULL, &allowed);
-               if (result != B_OK)
-                       return result;
-
-               if (allowed & ACCESS4_READ != ACCESS4_READ)
-                       return B_PERMISSION_DENIED;
-
-               cookie->fFileSystem = fFileSystem;
-               cookie->fSpecial = 0;
-               cookie->fSnapshot = NULL;
-               cookie->fCurrent = NULL;
-               cookie->fEOF = false;
-
-               fFileSystem->Root()->MakeInfoInvalid();
-
-               return B_OK;
-       } while (true);
-}
-
-
-status_t
-Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
-       bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf)
-{
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-
-               Attribute dirAttr[] = { FATTR4_CHANGE };
-               if (*change == 0)
-                       req.GetAttr(dirAttr, sizeof(dirAttr) / 
sizeof(Attribute));
-
-               Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
-               req.ReadDir(*count, *dirCookie, *dirCookieVerf, attr,
-                       sizeof(attr) / sizeof(Attribute));
-
-               req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
-
-               status_t result = request.Send(cookie);
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               AttrValue* before = NULL;
-               uint32 attrCount;
-               if (*change == 0) {
-                       result = reply.GetAttr(&before, &attrCount);
-                       if (result != B_OK)
-                               return result;
-               }
-
-               result = reply.ReadDir(dirCookie, dirCookieVerf, dirents,
-                       count, eof);
-               if (result != B_OK) {
-                       delete[] before;
-                       return result;
-               }
-
-               AttrValue* after;
-               result = reply.GetAttr(&after, &attrCount);
-               if (result != B_OK) {
-                       delete[] before;
-                       return result;
-               }
-
-               if (*change == 0 && before[0].fData.fValue64 == 
after[0].fData.fValue64
-                       || *change == after[0].fData.fValue64)
-                       *change = after[0].fData.fValue64;
-               else
-                       return B_ERROR;
-
-               delete[] before;
-               delete[] after;
-
-               return B_OK;
-       } while (true);
+       return B_OK;
 }
 
 
 status_t
-Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
+Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
        uint32 size)
 {
        uint32 nameSize = strlen(name);
@@ -249,7 +67,7 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const 
char* name, uint32 pos,
 
 
 status_t
-Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
+Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
 {
        do {
                RPC::Server* serv = fFileSystem->Server();
@@ -271,7 +89,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
 
                ReplyInterpreter& reply = request.Reply();
 
-               if (_HandleErrors(reply.NFS4Error(), serv))
+               if (HandleErrors(reply.NFS4Error(), serv))
                        continue;
 
                reply.PutFH();
@@ -295,13 +113,13 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 
size)
                } else
                        fileId = fFileSystem->AllocFileId();
 
-               return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, 
size);
+               return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size);
        } while (true);
 }
 
 
 status_t
-Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
+Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
        OpenDirCookie* cookie, uint64* _change)
 {
        DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot;
@@ -317,7 +135,7 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
                uint32 count;
                DirEntry* dirents;
 
-               status_t result = _ReadDirOnce(&dirents, &count, cookie, &eof, 
&change,
+               status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, 
&change,
                        &dirCookie, &dirCookieVerf);
                if (result != B_OK) {
                        delete snapshot;
@@ -335,9 +153,9 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
 
                        ino_t id;
                        if (dirents[i].fAttrCount == 2)
-                               id = 
_FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
+                               id = 
FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
                        else
-                               id = _FileIdToInoT(fFileSystem->AllocFileId());
+                               id = FileIdToInoT(fFileSystem->AllocFileId());
        
                        NameCacheEntry* entry = new 
NameCacheEntry(dirents[i].fName, id);
                        if (entry == NULL || entry->fName == NULL) {
@@ -381,7 +199,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
                cookie->fSnapshot = fCache->GetSnapshot();
                if (cookie->fSnapshot == NULL) {
                        uint64 change;
-                       result = _GetDirSnapshot(&cookie->fSnapshot, cookie, 
&change);
+                       result = GetDirSnapshot(&cookie->fSnapshot, cookie, 
&change);
                        if (result != B_OK) {
                                fCache->Unlock();
                                fFileSystem->Revalidator().Unlock();
@@ -405,7 +223,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
                struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
 
                status_t result;
-               result = _FillDirEntry(de, fInfo.fFileId, ".", pos, size);
+               result = FillDirEntry(de, fInfo.fFileId, ".", pos, size);
 
                if (result == B_BUFFER_OVERFLOW)
                        overflow = true;
@@ -422,9 +240,11 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
                
                status_t result;
                if (strcmp(fInfo.fName, "/"))
-                       result = _ReadDirUp(de, pos, size);
-               else
-                       result = _FillDirEntry(de, 
_FileIdToInoT(fInfo.fFileId), "..", pos, size);
+                       result = ReadDirUp(de, pos, size);
+               else {
+                       result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), 
"..", pos,
+                               size);
+               }
 
                if (result == B_BUFFER_OVERFLOW)
                        overflow = true;
@@ -452,7 +272,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
                        break;
                }
 
-               if (_FillDirEntry(de, cookie->fCurrent->fNode, 
cookie->fCurrent->fName,
+               if (FillDirEntry(de, cookie->fCurrent->fNode, 
cookie->fCurrent->fName,
                        pos, size) == B_BUFFER_OVERFLOW) {
                        overflow = true;
                        break;
diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp 
b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
index df49273..d9da7c2 100644
--- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
+++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
@@ -20,181 +20,54 @@
 
 
 status_t
-Inode::_ConfirmOpen(const FileHandle& fh, OpenFileCookie* cookie)
-{
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fh);
-               req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
-                       cookie->fStateSeq);
-
-               status_t result = request.Send();
-               if (result != B_OK) {
-                       fFileSystem->RemoveOpenFile(cookie);
-                       return result;
-               }
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-               result = reply.OpenConfirm(&cookie->fStateSeq);
-               if (result != B_OK) {
-                       fFileSystem->RemoveOpenFile(cookie);
-                       return result;
-               }
-
-               break;
-       } while (true);
-
-       return B_OK;
-}
-
-
-status_t
 Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
        ino_t* id)
 {
-       bool confirm;
-       status_t result;
-
        cookie->fMode = mode;
        cookie->fSequence = 0;
        cookie->fLocks = NULL;
 
-       bool badOwner = false;
-       FileHandle fh;
-       do {
-               cookie->fClientId = fFileSystem->NFSServer()->ClientId();
-
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
-
-               req.PutFH(fInfo.fHandle);
-
-               AttrValue cattr[4];
-               uint32 i = 0;
-               if ((mode & O_TRUNC) == O_TRUNC) {
-                       cattr[i].fAttribute = FATTR4_SIZE;
-                       cattr[i].fFreePointer = false;
-                       cattr[i].fData.fValue64 = 0;
-                       i++;
-               }
-               cattr[i].fAttribute = FATTR4_MODE;
-               cattr[i].fFreePointer = false;
-               cattr[i].fData.fValue32 = perms;
-               i++;
-
-               if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) {
-                       cattr[i].fAttribute = FATTR4_OWNER;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid());
-                       i++;
-               }
-
-               if (!badOwner && 
fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) {
-                       cattr[i].fAttribute = FATTR4_OWNER_GROUP;
-                       cattr[i].fFreePointer = true;
-                       cattr[i].fData.fPointer = 
gIdMapper->GetOwnerGroup(getgid());
-                       i++;
-               }
-
-               req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
-                       cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, 
name, cattr,
-                       i, (mode & O_EXCL) == O_EXCL);
-
-               req.GetFH();
-
-               if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
-                       Attribute attr[] = { FATTR4_FILEID };
-                       req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
-               }
-
-               result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
-                       badOwner = true;
-                       continue;
-               }
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               reply.PutFH();
-
-               bool atomic;
-               uint64 before, after;
-               result = reply.Open(cookie->fStateId, &cookie->fStateSeq, 
&confirm,
-                       &before, &after, &atomic);
-               if (result != B_OK)
-                       return result;
-
-               reply.GetFH(&fh);
-
-               uint64 fileId;
-               if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
-                       AttrValue* values;
-                       uint32 count;
-                       result = reply.GetAttr(&values, &count);
-                       if (result != B_OK)
-                               return result;
-
-                       fileId = values[0].fData.fValue64;
-
-                       delete[] values;
-               } else
-                       fileId = fFileSystem->AllocFileId();
-
-               *id = _FileIdToInoT(fileId);
-
-               FileInfo fi;
-               fi.fFileId = fileId;
-               fi.fHandle = fh;
-               fi.fParent = fInfo.fHandle;
-               fi.fName = strdup(name);
-
-               char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
-                       strlen(fInfo.fPath)));
-               strcpy(path, fInfo.fPath);
-               strcat(path, "/");
-               strcat(path, name);
-               fi.fPath = path;
-
-               fFileSystem->InoIdMap()->AddEntry(fi, *id);
-
-               if (fCache->Lock() == B_OK) {
-                       if (atomic && fCache->ChangeInfo() == before) {
-                               fCache->AddEntry(name, fileId, true);
-                               fCache->SetChangeInfo(after);
-                       } else if (fCache->ChangeInfo() != before)
-                               fCache->Trash();
-                       fCache->Unlock();
-               }
-
-               cookie->fFileSystem = fFileSystem;
-               cookie->fInfo = fi;
+       uint64 fileID;
+       FileHandle handle;
+       ChangeInfo changeInfo;
+       status_t result = CreateFile(name, mode, perms, cookie, &changeInfo,
+               &fileID, &handle);
+       if (result != B_OK)
+               return result;
+
+       *id = FileIdToInoT(fileID);
+
+       FileInfo fi;
+       fi.fFileId = fileID;
+       fi.fHandle = handle;
+       fi.fParent = fInfo.fHandle;
+       fi.fName = strdup(name);
+
+       char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
+               strlen(fInfo.fPath)));
+       strcpy(path, fInfo.fPath);
+       strcat(path, "/");
+       strcat(path, name);
+       fi.fPath = path;
+
+       fFileSystem->InoIdMap()->AddEntry(fi, *id);
+
+       if (fCache->Lock() == B_OK) {
+               if (changeInfo.fAtomic
+                       && fCache->ChangeInfo() == changeInfo.fBefore) {
+                       fCache->AddEntry(name, fileID, true);
+                       fCache->SetChangeInfo(changeInfo.fAfter);
+               } else if (fCache->ChangeInfo() != changeInfo.fBefore)
+                       fCache->Trash();
+               fCache->Unlock();
+       }
 
-               break;
-       } while (true);
+       cookie->fFileSystem = fFileSystem;
+       cookie->fInfo = fi;
 
        fFileSystem->AddOpenFile(cookie);
        fFileSystem->Root()->MakeInfoInvalid();
 
-       if (confirm)
-               return _ConfirmOpen(fh, cookie);
-
        return B_OK;
 }
 
@@ -202,95 +75,18 @@ Inode::Create(const char* name, int mode, int perms, 
OpenFileCookie* cookie,
 status_t
 Inode::Open(int mode, OpenFileCookie* cookie)
 {
-       bool confirm;
-       status_t result;
-
        cookie->fFileSystem = fFileSystem;
        cookie->fInfo = fInfo;
        cookie->fMode = mode;
        cookie->fSequence = 0;
        cookie->fLocks = NULL;
 
-       do {
-               cookie->fClientId = fFileSystem->NFSServer()->ClientId();
-
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               cookie->fOwnerId = atomic_add64(&cookie->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)) {
-                       req.PutFH(fInfo.fParent);
-                       req.LookUp(fInfo.fName);
-                       AttrValue attr;
-                       attr.fAttribute = FATTR4_FILEID;
-                       attr.fFreePointer = false;
-                       attr.fData.fValue64 = fInfo.fFileId;
-                       req.Verify(&attr, 1);
-               } else if (fFileSystem->ExpireType() == FH4_PERSISTENT) {
-                       req.PutFH(fInfo.fParent);
-                       req.LookUp(fInfo.fName);
-                       AttrValue attr;
-                       attr.fAttribute = FATTR4_FILEHANDLE;
-                       attr.fFreePointer = true;
-                       attr.fData.fPointer = malloc(sizeof(fInfo.fHandle));
-                       memcpy(attr.fData.fPointer, &fInfo.fHandle, 
sizeof(fInfo.fHandle));
-                       req.Verify(&attr, 1);
-               }
-
-               req.PutFH(fInfo.fParent);
-               if ((mode & O_TRUNC) == O_TRUNC) {
-                       AttrValue attr;
-                       attr.fAttribute = FATTR4_SIZE;
-                       attr.fFreePointer = false;
-                       attr.fData.fValue64 = 0;
-                       req.Open(CLAIM_NULL, cookie->fSequence++, 
sModeToAccess(mode),
-                               cookie->fClientId, OPEN4_CREATE, 
cookie->fOwnerId, fInfo.fName,
-                               &attr, 1, false);
-               } else
-               req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
-                       cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, 
fInfo.fName);
-
-               result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv))
-                       continue;
-
-               // Verify if the file we want to open is the file this Inode
-               // represents.
-               if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
-                       fFileSystem->ExpireType() == FH4_PERSISTENT) {
-                       reply.PutFH();
-                       result = reply.LookUp();
-                       if (result != B_OK)
-                               return result;
-                       result = reply.Verify();
-                       if (result != B_OK && reply.NFS4Error() == 
NFS4ERR_NOT_SAME)
-                               return B_ENTRY_NOT_FOUND;
-                       else if (result != B_OK)
-                               return result;
-               }
-
-               reply.PutFH();
-               result = reply.Open(cookie->fStateId, &cookie->fStateSeq, 
&confirm);
-               if (result != B_OK)
-                       return result;
-
-               break;
-       } while (true);
+       status_t result = OpenFile(cookie, mode);
+       if (result != B_OK)
+               return result;
 
        fFileSystem->AddOpenFile(cookie);
 
-       if (confirm)
-               return _ConfirmOpen(fInfo.fHandle, cookie);
-
        return B_OK;
 }
 
@@ -299,34 +95,7 @@ status_t
 Inode::Close(OpenFileCookie* cookie)
 {
        fFileSystem->RemoveOpenFile(cookie);
-
-       do {
-               RPC::Server* serv = fFileSystem->Server();
-               Request request(serv);
-               RequestBuilder& req = request.Builder();
-
-               req.PutFH(fInfo.fHandle);
-               req.Close(cookie->fSequence++, cookie->fStateId,
-                       cookie->fStateSeq);
-
-               status_t result = request.Send();
-               if (result != B_OK)
-                       return result;
-
-               ReplyInterpreter& reply = request.Reply();
-
-               if (_HandleErrors(reply.NFS4Error(), serv, cookie))
-                       continue;
-
-               reply.PutFH();
-               result = reply.Close();
-               if (result != B_OK)
-                       return result;
-
-               break;
-       } while (true);
-
-       return B_OK;
+       return CloseFile(cookie);
 }
 
 
@@ -336,37 +105,20 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* 
buffer, size_t* _length,
 {
        *eof = false;
        uint32 size = 0;
-       uint32 len = 0;
 
+       status_t result;
        while (size < *_length && !*eof) {
-               do {
-                       RPC::Server* serv = fFileSystem->Server();

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


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

Commit:      7efb4c9b493ccd82c277f013238cfc78aa8ab62d

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Fri Aug  3 22:47:13 2012 UTC

nfs4: Add ACCESS cache

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

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

Commit:      eeabdab19f7fe5d1a704d21cf0dbb67c0c80c8a7

Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Sat Aug  4 01:30:01 2012 UTC

nfs4: Do not open too much files on server

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


Other related posts: