nfs4: Add basic support for extended attributes

This commit is contained in:
Pawel Dziepak
2012-08-09 23:39:56 +02:00
parent 29fb3a4af2
commit 20d1b02eef
17 changed files with 475 additions and 121 deletions
@@ -73,11 +73,12 @@ struct Cookie {
status_t CancelAll(); status_t CancelAll();
}; };
struct OpenFileCookie : public Cookie { struct OpenStateCookie : public Cookie {
OpenState* fOpenState; OpenState* fOpenState;
uint32 fMode; uint32 fMode;
};
struct OpenFileCookie : public OpenStateCookie {
LockInfo* fLocks; LockInfo* fLocks;
void AddLock(LockInfo* lock); void AddLock(LockInfo* lock);
@@ -97,6 +98,8 @@ struct OpenDirCookie : public Cookie {
~OpenDirCookie(); ~OpenDirCookie();
}; };
struct OpenAttrCookie : public OpenStateCookie { };
#endif // COOKIE_H #endif // COOKIE_H
@@ -14,11 +14,12 @@
Delegation::Delegation(const OpenDelegationData& data, Inode* inode, Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
uint64 clientID) uint64 clientID, bool attribute)
: :
fClientID(clientID), fClientID(clientID),
fData(data), fData(data),
fInode(inode) fInode(inode),
fAttribute(attribute)
{ {
} }
@@ -26,7 +27,7 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
status_t status_t
Delegation::GiveUp(bool truncate) Delegation::GiveUp(bool truncate)
{ {
if (!truncate) if (!fAttribute && !truncate)
fInode->SyncAndCommit(true); fInode->SyncAndCommit(true);
ReturnDelegation(); ReturnDelegation();
@@ -21,7 +21,7 @@ class Delegation : public NFS4Object,
public DoublyLinkedListLinkImpl<Delegation> { public DoublyLinkedListLinkImpl<Delegation> {
public: public:
Delegation(const OpenDelegationData& data, Inode* inode, Delegation(const OpenDelegationData& data, Inode* inode,
uint64 clientID); uint64 clientID, bool attr = false);
status_t GiveUp(bool truncate = false); status_t GiveUp(bool truncate = false);
@@ -35,6 +35,7 @@ private:
uint64 fClientID; uint64 fClientID;
OpenDelegationData fData; OpenDelegationData fData;
Inode* fInode; Inode* fInode;
bool fAttribute;
}; };
@@ -25,6 +25,8 @@ struct FileHandle {
inline FileHandle(const FileHandle& fh); inline FileHandle(const FileHandle& fh);
inline FileHandle& operator=(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;
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 inline bool
FileHandle::operator>(const FileHandle& handle) const FileHandle::operator>(const FileHandle& handle) const
{ {
+75 -37
View File
@@ -262,68 +262,100 @@ Inode::Link(Inode* dir, const char* name)
status_t status_t
Inode::Remove(const char* name, FileType type) Inode::Remove(const char* name, FileType type)
{ {
if (type == NF4NAMEDATTR) {
status_t result = LoadAttrDirHandle();
if (result != B_OK)
return result;
}
ChangeInfo changeInfo; ChangeInfo changeInfo;
uint64 fileID; uint64 fileID;
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
if (result != B_OK) if (result != B_OK)
return result; return result;
if (fCache->Lock() == B_OK) { DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache;
if (cache->Lock() == B_OK) {
if (changeInfo.fAtomic if (changeInfo.fAtomic
&& fCache->ChangeInfo() == changeInfo.fBefore) { && fCache->ChangeInfo() == changeInfo.fBefore) {
fCache->RemoveEntry(name); cache->RemoveEntry(name);
fCache->SetChangeInfo(changeInfo.fAfter); cache->SetChangeInfo(changeInfo.fAfter);
} else if (fCache->ChangeInfo() != changeInfo.fBefore) } else if (cache->ChangeInfo() != changeInfo.fBefore)
fCache->Trash(); cache->Trash();
fCache->Unlock(); cache->Unlock();
} }
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
notify_entry_removed(fFileSystem->DevId(), ID(), name, if (type == NF4NAMEDATTR) {
FileIdToInoT(fileID)); notify_attribute_changed(fFileSystem->DevId(), ID(), name,
B_ATTR_REMOVED);
} else {
notify_entry_removed(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
}
return B_OK; return B_OK;
} }
status_t 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) if (from->fFileSystem != to->fFileSystem)
return B_DONT_DO_THAT; 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; ChangeInfo fromChange, toChange;
uint64 fileID; uint64 fileID;
status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange,
&toChange, &fileID); &toChange, &fileID, attribute);
if (result != B_OK) if (result != B_OK)
return result; return result;
from->fFileSystem->Root()->MakeInfoInvalid(); 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 if (fromChange.fAtomic
&& from->fCache->ChangeInfo() == fromChange.fBefore) { && cache->ChangeInfo() == fromChange.fBefore) {
from->fCache->RemoveEntry(fromName); cache->RemoveEntry(fromName);
from->fCache->SetChangeInfo(fromChange.fAfter); cache->SetChangeInfo(fromChange.fAfter);
} else if (from->fCache->ChangeInfo() != fromChange.fBefore) } else if (cache->ChangeInfo() != fromChange.fBefore)
from->fCache->Trash(); cache->Trash();
from->fCache->Unlock(); cache->Unlock();
} }
if (to->fCache->Lock() == B_OK) { cache = attribute ? to->fAttrCache : to->fCache;
if (cache->Lock() == B_OK) {
if (toChange.fAtomic if (toChange.fAtomic
&& to->fCache->ChangeInfo() == toChange.fBefore) { && cache->ChangeInfo() == toChange.fBefore) {
to->fCache->AddEntry(toName, fileID, true); cache->AddEntry(toName, fileID, true);
to->fCache->SetChangeInfo(toChange.fAfter); cache->SetChangeInfo(toChange.fAfter);
} else if (to->fCache->ChangeInfo() != toChange.fBefore) } else if (to->fCache->ChangeInfo() != toChange.fBefore)
to->fCache->Trash(); cache->Trash();
to->fCache->Unlock(); cache->Unlock();
} }
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, if (attribute) {
to->ID(), toName, FileIdToInoT(fileID)); 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; return B_OK;
} }
@@ -404,8 +436,11 @@ Inode::Access(int mode)
status_t 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); status_t result = fMetaCache.GetStat(st);
if (result != B_OK) { if (result != B_OK) {
struct stat temp; struct stat temp;
@@ -421,11 +456,11 @@ Inode::Stat(struct stat* st)
status_t status_t
Inode::GetStat(struct stat* st) Inode::GetStat(struct stat* st, OpenAttrCookie* attr)
{ {
AttrValue* values; AttrValue* values;
uint32 count; uint32 count;
status_t result = NFS4Inode::GetStat(&values, &count); status_t result = NFS4Inode::GetStat(&values, &count, attr);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -504,7 +539,7 @@ Inode::GetStat(struct stat* st)
status_t status_t
Inode::WriteStat(const struct stat* st, uint32 mask) Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie)
{ {
status_t result; status_t result;
AttrValue attr[6]; AttrValue attr[6];
@@ -554,15 +589,18 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
i++; i++;
} }
MutexLocker stateLocker(fStateLock); if (cookie == NULL) {
result = NFS4Inode::WriteStat(fOpenState, attr, i); MutexLocker stateLocker(fStateLock);
stateLocker.Unlock(); result = NFS4Inode::WriteStat(fOpenState, attr, i);
stateLocker.Unlock();
fMetaCache.InvalidateStat(); fMetaCache.InvalidateStat();
if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0
|| (mask & B_STAT_GID) != 0) { || (mask & B_STAT_GID) != 0) {
fMetaCache.InvalidateAccess(); fMetaCache.InvalidateAccess();
} }
} else
result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i);
return result; return result;
} }
+18 -6
View File
@@ -57,24 +57,33 @@ public:
status_t Link(Inode* dir, const char* name); status_t Link(Inode* dir, const char* name);
status_t Remove(const char* name, FileType type); status_t Remove(const char* name, FileType type);
static status_t Rename(Inode* from, Inode* to, 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 Stat(struct stat* st,
status_t WriteStat(const struct stat* st, uint32 mask); 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, status_t Create(const char* name, int mode, int perms,
OpenFileCookie* cookie, OpenFileCookie* cookie,
OpenDelegationData* data, ino_t* id); OpenDelegationData* data, ino_t* id);
status_t Open(int mode, OpenFileCookie* cookie); status_t Open(int mode, OpenFileCookie* cookie);
status_t Close(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, status_t Read(OpenFileCookie* cookie, off_t pos,
void* buffer, size_t* length); void* buffer, size_t* length);
status_t Write(OpenFileCookie* cookie, off_t pos, status_t Write(OpenFileCookie* cookie, off_t pos,
const void* buffer, size_t *_length); 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); 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); const void* buffer, size_t *_length);
status_t CreateDir(const char* name, int mode); status_t CreateDir(const char* name, int mode);
@@ -96,6 +105,8 @@ public:
_snapshot, OpenDirCookie* cookie, _snapshot, OpenDirCookie* cookie,
uint64* _change, bool attribute); uint64* _change, bool attribute);
status_t LoadAttrDirHandle();
protected: protected:
Inode(); Inode();
@@ -115,7 +126,8 @@ protected:
status_t ChildAdded(const char* name, uint64 fileID, status_t ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle); 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); static inline status_t CheckLockType(short ltype, uint32 mode);
@@ -55,6 +55,13 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
cookie->fEOF = false; cookie->fEOF = false;
cookie->fAttrDir = true; cookie->fAttrDir = true;
return LoadAttrDirHandle();
}
status_t
Inode::LoadAttrDirHandle()
{
if (fInfo.fAttrDir.fSize == 0) { if (fInfo.fAttrDir.fSize == 0) {
FileHandle handle; FileHandle handle;
@@ -65,7 +72,7 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
fInfo.fAttrDir = handle; fInfo.fAttrDir = handle;
} }
return B_OK; return B_OK;
} }
@@ -193,7 +193,72 @@ Inode::Close(OpenFileCookie* cookie)
status_t 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) bool* eof)
{ {
*eof = false; *eof = false;
@@ -203,9 +268,10 @@ Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _leng
*_length = min_c(ioSize, *_length); *_length = min_c(ioSize, *_length);
status_t result; status_t result;
OpenState* state = cookie != NULL ? cookie->fOpenState : fOpenState;
while (size < *_length && !*eof) { while (size < *_length && !*eof) {
uint32 len = *_length - size; uint32 len = *_length - size;
result = ReadFile(cookie, fOpenState, pos + size, &len, result = ReadFile(cookie, state, pos + size, &len,
reinterpret_cast<char*>(buffer) + size, eof); reinterpret_cast<char*>(buffer) + size, eof);
if (result != B_OK) { if (result != B_OK) {
if (size == 0) if (size == 0)
@@ -234,7 +300,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
status_t 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) size_t *_length)
{ {
uint32 size = 0; uint32 size = 0;
@@ -243,12 +309,20 @@ Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer,
uint32 ioSize = fFileSystem->Root()->IOSize(); uint32 ioSize = fFileSystem->Root()->IOSize();
*_length = min_c(ioSize, *_length); *_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) { while (size < *_length) {
uint32 len = *_length - size; uint32 len = *_length - size;
status_t result = WriteFile(cookie, fOpenState, pos + size, &len, status_t result = WriteFile(cookie, state, pos + size,
buffer + size); &len, buffer + size, attribute);
if (result != B_OK) { if (result != B_OK) {
if (size == 0) if (size == 0)
return result; return result;
@@ -83,7 +83,10 @@ MetadataCache::GetAccess(uid_t uid, uint32* allowed)
if (!it.HasCurrent()) if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND; 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(); it.Remove();
return B_ERROR; return B_ERROR;
} }
@@ -105,6 +108,7 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed)
AccessEntry entry; AccessEntry entry;
entry.fAllowed = allowed; entry.fAllowed = allowed;
entry.fExpire = time(NULL) + kExpirationTime; entry.fExpire = time(NULL) + kExpirationTime;
entry.fForceValid = fForceValid;
fAccessCache.Insert(uid, entry); fAccessCache.Insert(uid, entry);
} }
@@ -20,6 +20,8 @@ class Inode;
struct AccessEntry { struct AccessEntry {
time_t fExpire; time_t fExpire;
bool fForceValid;
uint32 fAllowed; uint32 fAllowed;
}; };
@@ -245,14 +245,17 @@ NFS4Inode::ReadLink(void* buffer, size_t* length)
status_t status_t
NFS4Inode::GetStat(AttrValue** values, uint32* count) NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie)
{ {
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); 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, Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS,
FATTR4_OWNER, FATTR4_OWNER_GROUP, FATTR4_OWNER, FATTR4_OWNER_GROUP,
@@ -260,7 +263,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count)
FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send(); status_t result = request.Send(cookie);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -284,7 +287,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle); req.PutFH(state->fInfo.fHandle);
if (state != NULL) if (state != NULL)
req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount);
else else
@@ -313,21 +316,29 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
status_t status_t
NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName,
const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange,
uint64* fileID) uint64* fileID, bool attribute)
{ {
do { do {
RPC::Server* serv = from->fFileSystem->Server(); RPC::Server* serv = from->fFileSystem->Server();
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); 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.SaveFH();
req.PutFH(to->fInfo.fHandle); if (attribute)
req.PutFH(to->fInfo.fAttrDir);
else
req.PutFH(to->fInfo.fHandle);
req.Rename(fromName, toName); req.Rename(fromName, toName);
Attribute attr[] = { FATTR4_FILEID }; if (!attribute) {
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); req.LookUp(toName);
req.LookUp(toName); Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
}
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) if (result != B_OK)
@@ -358,22 +369,24 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName,
if (result != B_OK) if (result != B_OK)
return result; return result;
result = reply.LookUp(); if (!attribute) {
if (result != B_OK) result = reply.LookUp();
return result; if (result != B_OK)
return result;
AttrValue* values; AttrValue* values;
uint32 count; uint32 count;
result = reply.GetAttr(&values, &count); result = reply.GetAttr(&values, &count);
if (result != B_OK) if (result != B_OK)
return result; return result;
if (count == 0) if (count == 0)
*fileID = from->fFileSystem->AllocFileId(); *fileID = from->fFileSystem->AllocFileId();
else else
*fileID = values[0].fData.fValue64; *fileID = values[0].fData.fValue64;
delete[] values; delete[] values;
}
return B_OK; return B_OK;
} while (true); } while (true);
@@ -581,7 +594,61 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
status_t 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) uint32* length, void* buffer, bool* eof)
{ {
do { do {
@@ -589,7 +656,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle); req.PutFH(state->fInfo.fHandle);
req.Read(state->fStateID, state->fStateSeq, position, *length); req.Read(state->fStateID, state->fStateSeq, position, *length);
status_t result = request.Send(cookie); status_t result = request.Send(cookie);
@@ -612,8 +679,8 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
status_t status_t
NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
uint32* length, const void* buffer) uint32* length, const void* buffer, bool commit)
{ {
do { do {
@@ -621,9 +688,10 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); 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); status_t result = request.Send(cookie);
if (result != B_OK) if (result != B_OK)
@@ -757,8 +825,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
req.PutFH(fInfo.fHandle); req.PutFH(fInfo.fHandle);
Attribute idAttr[] = { FATTR4_FILEID }; if (type != NF4NAMEDATTR) {
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); Attribute idAttr[] = { FATTR4_FILEID };
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
}
req.Remove(name); req.Remove(name);
@@ -790,17 +860,19 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
reply.PutFH(); reply.PutFH();
AttrValue* values; if (type != NF4NAMEDATTR) {
uint32 count; AttrValue* values;
result = reply.GetAttr(&values, &count); uint32 count;
if (result != B_OK) result = reply.GetAttr(&values, &count);
return result; if (result != B_OK)
return result;
if (count == 0) if (count == 0)
*fileID = fFileSystem->AllocFileId(); *fileID = fFileSystem->AllocFileId();
else else
*fileID = values[0].fData.fValue64; *fileID = values[0].fData.fValue64;
delete[] values; delete[] values;
}
return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
changeInfo->fAtomic); changeInfo->fAtomic);
@@ -38,9 +38,11 @@ protected:
static status_t Rename(Inode* from, Inode* to, const char* fromName, static status_t Rename(Inode* from, Inode* to, const char* fromName,
const char* toName, ChangeInfo* fromChange, 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, status_t WriteStat(OpenState* state, AttrValue* attrs,
uint32 attrCount); uint32 attrCount);
@@ -51,12 +53,15 @@ protected:
status_t OpenFile(OpenState* state, int mode, status_t OpenFile(OpenState* state, int mode,
OpenDelegationData* delegation); 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, uint64 position, uint32* length, void* buffer,
bool* eof); bool* eof);
status_t WriteFile(OpenFileCookie* cookie, OpenState* state, status_t WriteFile(OpenStateCookie* cookie, OpenState* state,
uint64 position, uint32* length, uint64 position, uint32* length,
const void* buffer); const void* buffer, bool commit = false);
status_t CreateObject(const char* name, const char* path, status_t CreateObject(const char* name, const char* path,
int mode, FileType type, ChangeInfo* changeInfo, int mode, FileType type, ChangeInfo* changeInfo,
@@ -16,7 +16,7 @@
bool bool
NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
OpenFileCookie* cookie, OpenState* state) OpenStateCookie* cookie, OpenState* state)
{ {
uint32 leaseTime; uint32 leaseTime;
@@ -13,13 +13,13 @@
#include "RPCServer.h" #include "RPCServer.h"
class OpenFileCookie; class OpenStateCookie;
class OpenState; class OpenState;
class NFS4Object { class NFS4Object {
public: public:
bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, 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); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state);
@@ -788,7 +788,7 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count)
status_t status_t
RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
uint64 pos, uint32 len) uint64 pos, uint32 len, bool stable)
{ {
if (fProcedure != ProcCompound) if (fProcedure != ProcCompound)
return B_BAD_VALUE; 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[1]);
fRequest->Stream().AddUInt(id[2]); fRequest->Stream().AddUInt(id[2]);
fRequest->Stream().AddUHyper(pos); fRequest->Stream().AddUHyper(pos);
fRequest->Stream().AddInt(UNSTABLE4); fRequest->Stream().AddInt(stable ? FILE_SYNC4 : UNSTABLE4);
fRequest->Stream().AddOpaque(buffer, len); fRequest->Stream().AddOpaque(buffer, len);
fOpCount++; fOpCount++;
@@ -862,6 +862,12 @@ void
RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
uint32 count) uint32 count)
{ {
if (count == 0) {
stream.AddUInt(0);
stream.AddOpaque(NULL, 0);
return;
}
Attribute* attrs = Attribute* attrs =
reinterpret_cast<Attribute*>(malloc(sizeof(Attribute) * count)); reinterpret_cast<Attribute*>(malloc(sizeof(Attribute) * count));
for (uint32 i = 0; i < count; i++) for (uint32 i = 0; i < count; i++)
@@ -78,7 +78,7 @@ public:
status_t Verify(AttrValue* attr, uint32 count); status_t Verify(AttrValue* attr, uint32 count);
status_t Write(const uint32* id, uint32 stateSeq, status_t Write(const uint32* id, uint32 stateSeq,
const void* buffer, uint64 pos, const void* buffer, uint64 pos,
uint32 len); uint32 len, bool stable = false);
status_t ReleaseLockOwner(OpenState* state, status_t ReleaseLockOwner(OpenState* state,
LockOwner* owner); LockOwner* owner);
@@ -636,7 +636,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
static status_t static status_t
nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) 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 static status_t
nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) 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<Inode*>(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<Inode*>(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*>(_cookie);
return cookie->CancelAll();
}
static status_t
nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_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<Inode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_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<Inode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_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<Inode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_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<Inode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_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<Inode*>(fromVnode->private_node);
Inode* toInode = reinterpret_cast<Inode*>(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<Inode*>(vnode->private_node);
return inode->Remove(name, NF4NAMEDATTR);
} }
@@ -832,17 +950,17 @@ fs_vnode_ops gNFSv4VnodeOps = {
nfs4_rewind_attr_dir, nfs4_rewind_attr_dir,
/* attribute operations */ /* attribute operations */
NULL, // create_attr nfs4_create_attr,
NULL, // open_attr nfs4_open_attr,
NULL, // close_attr nfs4_close_attr,
NULL, // free_attr_cookie nfs4_free_attr_cookie,
NULL, // read_attr nfs4_read_attr,
NULL, // write_attr nfs4_write_attr,
NULL, // read_attr_stat nfs4_read_attr_stat,
NULL, // write_attr_stat nfs4_write_attr_stat,
NULL, // rename_attr nfs4_rename_attr,
NULL, // remove_attr nfs4_remove_attr,
/* support for node and FS layers */ /* support for node and FS layers */
NULL, // create_special_node NULL, // create_special_node