diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 55d91a1433..d3bc3549ef 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -91,7 +91,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.GetFH(); req.Access(); - Attribute attr[] = { FATTR4_FSID, FATTR4_FS_LOCATIONS }; + Attribute attr[] = { FATTR4_SUPPORTED_ATTRS, FATTR4_FH_EXPIRE_TYPE, + FATTR4_FSID, FATTR4_FS_LOCATIONS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -119,22 +120,28 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) + if (result != B_OK || count < 2) return result; + Filesystem* fs = new(std::nothrow) Filesystem; + if (fs == NULL) + return B_NO_MEMORY; + + // FATTR4_SUPPORTED_ATTRS is mandatory + memcpy(fs->fSupAttrs, &values[0].fData.fValue64, sizeof(fs->fSupAttrs)); + + // FATTR4_FH_EXPIRE_TYPE is mandatory + fs->fExpireType = values[1].fData.fValue32; + // FATTR4_FSID is mandatory FilesystemId* fsid = - reinterpret_cast(values[0].fData.fPointer); + reinterpret_cast(values[2].fData.fPointer); - Filesystem* fs = new(std::nothrow) Filesystem; - - if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) { + if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) { FSLocations* locs = - reinterpret_cast(values[1].fData.fLocations); + reinterpret_cast(values[3].fData.fLocations); fs->fPath = strdup(locs->fRootPath); - - delete locs; } else fs->fPath = NULL; @@ -162,6 +169,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, *pfs = fs; + delete[] values; return B_OK; } @@ -264,6 +272,8 @@ Filesystem::ReadInfo(struct fs_info* info) info->flags = B_FS_IS_READONLY; strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + delete[] values; + return B_OK; } @@ -310,6 +320,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) reinterpret_cast(&dns)); if (result != B_OK) { mutex_unlock(&fMigrationLock); + delete[] values; return result; } @@ -337,7 +348,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) } put_module(DNS_RESOLVER_MODULE_NAME); - delete locs; + delete[] values; if (server == fServer) { mutex_unlock(&fMigrationLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index ed11fc2f89..fe50ff4766 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -33,6 +33,9 @@ public: status_t Migrate(const Filehandle& fh, const RPC::Server* serv); + inline bool IsAttrSupported(Attribute attr) const; + inline uint32 ExpireType() const; + inline RPC::Server* Server(); inline NFS4Server* NFSServer(); @@ -46,6 +49,9 @@ public: private: Filesystem(); + uint32 fExpireType; + uint32 fSupAttrs[2]; + FilesystemId fFsId; const char* fPath; mutex fMigrationLock; @@ -63,6 +69,20 @@ private: }; +inline bool +Filesystem::IsAttrSupported(Attribute attr) const +{ + return sIsAttrSet(attr, fSupAttrs, 2); +} + + +inline uint32 +Filesystem::ExpireType() const +{ + return fExpireType; +} + + inline RPC::Server* Filesystem::Server() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1eb880e98e..1e18c32bca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -819,8 +819,28 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - req.PutFH(fParentFH); + // 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(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { + req.PutFH(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEHANDLE; + attr.fFreePointer = true; + attr.fData.fPointer = malloc(sizeof(fHandle)); + memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); + req.Verify(&attr, 1); + } + req.PutFH(fParentFH); if ((mode & O_TRUNC) == O_TRUNC) { AttrValue attr; attr.fAttribute = FATTR4_SIZE; @@ -844,6 +864,21 @@ Inode::Open(int mode, OpenFileCookie* cookie) 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) @@ -1191,6 +1226,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) } else fileId = values[0].fData.fValue64; + delete[] values; + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 11cb1f8abc..5ae3b149ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -124,6 +124,17 @@ enum Attribute { FATTR4_MAXIMUM_ATTR_ID }; + +static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap, + uint32 count) +{ + if ((uint32)attr / 32 >= count) + return false; + + return (bitmap[attr / 32] & 1 << attr % 32) != 0; +} + + enum FileType { NF4REG = 1, /* Regular File */ NF4DIR = 2, /* Directory */ diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index dadabcb779..42ed5712bb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -154,15 +154,6 @@ static inline uint32 sCountBits(uint32 v) } -static inline bool sIsAttrSet(Attribute attr, uint32* bitmap, uint32 count) -{ - if ((uint32)attr / 32 >= count) - return false; - - return (bitmap[attr / 32] & 1 << attr % 32) != 0; -} - - status_t ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) { @@ -513,6 +504,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32 current = 0; + if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS, bitmap, bcount)) { + values[current].fAttribute = FATTR4_SUPPORTED_ATTRS; + uint32 count = stream.GetInt(); + uint32 i; + // two uint32 are enough for NFS4, not for NFS4.1 + for (i = 0; i < min_c(count, 2); i++) + ((uint32*)&values[current].fData.fValue64)[i] = stream.GetUInt(); + for (; i < count; i++) + stream.GetUInt(); + current++; + } + if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) { values[current].fAttribute = FATTR4_TYPE; values[current].fData.fValue32 = stream.GetInt(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 9fd61fb8bf..5654c94835 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -716,6 +716,17 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_FILEHANDLE) { + Filehandle* fh = reinterpret_cast(attr[i].fData.fPointer); + str.AddOpaque(fh->fFH, fh->fSize); + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_FILEID) { + str.AddUHyper(attr[i].fData.fValue64); + i++; + } + if (i < count && attr[i].fAttribute == FATTR4_MODE) { str.AddUInt(attr[i].fData.fValue32); i++;