nfs4: Use global open owner, check whether delegation was granted

This commit is contained in:
Pawel Dziepak
2012-08-05 19:37:58 +02:00
parent 5a9212d612
commit 990922235b
13 changed files with 182 additions and 55 deletions
@@ -551,7 +551,7 @@ ConnectionBase::Disconnect()
status_t
ConnectionListener::Listen(ConnectionListener** _listener, uint16 port)
ConnectionListener::Listen(ConnectionListener** listener, uint16 port)
{
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
@@ -577,16 +577,13 @@ ConnectionListener::Listen(ConnectionListener** _listener, uint16 port)
address.fProtocol = IPPROTO_TCP;
memset(&address.fAddress, 0, sizeof(address.fAddress));
ConnectionListener* listener;
listener = new(std::nothrow) ConnectionListener(address);
if (listener == NULL) {
*listener = new(std::nothrow) ConnectionListener(address);
if (*listener == NULL) {
close(sock);
return B_NO_MEMORY;
}
listener->fSocket = sock;
*_listener = listener;
(*listener)->fSocket = sock;
return B_OK;
}
@@ -27,10 +27,16 @@ FileSystem::FileSystem()
fPrev(NULL),
fOpenFiles(NULL),
fOpenCount(0),
fOpenOwnerSequence(0),
fPath(NULL),
fRoot(NULL),
fId(1)
{
fOpenOwner = rand();
fOpenOwner <<= 32;
fOpenOwner |= rand();
mutex_init(&fOpenOwnerLock, NULL);
mutex_init(&fOpenLock, NULL);
}
@@ -40,6 +46,7 @@ FileSystem::~FileSystem()
NFSServer()->RemoveFileSystem(this);
mutex_destroy(&fOpenLock);
mutex_destroy(&fOpenOwnerLock);
free(const_cast<char*>(fPath));
delete fRoot;
@@ -51,6 +51,10 @@ public:
inline dev_t DevId() const;
inline InodeIdMap* InoIdMap();
inline uint64 OpenOwner() const;
inline uint32 OpenOwnerSequenceLock();
inline void OpenOwnerSequenceUnlock(bool increment = true);
FileSystem* fNext;
FileSystem* fPrev;
private:
@@ -62,6 +66,10 @@ private:
uint32 fOpenCount;
mutex fOpenLock;
uint64 fOpenOwner;
uint32 fOpenOwnerSequence;
mutex fOpenOwnerLock;
uint32 fExpireType;
uint32 fSupAttrs[2];
@@ -163,5 +171,29 @@ FileSystem::InoIdMap()
}
inline uint64
FileSystem::OpenOwner() const
{
return fOpenOwner;
}
inline uint32
FileSystem::OpenOwnerSequenceLock()
{
mutex_lock(&fOpenOwnerLock);
return fOpenOwnerSequence;
}
inline void
FileSystem::OpenOwnerSequenceUnlock(bool increment = true)
{
if (increment)
fOpenOwnerSequence++;
mutex_unlock(&fOpenOwnerLock);
}
#endif // FILESYSTEM_H
@@ -207,11 +207,32 @@ enum OpenClaim {
CLAIM_DELEGATE_PREV = 3
};
enum OpenDelegation {
OPEN_DELEGATE_NONE = 0,
OPEN_DELEGATE_READ = 1,
OPEN_DELEGATE_WRITE = 2
};
struct OpenDelegationData {
OpenDelegation fType;
uint32 fStateSeq;
uint32 fStateID[3];
bool fRecall;
uint64 fSpaceLimit;
};
enum OpenFlags {
OPEN4_RESULT_CONFIRM = 2,
OPEN4_RESULT_LOCKTYPE_POSIX = 4
};
enum {
NFS_LIMIT_SIZE = 1,
NFS_LIMIT_BLOCKS = 2
};
struct ChangeInfo {
bool fAtomic;
uint64 fBefore;
@@ -389,6 +389,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
status_t result;
bool badOwner = false;
OpenDelegationData delegation;
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
state->fClientID = fFileSystem->NFSServer()->ClientId();
@@ -396,8 +398,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
Request request(serv);
RequestBuilder& req = request.Builder();
state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1);
req.PutFH(fInfo.fHandle);
AttrValue cattr[4];
@@ -427,9 +427,9 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
i++;
}
req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode),
state->fClientID, OPEN4_CREATE, state->fOwnerID, name, cattr,
i, (mode & O_EXCL) == O_EXCL);
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name,
cattr, i, (mode & O_EXCL) == O_EXCL);
req.GetFH();
@@ -439,22 +439,29 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
}
result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
fFileSystem->OpenOwnerSequenceUnlock();
sequence = fFileSystem->OpenOwnerSequenceLock();
badOwner = true;
continue;
}
if (HandleErrors(reply.NFS4Error(), serv))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
reply.PutFH();
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
&changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic);
&delegation, changeInfo);
if (result != B_OK)
return result;
@@ -488,8 +495,10 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
status_t
NFS4Inode::OpenFile(OpenState* state, int mode)
{
OpenDelegationData delegation;
bool confirm;
status_t result;
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
state->fClientID = fFileSystem->NFSServer()->ClientId();
@@ -497,8 +506,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
Request request(serv);
RequestBuilder& req = request.Builder();
state->fOwnerID = atomic_add64(&state->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)) {
@@ -526,22 +533,27 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
attr.fAttribute = FATTR4_SIZE;
attr.fFreePointer = false;
attr.fData.fValue64 = 0;
req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode),
state->fClientID, OPEN4_CREATE, state->fOwnerID, fInfo.fName,
&attr, 1, false);
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(),
fInfo.fName, &attr, 1, false);
} else
req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode),
state->fClientID, OPEN4_NOCREATE, state->fOwnerID, fInfo.fName);
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName);
req.GetFH();
result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
// Verify if the file we want to open is the file this Inode
// represents.
if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
@@ -558,7 +570,12 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
}
reply.PutFH();
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm);
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
&delegation);
FileHandle handle;
reply.GetFH(&handle);
if (result != B_OK)
return result;
@@ -570,6 +587,9 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
if (confirm)
return ConfirmOpen(fInfo.fHandle, state);
if (delegation.fType != OPEN_DELEGATE_NONE)
dprintf("GOT A DELEGATION!\n");
return B_OK;
}
@@ -891,6 +911,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position,
status_t
NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
{
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
MutexLocker ownerLocker(lockInfo->fOwner->fLock);
@@ -899,11 +920,13 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.Lock(cookie, lockInfo);
req.Lock(cookie, lockInfo, sequence);
status_t result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter &reply = request.Reply();
@@ -912,13 +935,16 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
ownerLocker.Unlock();
if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
fFileSystem->OpenOwnerSequenceUnlock();
snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
B_RELATIVE_TIMEOUT);
sequence = fFileSystem->OpenOwnerSequenceLock();
continue;
}
if (HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
if (result != B_OK)
return result;
@@ -103,6 +103,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
status_t
NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state)
{
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
@@ -110,17 +111,21 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state)
RequestBuilder& req = request.Builder();
req.PutFH(fh);
req.OpenConfirm(state->fSequence++, state->fStateID, state->fStateSeq);
req.OpenConfirm(sequence, state->fStateID, state->fStateSeq);
status_t result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
reply.PutFH();
result = reply.OpenConfirm(&state->fStateSeq);
if (result != B_OK)
@@ -15,11 +15,8 @@
#include "Request.h"
vint64 OpenState::fLastOwnerID = 0;
OpenState::OpenState()
:
fSequence(0),
fOpened(false)
{
mutex_init(&fLock, NULL);
@@ -46,27 +43,34 @@ OpenState::Reclaim(uint64 newClientID)
fClientID = newClientID;
bool confirm;
OpenDelegationData delegation;
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
RPC::Server* server = fFileSystem->Server();
Request request(server);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.Open(CLAIM_PREVIOUS, fSequence++, sModeToAccess(fMode), newClientID,
OPEN4_NOCREATE, fOwnerID, NULL);
req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID,
OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL);
status_t result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), server))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
reply.PutFH();
result = reply.Open(fStateID, &fStateSeq, &confirm);
result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation);
if (result != B_OK)
return result;
} while (true);
@@ -87,24 +91,29 @@ OpenState::Close()
MutexLocker _(fLock);
fOpened = false;
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.Close(fSequence++, fStateID, fStateSeq);
req.Close(sequence, fStateID, fStateSeq);
status_t result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFileSystem->OpenOwnerSequenceUnlock(false);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, this))
continue;
fFileSystem->OpenOwnerSequenceUnlock();
reply.PutFH();
return reply.Close();
} while (true);
}
@@ -28,14 +28,8 @@ struct OpenState : public NFS4Object, public KernelReferenceable {
uint32 fStateID[3];
uint32 fStateSeq;
uint32 fSequence;
uint64 fOwnerID;
static vint64 fLastOwnerID;
bool fOpened;
status_t Reclaim(uint64 newClientID);
status_t Close();
@@ -287,6 +287,7 @@ CallbackServer::ListenerThread()
{
while (fThreadRunning) {
Connection* connection;
status_t result = fListener->AcceptConnection(&connection);
if (result != B_OK) {
fThreadRunning = false;
@@ -266,8 +266,8 @@ ReplyInterpreter::LockU(LockInfo* linfo)
status_t
ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before,
uint64* _after, bool* _atomic)
ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm,
OpenDelegationData* delegData, ChangeInfo* changeInfo)
{
status_t res = _OperationError(OpOpen);
if (res != B_OK)
@@ -280,14 +280,13 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before,
// change info
bool atomic = fReply->Stream().GetBoolean();
if (_atomic != NULL)
*_atomic = atomic;
uint64 before = fReply->Stream().GetUHyper();
if (_before != NULL)
*_before = before;
uint64 after = fReply->Stream().GetUHyper();
if (_after != NULL)
*_after = after;
if (changeInfo != NULL) {
changeInfo->fAtomic = atomic;
changeInfo->fBefore = before;
changeInfo->fAfter = after;
}
uint32 flags = fReply->Stream().GetUInt();
*confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM;
@@ -298,7 +297,41 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before,
fReply->Stream().GetUInt();
// delegation info
uint32 delegation = fReply->Stream().GetUInt();
if (delegation == OPEN_DELEGATE_NONE) {
delegData->fType = OPEN_DELEGATE_NONE;
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
delegData->fStateSeq = fReply->Stream().GetUInt();
delegData->fStateID[0] = fReply->Stream().GetUInt();
delegData->fStateID[1] = fReply->Stream().GetUInt();
delegData->fStateID[2] = fReply->Stream().GetUInt();
delegData->fRecall = fReply->Stream().GetBoolean();
switch (delegation) {
case OPEN_DELEGATE_READ:
delegData->fType = OPEN_DELEGATE_READ;
break;
case OPEN_DELEGATE_WRITE:
delegData->fType = OPEN_DELEGATE_WRITE;
int32 limitBy = fReply->Stream().GetInt();
if (limitBy == NFS_LIMIT_SIZE)
delegData->fSpaceLimit = fReply->Stream().GetUHyper();
else if (limitBy == NFS_LIMIT_BLOCKS) {
uint32 numBlocks = fReply->Stream().GetUInt();
delegData->fSpaceLimit = fReply->Stream().GetUInt() * numBlocks;
}
break;
}
// ACE data
fReply->Stream().GetUInt();
fReply->Stream().GetUInt();
fReply->Stream().GetUInt();
fReply->Stream().GetOpaque(NULL);
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
@@ -81,8 +81,8 @@ public:
inline status_t LookUpUp();
inline status_t Nverify();
status_t Open(uint32* id, uint32* seq, bool* confirm,
uint64* before = NULL, uint64* after = NULL,
bool* atomic = NULL);
OpenDelegationData* delegData,
ChangeInfo* changeInfo = NULL);
status_t OpenConfirm(uint32* stateSeq);
inline status_t PutFH();
inline status_t PutRootFH();
@@ -186,7 +186,8 @@ RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
status_t
RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence,
bool reclaim)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
@@ -213,7 +214,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
else
state = cookie->fWriteState;
fRequest->Stream().AddUInt(state->fSequence++);
fRequest->Stream().AddUInt(sequence);
fRequest->Stream().AddUInt(state->fStateSeq);
fRequest->Stream().AddUInt(state->fStateID[0]);
fRequest->Stream().AddUInt(state->fStateID[1]);
@@ -41,7 +41,8 @@ public:
status_t GetFH();
status_t Link(const char* name);
status_t Lock(OpenFileCookie* cookie,
LockInfo* lock, bool reclaim = false);
LockInfo* lock, uint32 sequence,
bool reclaim = false);
status_t LockT(LockType type, uint64 pos,
uint64 len, OpenFileCookie* cookie);
status_t LockU(LockInfo* lock);