From 0dbff361721c31a831a7adda62f198b6e6960b23 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 4 Aug 2012 00:00:25 +0200 Subject: [PATCH] nfs4: Move low level NFS4 code to Inode's base class --- .../kernel/file_systems/nfs4/Inode.cpp | 1134 ++++------------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 60 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 232 +--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 433 +------ src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 6 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 1016 +++++++++++++++ .../kernel/file_systems/nfs4/NFS4Inode.h | 78 ++ .../kernel/file_systems/nfs4/NFS4Object.cpp | 89 ++ .../kernel/file_systems/nfs4/NFS4Object.h | 29 + .../kernel/file_systems/nfs4/RootInode.cpp | 6 +- 11 files changed, 1573 insertions(+), 1512 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Object.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 039da2d1c4..53394cd8f5 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; @@ -158,45 +158,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) { @@ -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(); + uint64 change; + uint64 fileID; + FileHandle handle; + status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); + *id = FileIdToInoT(fileID); - Attribute dirAttr[] = { FATTR4_CHANGE }; - req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + result = ChildAdded(name, fileID, handle); + if (result != B_OK) + return result; - if (!strcmp(name, "..")) - req.LookUpUp(); - else - req.LookUp(name); + fFileSystem->Revalidator().Lock(); + if (fCache->Lock() != B_OK) { + fCache->ResetAndLock(); + fCache->SetChangeInfo(change); + } else { + fFileSystem->Revalidator().RemoveDirectory(fCache); + fCache->ValidateChangeInfo(change); + } - req.GetFH(); + fCache->AddEntry(name, *id); + fFileSystem->Revalidator().AddDirectory(fCache); + fCache->Unlock(); + fFileSystem->Revalidator().Unlock(); - 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(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; - - *id = _FileIdToInoT(fileId); - - result = _ChildAdded(name, fileId, fh); - 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); - } - - 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(); + ChangeInfo changeInfo; + status_t result = NFS4Inode::Link(dir, name, &changeInfo); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); - req.SaveFH(); - req.PutFH(dir->fInfo.fHandle); - req.Link(name); + fFileSystem->Root()->MakeInfoInvalid(); - status_t result = request.Send(); - if (result != B_OK) - return result; + FileInfo fi = fInfo; + fi.fParent = dir->fInfo.fHandle; + free(const_cast(fi.fName)); + fi.fName = strdup(name); + if (fi.fName == NULL) + return B_NO_MEMORY; - ReplyInterpreter& reply = request.Reply(); + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; - // FileHandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - fInfo.UpdateFileHandles(fFileSystem); - dir->fInfo.UpdateFileHandles(dir->fFileSystem); - continue; - } + strcpy(path, dir->fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + free(const_cast(fi.fPath)); + fi.fPath = path; - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFileSystem->Migrate(serv); - continue; - } + fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); - reply.PutFH(); - reply.SaveFH(); - reply.PutFH(); + 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(); + } - uint64 before, after; - bool atomic; - result = reply.Link(&before, &after, atomic); - if (result != B_OK) - return result; - - fFileSystem->Root()->MakeInfoInvalid(); - - FileInfo fi = fInfo; - fi.fParent = dir->fInfo.fHandle; - free(const_cast(fi.fName)); - fi.fName = strdup(name); - if (fi.fName == NULL) - return B_NO_MEMORY; - - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, dir->fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - free(const_cast(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(); - } - - 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(); - - 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(); - } - - fFileSystem->Root()->MakeInfoInvalid(); - + ChangeInfo changeInfo; + status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo); + if (result != B_OK) return result; - } while (true); + + 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(); + + 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(); + ChangeInfo fromChange, toChange; + uint64 fileID; + status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, + &toChange, &fileID); + if (result != B_OK) + return result; - req.PutFH(from->fInfo.fHandle); - req.SaveFH(); - req.PutFH(to->fInfo.fHandle); - req.Rename(fromName, toName); + from->fFileSystem->Root()->MakeInfoInvalid(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - req.LookUp(toName); + 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(); + } - status_t result = request.Send(); - if (result != B_OK) - return result; + 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(); + } - 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; - - 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 (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(); - } - - 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; + ChangeInfo changeInfo; + uint64 fileID; + FileHandle handle; - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + status_t result = NFS4Inode::CreateObject(name, path, mode, type, &changeInfo, + &fileID, &handle); + if (result != B_OK) + return B_OK; - req.PutFH(fInfo.fHandle); - req.ReadLink(); + fFileSystem->Root()->MakeInfoInvalid(); - status_t result = request.Send(); - if (result != B_OK) - return result; + result = ChildAdded(name, fileID, handle); + if (result != B_OK) + return B_OK; - ReplyInterpreter& reply = request.Reply(); + 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(); + } - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - uint32 size; - result = reply.ReadLink(buffer, &size, *length); - *length = static_cast(size); - - 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; + uint32 allowed; + status_t result = NFS4Inode::Access(&allowed); + 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. + if ((allowed & ACCESS4_READ) != 0) + acc |= R_OK; - mode_t nodeMode = fAttrCache.st_mode; - uint8 userMode = (nodeMode & S_IRWXU) >> 6; - uint8 groupMode = (nodeMode & S_IRWXG) >> 3; - uint8 otherMode = (nodeMode & S_IRWXO); + if ((allowed & ACCESS4_LOOKUP) != 0) + acc |= X_OK | R_OK; - 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(); + if ((allowed & ACCESS4_EXECUTE) != 0) + acc |= X_OK; - 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; - - if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) - acc |= X_OK | R_OK; - - if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) - acc |= X_OK; - - if ((allowed & ACCESS4_MODIFY) != 0) - acc |= W_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(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(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; - fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; + 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; - return B_OK; - } while (true); + 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(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(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; + + 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(); + result = NFS4Inode::WriteStat(cookie, attr, i); - 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); + if ((mask & B_STAT_SIZE) != 0) { + Close(cookie); + delete cookie; + } - status_t result = request.Send(); - if (result != B_OK) { - Close(cookie); - delete cookie; - return result; - } + UpdateAttrCache(true); - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.SetAttr(); - - if ((mask & B_STAT_SIZE) != 0) { - Close(cookie); - delete cookie; - } - - if (result != B_OK) - return result; - - break; - } while (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(pos); - if (len >= OFF_MAX) - lock->l_len = OFF_MAX; - else - lock->l_len = static_cast(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(position); + if (length >= OFF_MAX) + lock->l_len = OFF_MAX; + else + lock->l_len = static_cast(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 2385063bff..0581251f8f 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 - -#include - -#include "Cookie.h" -#include "FileSystem.h" -#include "NFS4Defs.h" -#include "ReplyInterpreter.h" +#include "NFS4Inode.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 e12ab4c97e..c303678c9b 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(); + status_t result = Access(R_OK); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); - req.Access(); + cookie->fFileSystem = fFileSystem; + cookie->fSpecial = 0; + cookie->fSnapshot = NULL; + cookie->fCurrent = NULL; + cookie->fEOF = false; - 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 != 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); + return B_OK; } 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); -} - - -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(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 df49273f99..d9da7c2b9b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -19,182 +19,55 @@ #include "RootInode.h" -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(); + uint64 fileID; + FileHandle handle; + ChangeInfo changeInfo; + status_t result = CreateFile(name, mode, perms, cookie, &changeInfo, + &fileID, &handle); + if (result != B_OK) + return result; - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + *id = FileIdToInoT(fileID); - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + FileInfo fi; + fi.fFileId = fileID; + fi.fHandle = handle; + fi.fParent = fInfo.fHandle; + fi.fName = strdup(name); - req.PutFH(fInfo.fHandle); + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; - 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++; + fFileSystem->InoIdMap()->AddEntry(fi, *id); - if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) { - cattr[i].fAttribute = FATTR4_OWNER; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); - i++; - } + 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(); + } - 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(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; - - 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(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, - *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) + uint32 len = *_length - size; + result = ReadFile(cookie, pos + size, &len, + reinterpret_cast(buffer) + size, eof); + if (result != B_OK) { + if (size == 0) return result; + else + break; + } - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - result = reply.Read(reinterpret_cast(buffer) + size, &len, - eof); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); + size += len; } *_length = size; @@ -380,74 +132,21 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, size_t *_length) { uint32 size = 0; - uint32 len = 0; - uint64 fileSize; const char* buffer = reinterpret_cast(_buffer); fWriteDirty = true; while (size < *_length) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) { - struct stat st; - status_t result = Stat(&st); - if (result != B_OK) - return result; - - fileSize = st.st_size; - pos = fileSize; - } - - req.PutFH(fInfo.fHandle); - if ((cookie->fMode & O_APPEND) == O_APPEND) { - AttrValue attr; - attr.fAttribute = FATTR4_SIZE; - attr.fFreePointer = false; - attr.fData.fValue64 = fileSize + size; - req.Verify(&attr, 1); - } - req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size, - pos + size, *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) + uint32 len = *_length - size; + status_t result = WriteFile(cookie, pos + size, &len, buffer + size); + if (result != B_OK) { + if (size == 0) return result; + else + break; + } - ReplyInterpreter& reply = request.Reply(); - - // append: race condition - if (reply.NFS4Error() == NFS4ERR_NOT_SAME) { - if (size == 0) - continue; - else { - *_length = size; - return B_OK; - } - } - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - - if ((cookie->fMode & O_APPEND) == O_APPEND) { - result = reply.Verify(); - if (result != B_OK) - return result; - } - - result = reply.Write(&len); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); + size += len; } *_length = size; @@ -464,26 +163,10 @@ Inode::Commit() { if (!fWriteDirty) return B_OK; - - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Commit(0, 0); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - return reply.Commit(); - } while (true); + status_t result = CommitWrites(); + if (result != B_OK) + return result; + fWriteDirty = false; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 0d77bb21f5..13e62e81c1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -15,6 +15,8 @@ KernelAddon nfs4 : InodeDir.cpp InodeRegular.cpp kernel_interface.cpp + NFS4Inode.cpp + NFS4Object.cpp NFS4Server.cpp ReplyInterpreter.cpp Request.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 8ba791de2a..e9775aaa8d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -207,6 +207,12 @@ enum OpenFlags { OPEN4_RESULT_LOCKTYPE_POSIX = 4 }; +struct ChangeInfo { + bool fAtomic; + uint64 fBefore; + uint64 fAfter; +}; + enum WriteStable { UNSTABLE4 = 0, DATA_SYNC4 = 1, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp new file mode 100644 index 0000000000..564690c19b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -0,0 +1,1016 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "IdMap.h" +#include "Inode.h" +#include "NFS4Inode.h" +#include "Request.h" + + +status_t +NFS4Inode::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 +NFS4Inode::CommitWrites() +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Commit(0, 0); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + return reply.Commit(); + } while (true); +} + + +status_t +NFS4Inode::Access(uint32* allowed) +{ + 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(); + + return reply.Access(NULL, allowed); + } while (true); +} + + +status_t +NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, + FileHandle* handle) +{ + 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; + + *change = values[0].fData.fValue64; + delete[] values; + + if (!strcmp(name, "..")) + result = reply.LookUpUp(); + else + result = reply.LookUp(); + if (result != B_OK) + return result; + + reply.GetFH(handle); + + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + // FATTR4_FSID is mandatory + FileSystemId* fsid = + reinterpret_cast(values[0].fData.fPointer); + if (*fsid != fFileSystem->FsId()) { + delete[] values; + return B_ENTRY_NOT_FOUND; + } + + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[1].fData.fValue64; + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) +{ + 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(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + reply.SaveFH(); + reply.PutFH(); + + return reply.Link(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + } while (true); +} + + +status_t +NFS4Inode::ReadLink(void* buffer, size_t* length) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.ReadLink(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + uint32 size; + result = reply.ReadLink(buffer, &size, *length); + *length = static_cast(size); + + return result; + } while (true); +} + + +status_t +NFS4Inode::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) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenConfirm(&cookie->fStateSeq); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::GetStat(AttrValue** values, uint32* count) +{ + 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(); + + return reply.GetAttr(values, count); + } while (true); +} + + +status_t +NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + if (cookie != NULL) + req.SetAttr(cookie->fStateId, cookie->fStateSeq, attrs, attrCount); + else + req.SetAttr(NULL, 0, attrs, attrCount); + + 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.SetAttr(); + + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, + const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, + uint64* fileID) +{ + 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(); + + result = reply.Rename(&fromChange->fBefore, &fromChange->fAfter, + fromChange->fAtomic, &toChange->fBefore, &toChange->fAfter, + toChange->fAtomic); + 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; + + if (count == 0) + *fileID = from->fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::CreateFile(const char* name, int mode, int perms, + OpenFileCookie* cookie, ChangeInfo* changeInfo, uint64* fileID, + FileHandle* handle) +{ + bool confirm; + status_t result; + + bool badOwner = false; + 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(); + + result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm, + &changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic); + if (result != B_OK) + return result; + + reply.GetFH(handle); + + 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(); + + break; + } while (true); + + if (confirm) + return ConfirmOpen(*handle, cookie); + + return B_OK; +} + + +status_t +NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) +{ + bool confirm; + status_t result; + 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); + + if (confirm) + return ConfirmOpen(fInfo.fHandle, cookie); + + return B_OK; +} + + +status_t +NFS4Inode::CloseFile(OpenFileCookie* 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(); + return reply.Close(); + } while (true); +} + + +status_t +NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, + void* buffer, bool* eof) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, position, *length); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Read(buffer, length, eof); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, + const void* buffer) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + req.Write(cookie->fStateId, cookie->fStateSeq, buffer, position, + *length); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + + result = reply.Write(length); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::CreateObject(const char* name, const char* path, int mode, + FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) +{ + 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++; + } + + switch (type) { + case NF4DIR: + req.Create(NF4DIR, name, cattr, i); + break; + case NF4LNK: + req.Create(NF4LNK, name, cattr, i, path); + break; + default: + return B_BAD_VALUE; + } + + 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(); + result = reply.Create(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + if (result != B_OK) + return result; + + 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; + + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) +{ + 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(); + + return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + } while (true); +} + + +status_t +NFS4Inode::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); +} + + +status_t +NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, + uint64* length, bool& conflict) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.LockT(*type, *position, *length, 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(); + result = reply.LockT(position, length, type); + if (reply.NFS4Error() == NFS4ERR_DENIED) { + conflict = true; + result = B_OK; + } else if (reply.NFS4Error() == NFS4_OK) + conflict = false; + + return result; + } while (true); + + return B_OK; +} + + +status_t +NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) +{ + do { + MutexLocker ownerLocker(lockInfo->fOwner->fLock); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Lock(cookie, lockInfo); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + reply.PutFH(); + result = reply.Lock(lockInfo); + + 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) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) +{ + do { + MutexLocker ownerLocker(lockInfo->fOwner->fLock); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.LockU(lockInfo); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + reply.PutFH(); + result = reply.LockU(lockInfo); + + ownerLocker.Unlock(); + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h new file mode 100644 index 0000000000..4d5a6221db --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef NFS4INODE_H +#define NFS4INODE_H + + +#include + +#include + +#include "NFS4Object.h" +#include "ReplyInterpreter.h" + + +class NFS4Inode : protected NFS4Object { +public: + status_t GetChangeInfo(uint64* change); + status_t ReadLink(void* buffer, size_t* length); + +protected: + status_t Access(uint32* allowed); + + status_t CommitWrites(); + + status_t LookUp(const char* name, uint64* change, uint64* fileID, + FileHandle* handle); + + status_t Link(Inode* dir, const char* name, + ChangeInfo* changeInfo); + + static status_t Rename(Inode* from, Inode* to, const char* fromName, + const char* toName, ChangeInfo* fromChange, + ChangeInfo* toChange, uint64* fileID); + + status_t GetStat(AttrValue** values, uint32* count); + status_t WriteStat(OpenFileCookie* cookie, AttrValue* attrs, + uint32 attrCount); + + status_t CreateFile(const char* name, int mode, int perms, + OpenFileCookie* cookie, ChangeInfo* changeInfo, + uint64* fileID, FileHandle* handle); + status_t OpenFile(OpenFileCookie* cookie, int mode); + status_t CloseFile(OpenFileCookie* cookie); + + status_t ReadFile(OpenFileCookie* cookie, uint64 position, + uint32* length, void* buffer, bool* eof); + status_t WriteFile(OpenFileCookie* cookie, uint64 position, + uint32* length, const void* buffer); + + status_t CreateObject(const char* name, const char* path, + int mode, FileType type, ChangeInfo* changeInfo, + uint64* fileID, FileHandle* handle); + status_t RemoveObject(const char* name, FileType type, + ChangeInfo* changeInfo); + + status_t ReadDirOnce(DirEntry** dirents, uint32* count, + OpenDirCookie* cookie, bool* eof, uint64* change, + uint64* dirCookie, uint64* dirCookieVerf); + + status_t TestLock(OpenFileCookie* cookie, LockType* type, + uint64* position, uint64* length, bool& conflict); + status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, + bool wait); + status_t ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo); + + status_t ConfirmOpen(const FileHandle& fileHandle, + OpenFileCookie* cookie); + +}; + + +#endif // NFS4INODE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp new file mode 100644 index 0000000000..ba08e77c7c --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "NFS4Object.h" + + +bool +NFS4Object::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; + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h new file mode 100644 index 0000000000..49b4ecf466 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef NFS4OBJECT_H +#define NFS4OBJECT_H + + +#include "Cookie.h" +#include "FileSystem.h" +#include "NFS4Defs.h" + + +class NFS4Object { +public: + bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, + OpenFileCookie* cookie = NULL); + +protected: + FileInfo fInfo; + FileSystem* fFileSystem; +}; + + +#endif // NFS4OBJECT_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 6d99f30812..efb372a6d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -70,7 +70,7 @@ RootInode::_UpdateInfo(bool force) ReplyInterpreter& reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH(); @@ -152,7 +152,7 @@ RootInode::ProbeMigration() if (reply.NFS4Error() == NFS4ERR_MOVED) return true; - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; return false; @@ -179,7 +179,7 @@ RootInode::GetLocations(AttrValue** attrv) ReplyInterpreter& reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH();