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, <ype); - 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, <ype, &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 ----------------------------------------------------------------------------