From 20d1b02eefc137b62fac748323e6747c7f9e6ef3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 23:39:56 +0200 Subject: [PATCH] nfs4: Add basic support for extended attributes --- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 7 +- .../kernel/file_systems/nfs4/Delegation.cpp | 7 +- .../kernel/file_systems/nfs4/Delegation.h | 3 +- .../kernel/file_systems/nfs4/FileInfo.h | 11 ++ .../kernel/file_systems/nfs4/Inode.cpp | 112 ++++++++----- src/add-ons/kernel/file_systems/nfs4/Inode.h | 24 ++- .../kernel/file_systems/nfs4/InodeDir.cpp | 9 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 86 +++++++++- .../file_systems/nfs4/MetadataCache.cpp | 6 +- .../kernel/file_systems/nfs4/MetadataCache.h | 2 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 154 +++++++++++++----- .../kernel/file_systems/nfs4/NFS4Inode.h | 15 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 2 +- .../kernel/file_systems/nfs4/NFS4Object.h | 4 +- .../file_systems/nfs4/RequestBuilder.cpp | 10 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 142 ++++++++++++++-- 17 files changed, 475 insertions(+), 121 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 0f57b822bb..c8956eec58 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -73,11 +73,12 @@ struct Cookie { status_t CancelAll(); }; -struct OpenFileCookie : public Cookie { +struct OpenStateCookie : public Cookie { OpenState* fOpenState; - uint32 fMode; +}; +struct OpenFileCookie : public OpenStateCookie { LockInfo* fLocks; void AddLock(LockInfo* lock); @@ -97,6 +98,8 @@ struct OpenDirCookie : public Cookie { ~OpenDirCookie(); }; +struct OpenAttrCookie : public OpenStateCookie { }; + #endif // COOKIE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 80aeb4330a..19ea2f2a63 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -14,11 +14,12 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, - uint64 clientID) + uint64 clientID, bool attribute) : fClientID(clientID), fData(data), - fInode(inode) + fInode(inode), + fAttribute(attribute) { } @@ -26,7 +27,7 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, status_t Delegation::GiveUp(bool truncate) { - if (!truncate) + if (!fAttribute && !truncate) fInode->SyncAndCommit(true); ReturnDelegation(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 19afcfb450..f901173d23 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -21,7 +21,7 @@ class Delegation : public NFS4Object, public DoublyLinkedListLinkImpl { public: Delegation(const OpenDelegationData& data, Inode* inode, - uint64 clientID); + uint64 clientID, bool attr = false); status_t GiveUp(bool truncate = false); @@ -35,6 +35,7 @@ private: uint64 fClientID; OpenDelegationData fData; Inode* fInode; + bool fAttribute; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 47c377ddc8..ecacc0cace 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -25,6 +25,8 @@ struct FileHandle { inline FileHandle(const FileHandle& fh); inline FileHandle& operator=(const FileHandle& fh); + + inline bool operator!=(const FileHandle& handle) const; inline bool operator>(const FileHandle& handle) const; inline bool operator<(const FileHandle& handle) const; }; @@ -92,6 +94,15 @@ FileHandle::operator=(const FileHandle& fh) } +inline bool +FileHandle::operator!=(const FileHandle& handle) const +{ + if (fSize != handle.fSize) + return true; + return memcmp(fData, handle.fData, fSize) != 0; +} + + inline bool FileHandle::operator>(const FileHandle& handle) const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 805ba5ae9c..b0af3541b3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -262,68 +262,100 @@ Inode::Link(Inode* dir, const char* name) status_t Inode::Remove(const char* name, FileType type) { + if (type == NF4NAMEDATTR) { + status_t result = LoadAttrDirHandle(); + if (result != B_OK) + return result; + } + ChangeInfo changeInfo; uint64 fileID; status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; - if (fCache->Lock() == B_OK) { + DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; + if (cache->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(); + cache->RemoveEntry(name); + cache->SetChangeInfo(changeInfo.fAfter); + } else if (cache->ChangeInfo() != changeInfo.fBefore) + cache->Trash(); + cache->Unlock(); } fFileSystem->Root()->MakeInfoInvalid(); - notify_entry_removed(fFileSystem->DevId(), ID(), name, - FileIdToInoT(fileID)); + if (type == NF4NAMEDATTR) { + notify_attribute_changed(fFileSystem->DevId(), ID(), name, + B_ATTR_REMOVED); + } else { + notify_entry_removed(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + } return B_OK; } status_t -Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) +Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, + bool attribute) { if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; + if (attribute) { + status_t result = from->LoadAttrDirHandle(); + if (result != B_OK) + return result; + + result = to->LoadAttrDirHandle(); + if (result != B_OK) + return result; + } + ChangeInfo fromChange, toChange; uint64 fileID; status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, - &toChange, &fileID); + &toChange, &fileID, attribute); if (result != B_OK) return result; from->fFileSystem->Root()->MakeInfoInvalid(); - if (from->fCache->Lock() == B_OK) { + DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache; + if (cache->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(); + && cache->ChangeInfo() == fromChange.fBefore) { + cache->RemoveEntry(fromName); + cache->SetChangeInfo(fromChange.fAfter); + } else if (cache->ChangeInfo() != fromChange.fBefore) + cache->Trash(); + cache->Unlock(); } - if (to->fCache->Lock() == B_OK) { + cache = attribute ? to->fAttrCache : to->fCache; + if (cache->Lock() == B_OK) { if (toChange.fAtomic - && to->fCache->ChangeInfo() == toChange.fBefore) { - to->fCache->AddEntry(toName, fileID, true); - to->fCache->SetChangeInfo(toChange.fAfter); + && cache->ChangeInfo() == toChange.fBefore) { + cache->AddEntry(toName, fileID, true); + cache->SetChangeInfo(toChange.fAfter); } else if (to->fCache->ChangeInfo() != toChange.fBefore) - to->fCache->Trash(); - to->fCache->Unlock(); + cache->Trash(); + cache->Unlock(); } - notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, - to->ID(), toName, FileIdToInoT(fileID)); + if (attribute) { + notify_attribute_changed(from->fFileSystem->DevId(), from->ID(), + fromName, B_ATTR_REMOVED); + notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName, + B_ATTR_CREATED); + } else { + notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, + to->ID(), toName, FileIdToInoT(fileID)); + } return B_OK; } @@ -404,8 +436,11 @@ Inode::Access(int mode) status_t -Inode::Stat(struct stat* st) +Inode::Stat(struct stat* st, OpenAttrCookie* attr) { + if (attr != NULL) + return GetStat(st, attr); + status_t result = fMetaCache.GetStat(st); if (result != B_OK) { struct stat temp; @@ -421,11 +456,11 @@ Inode::Stat(struct stat* st) status_t -Inode::GetStat(struct stat* st) +Inode::GetStat(struct stat* st, OpenAttrCookie* attr) { AttrValue* values; uint32 count; - status_t result = NFS4Inode::GetStat(&values, &count); + status_t result = NFS4Inode::GetStat(&values, &count, attr); if (result != B_OK) return result; @@ -504,7 +539,7 @@ Inode::GetStat(struct stat* st) status_t -Inode::WriteStat(const struct stat* st, uint32 mask) +Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) { status_t result; AttrValue attr[6]; @@ -554,15 +589,18 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } - MutexLocker stateLocker(fStateLock); - result = NFS4Inode::WriteStat(fOpenState, attr, i); - stateLocker.Unlock(); + if (cookie == NULL) { + MutexLocker stateLocker(fStateLock); + result = NFS4Inode::WriteStat(fOpenState, attr, i); + stateLocker.Unlock(); - fMetaCache.InvalidateStat(); - if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 - || (mask & B_STAT_GID) != 0) { - fMetaCache.InvalidateAccess(); - } + fMetaCache.InvalidateStat(); + if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 + || (mask & B_STAT_GID) != 0) { + fMetaCache.InvalidateAccess(); + } + } else + result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i); return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 62fffcff80..e5a477aa20 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -57,24 +57,33 @@ public: 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); + const char* fromName, const char* toName, + bool attribute = false); - status_t Stat(struct stat* st); - status_t WriteStat(const struct stat* st, uint32 mask); + status_t Stat(struct stat* st, + OpenAttrCookie* attr = NULL); + status_t WriteStat(const struct stat* st, uint32 mask, + OpenAttrCookie* attr = NULL); status_t Create(const char* name, int mode, int perms, OpenFileCookie* cookie, OpenDelegationData* data, ino_t* id); status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); + + status_t OpenAttr(const char* name, int mode, + OpenAttrCookie* cookie, bool create, + int32 type = 0); + status_t CloseAttr(OpenAttrCookie* cookie); + status_t Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* length); status_t Write(OpenFileCookie* cookie, off_t pos, const void* buffer, size_t *_length); - status_t ReadDirect(OpenFileCookie* cookie, off_t pos, + status_t ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* length, bool* eof); - status_t WriteDirect(OpenFileCookie* cookie, off_t pos, + status_t WriteDirect(OpenStateCookie* cookie, off_t pos, const void* buffer, size_t *_length); status_t CreateDir(const char* name, int mode); @@ -96,6 +105,8 @@ public: _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute); + status_t LoadAttrDirHandle(); + protected: Inode(); @@ -115,7 +126,8 @@ protected: status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); - status_t GetStat(struct stat* st); + status_t GetStat(struct stat* st, + OpenAttrCookie* attr = NULL); static inline status_t CheckLockType(short ltype, uint32 mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index ac80441cb7..f2c83fe6ab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -55,6 +55,13 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) cookie->fEOF = false; cookie->fAttrDir = true; + return LoadAttrDirHandle(); +} + + +status_t +Inode::LoadAttrDirHandle() +{ if (fInfo.fAttrDir.fSize == 0) { FileHandle handle; @@ -65,7 +72,7 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) fInfo.fAttrDir = handle; } - return B_OK; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 7bad21a6f5..2eb1a1b104 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -193,7 +193,72 @@ Inode::Close(OpenFileCookie* cookie) status_t -Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, +Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, + int32 type) +{ + (void)type; + + status_t result = LoadAttrDirHandle(); + if (result != B_OK) + return result; + + OpenDelegationData data; + data.fType = OPEN_DELEGATE_NONE; + + OpenState* state = new OpenState; + if (state == NULL) + return B_NO_MEMORY; + + state->fInfo.fName = name; + state->fInfo.fParent = fInfo.fAttrDir; + result = NFS4Inode::OpenAttr(state, name, mode, &data, create); + if (result != B_OK) { + delete state; + return result; + } + + fFileSystem->AddOpenFile(state); + + cookie->fOpenState = state; + cookie->fFileSystem = fFileSystem; + cookie->fMode = mode; + + if (data.fType != OPEN_DELEGATE_NONE) { + Delegation* delegation + = new(std::nothrow) Delegation(data, this, fOpenState->fClientID, + true); + if (delegation != NULL) { + delegation->fInfo = state->fInfo; + delegation->fFileSystem = fFileSystem; + state->fDelegation = delegation; + fFileSystem->AddDelegation(delegation); + } + } + + if ((mode & O_TRUNC) == O_TRUNC) { + struct stat st; + st.st_size = 0; + WriteStat(&st, B_STAT_SIZE, cookie); + } + + return B_OK; +} + + +status_t +Inode::CloseAttr(OpenAttrCookie* cookie) +{ + cookie->fOpenState->fDelegation->GiveUp(); + fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); + delete cookie->fOpenState->fDelegation; + delete cookie->fOpenState; + + return B_OK; +} + + +status_t +Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* _length, bool* eof) { *eof = false; @@ -203,9 +268,10 @@ Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _leng *_length = min_c(ioSize, *_length); status_t result; + OpenState* state = cookie != NULL ? cookie->fOpenState : fOpenState; while (size < *_length && !*eof) { uint32 len = *_length - size; - result = ReadFile(cookie, fOpenState, pos + size, &len, + result = ReadFile(cookie, state, pos + size, &len, reinterpret_cast(buffer) + size, eof); if (result != B_OK) { if (size == 0) @@ -234,7 +300,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) status_t -Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer, +Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, size_t *_length) { uint32 size = 0; @@ -243,12 +309,20 @@ Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer, uint32 ioSize = fFileSystem->Root()->IOSize(); *_length = min_c(ioSize, *_length); - fWriteDirty = true; + bool attribute = false; + OpenState* state = fOpenState; + if (cookie != NULL) { + attribute = cookie->fOpenState->fInfo.fHandle != fInfo.fHandle; + state = cookie->fOpenState; + } + + if (!attribute) + fWriteDirty = true; while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, fOpenState, pos + size, &len, - buffer + size); + status_t result = WriteFile(cookie, state, pos + size, + &len, buffer + size, attribute); if (result != B_OK) { if (size == 0) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 901021c47a..d561e29424 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -83,7 +83,10 @@ MetadataCache::GetAccess(uid_t uid, uint32* allowed) if (!it.HasCurrent()) return B_ENTRY_NOT_FOUND; - if (it.Current().fExpire < time(NULL)) { + if (!fForceValid) + it.Current().fForceValid = false; + + if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) { it.Remove(); return B_ERROR; } @@ -105,6 +108,7 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) AccessEntry entry; entry.fAllowed = allowed; entry.fExpire = time(NULL) + kExpirationTime; + entry.fForceValid = fForceValid; fAccessCache.Insert(uid, entry); } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index 26a5e971f1..07a13a3c58 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -20,6 +20,8 @@ class Inode; struct AccessEntry { time_t fExpire; + bool fForceValid; + uint32 fAllowed; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index a026e18d5c..9c0953221e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -245,14 +245,17 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) status_t -NFS4Inode::GetStat(AttrValue** values, uint32* count) +NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (cookie != NULL) + req.PutFH(cookie->fOpenState->fInfo.fHandle); + else + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, FATTR4_OWNER, FATTR4_OWNER_GROUP, @@ -260,7 +263,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count) FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); + status_t result = request.Send(cookie); if (result != B_OK) return result; @@ -284,7 +287,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); if (state != NULL) req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); else @@ -313,21 +316,29 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) status_t NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, - uint64* fileID) + uint64* fileID, bool attribute) { do { RPC::Server* serv = from->fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(from->fInfo.fHandle); + if (attribute) + req.PutFH(from->fInfo.fAttrDir); + else + req.PutFH(from->fInfo.fHandle); req.SaveFH(); - req.PutFH(to->fInfo.fHandle); + if (attribute) + req.PutFH(to->fInfo.fAttrDir); + else + req.PutFH(to->fInfo.fHandle); req.Rename(fromName, toName); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - req.LookUp(toName); + if (!attribute) { + req.LookUp(toName); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } status_t result = request.Send(); if (result != B_OK) @@ -358,22 +369,24 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, if (result != B_OK) return result; - result = reply.LookUp(); - if (result != B_OK) - return result; + if (!attribute) { + result = reply.LookUp(); + if (result != B_OK) + return result; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - 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; + if (count == 0) + *fileID = from->fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; - delete[] values; + delete[] values; + } return B_OK; } while (true); @@ -581,7 +594,61 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) status_t -NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, +NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, + OpenDelegationData* delegation, bool create) +{ + bool confirm; + status_t result; + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); + do { + state->fClientID = fFileSystem->NFSServer()->ClientId(); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fAttrDir); + req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, + create ? OPEN4_CREATE : OPEN4_NOCREATE, fFileSystem->OpenOwner(), + name); + req.GetFH(); + + result = request.Send(); + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) + continue; + + fFileSystem->OpenOwnerSequenceUnlock(); + + reply.PutFH(); + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, + delegation); + + reply.GetFH(&state->fInfo.fHandle); + + if (result != B_OK) + return result; + + break; + } while (true); + + state->fOpened = true; + + if (confirm) + return ConfirmOpen(fInfo.fHandle, state); + + return B_OK; +} + + +status_t +NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, bool* eof) { do { @@ -589,7 +656,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); req.Read(state->fStateID, state->fStateSeq, position, *length); status_t result = request.Send(cookie); @@ -612,8 +679,8 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, status_t -NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, - uint32* length, const void* buffer) +NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, + uint32* length, const void* buffer, bool commit) { do { @@ -621,9 +688,10 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); - req.Write(state->fStateID, state->fStateSeq, buffer, position, *length); + req.Write(state->fStateID, state->fStateSeq, buffer, position, *length, + commit); status_t result = request.Send(cookie); if (result != B_OK) @@ -757,8 +825,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, req.PutFH(fInfo.fHandle); - Attribute idAttr[] = { FATTR4_FILEID }; - req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + if (type != NF4NAMEDATTR) { + Attribute idAttr[] = { FATTR4_FILEID }; + req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + } req.Remove(name); @@ -790,17 +860,19 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, reply.PutFH(); - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + if (type != NF4NAMEDATTR) { + 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; + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + delete[] values; + } return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, changeInfo->fAtomic); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index fad2e89c53..110cce7ffe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -38,9 +38,11 @@ protected: static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, - ChangeInfo* toChange, uint64* fileID); + ChangeInfo* toChange, uint64* fileID, + bool attribute = false); - status_t GetStat(AttrValue** values, uint32* count); + status_t GetStat(AttrValue** values, uint32* count, + OpenAttrCookie* attr = NULL); status_t WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount); @@ -51,12 +53,15 @@ protected: status_t OpenFile(OpenState* state, int mode, OpenDelegationData* delegation); - status_t ReadFile(OpenFileCookie* cookie, OpenState* state, + status_t OpenAttr(OpenState* state, const char* name, int mode, + OpenDelegationData* delegation, bool create); + + status_t ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, bool* eof); - status_t WriteFile(OpenFileCookie* cookie, OpenState* state, + status_t WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, - const void* buffer); + const void* buffer, bool commit = false); status_t CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 192e691f00..6663cc30ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -16,7 +16,7 @@ bool NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie, OpenState* state) + OpenStateCookie* cookie, OpenState* state) { uint32 leaseTime; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 79df6f1337..3af5129144 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -13,13 +13,13 @@ #include "RPCServer.h" -class OpenFileCookie; +class OpenStateCookie; class OpenState; class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie = NULL, OpenState* state = NULL); + OpenStateCookie* cookie = NULL, OpenState* state = NULL); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 04add4c0e4..3eab8254b7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -788,7 +788,7 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count) status_t RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, - uint64 pos, uint32 len) + uint64 pos, uint32 len, bool stable) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -801,7 +801,7 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, fRequest->Stream().AddUInt(id[1]); fRequest->Stream().AddUInt(id[2]); fRequest->Stream().AddUHyper(pos); - fRequest->Stream().AddInt(UNSTABLE4); + fRequest->Stream().AddInt(stable ? FILE_SYNC4 : UNSTABLE4); fRequest->Stream().AddOpaque(buffer, len); fOpCount++; @@ -862,6 +862,12 @@ void RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, uint32 count) { + if (count == 0) { + stream.AddUInt(0); + stream.AddOpaque(NULL, 0); + return; + } + Attribute* attrs = reinterpret_cast(malloc(sizeof(Attribute) * count)); for (uint32 i = 0; i < count; i++) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 9ef417413b..1b0ea90dc3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -78,7 +78,7 @@ public: status_t Verify(AttrValue* attr, uint32 count); status_t Write(const uint32* id, uint32 stateSeq, const void* buffer, uint64 pos, - uint32 len); + uint32 len, bool stable = false); status_t ReleaseLockOwner(OpenState* state, LockOwner* owner); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 17e1d7c8f5..e2483320c0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -636,7 +636,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) static status_t nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) { - return nfs4_close_attr_dir(volume, vnode, cookie); + return nfs4_close_dir(volume, vnode, cookie); } @@ -658,7 +658,125 @@ nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie, static status_t nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) { - return nfs4_rewind_attr_dir(volume, vnode, cookie); + return nfs4_rewind_dir(volume, vnode, cookie); +} + + +static status_t +nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name, + uint32 type, int openMode, void** _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = new OpenAttrCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + status_t result = inode->OpenAttr(name, openMode, cookie, true, type); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name, + int openMode, void** _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = new OpenAttrCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + status_t result = inode->OpenAttr(name, openMode, cookie, false); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + Cookie* cookie = reinterpret_cast(_cookie); + return cookie->CancelAll(); +} + + +static status_t +nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + inode->CloseAttr(cookie); + delete cookie; + + return B_OK; +} + + +static status_t +nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + bool eof; + return inode->ReadDirect(cookie, pos, buffer, length, &eof); +} + + +static status_t +nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + const void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->WriteDirect(cookie, pos, buffer, length); +} + + +static status_t +nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, + struct stat* stat) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->Stat(stat, cookie); +} + + +static status_t +nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, + const struct stat* stat, int statMask) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->WriteStat(stat, statMask, cookie); +} + + +static status_t +nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName, + fs_vnode* toVnode, const char* toName) +{ + Inode* fromInode = reinterpret_cast(fromVnode->private_node); + Inode* toInode = reinterpret_cast(toVnode->private_node); + return Inode::Rename(fromInode, toInode, fromName, toName, true); +} + + +static status_t +nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->Remove(name, NF4NAMEDATTR); } @@ -832,17 +950,17 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_rewind_attr_dir, /* attribute operations */ - NULL, // create_attr - NULL, // open_attr - NULL, // close_attr - NULL, // free_attr_cookie - NULL, // read_attr - NULL, // write_attr + nfs4_create_attr, + nfs4_open_attr, + nfs4_close_attr, + nfs4_free_attr_cookie, + nfs4_read_attr, + nfs4_write_attr, - NULL, // read_attr_stat - NULL, // write_attr_stat - NULL, // rename_attr - NULL, // remove_attr + nfs4_read_attr_stat, + nfs4_write_attr_stat, + nfs4_rename_attr, + nfs4_remove_attr, /* support for node and FS layers */ NULL, // create_special_node