nfs4: Behave correctly if server is in grace period

This commit is contained in:
Pawel Dziepak
2012-06-29 02:14:49 +02:00
parent b268b6f2fc
commit 8b499ea677
2 changed files with 110 additions and 56 deletions
+97 -55
View File
@@ -336,32 +336,49 @@ Inode::Stat(struct stat* st)
status_t status_t
Inode::Open(int mode, OpenFileCookie* cookie) Inode::Open(int mode, OpenFileCookie* cookie)
{ {
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutFH(fParentFH);
req.Open(fFilesystem->NFSServer()->SequenceId(), OPEN4_SHARE_ACCESS_READ,
cookie->fClientId, OPEN4_NOCREATE, fName);
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
result = reply.PutFH();
if (result != B_OK)
return result;
bool confirm; bool confirm;
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); status_t result;
if (result != B_OK) do {
return result; cookie->fClientId = fFilesystem->NFSServer()->ClientId();
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutFH(fParentFH);
req.Open(fFilesystem->NFSServer()->SequenceId(),
OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, fName);
result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
// server is in grace period, we need to wait
if (reply.NFS4Error() == NFS4ERR_GRACE) {
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
if (result != B_OK)
return result;
break;
} while (true);
if (confirm) { if (confirm) {
request.Reset(); Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutFH(fHandle); req.PutFH(fHandle);
req.OpenConfirm(fFilesystem->NFSServer()->SequenceId(), req.OpenConfirm(fFilesystem->NFSServer()->SequenceId(),
cookie->fStateId, cookie->fStateSeq); cookie->fStateId, cookie->fStateSeq);
@@ -370,6 +387,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
if (result != B_OK) if (result != B_OK)
return result; return result;
ReplyInterpreter& reply = request.Reply();
result = reply.PutFH(); result = reply.PutFH();
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -386,28 +405,39 @@ Inode::Open(int mode, OpenFileCookie* cookie)
status_t status_t
Inode::Close(OpenFileCookie* cookie) Inode::Close(OpenFileCookie* cookie)
{ {
Request request(fFilesystem->Server()); do {
RequestBuilder& req = request.Builder(); Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutFH(fHandle); req.PutFH(fHandle);
req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId,
cookie->fStateSeq); cookie->fStateSeq);
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) if (result != B_OK)
return result; return result;
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
result = reply.PutFH(); // server is in grace period, we need to wait
if (result != B_OK) if (reply.NFS4Error() == NFS4ERR_GRACE) {
return result; snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
continue;
}
result = reply.Close(); result = reply.PutFH();
if (result != B_OK) if (result != B_OK)
return result; return result;
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); result = reply.Close();
if (result != B_OK)
return result;
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
return B_OK;
} while (true);
return B_OK; return B_OK;
} }
@@ -421,28 +451,40 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
uint32 len = 0; uint32 len = 0;
while (size < *_length && !eof) { while (size < *_length && !eof) {
Request request(fFilesystem->Server()); do {
RequestBuilder& req = request.Builder(); Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutFH(fHandle); req.PutFH(fHandle);
req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, req.Read(cookie->fStateId, cookie->fStateSeq, pos + size,
*_length - size); *_length - size);
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) if (result != B_OK)
return result; return result;
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
result = reply.PutFH(); // server is in grace period, we need to wait
if (result != B_OK) if (reply.NFS4Error() == NFS4ERR_GRACE) {
return result; snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
continue;
}
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len, &eof); result = reply.PutFH();
if (result != B_OK) if (result != B_OK)
return result; return result;
size += len; result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
&eof);
if (result != B_OK)
return result;
size += len;
break;
} while (true);
} }
*_length = size; *_length = size;
@@ -23,6 +23,8 @@ public:
void ReleaseCID(uint64 cid); void ReleaseCID(uint64 cid);
inline uint32 SequenceId(); inline uint32 SequenceId();
inline uint32 LeaseTime();
private: private:
status_t _GetLeaseTime(); status_t _GetLeaseTime();
@@ -43,12 +45,22 @@ private:
RPC::Server* fServer; RPC::Server* fServer;
}; };
uint32 inline uint32
NFS4Server::SequenceId() NFS4Server::SequenceId()
{ {
return static_cast<uint32>(atomic_add(&fSequenceId, 1)); return static_cast<uint32>(atomic_add(&fSequenceId, 1));
} }
inline uint32
NFS4Server::LeaseTime()
{
if (fLeaseTime == 0)
_GetLeaseTime();
return fLeaseTime;
}
#endif // NFS4SERVER_H #endif // NFS4SERVER_H