nfs4: Renew all owned and used leases

This commit is contained in:
Pawel Dziepak 2012-06-13 02:38:51 +02:00
parent 6ee3ed0f6f
commit 27a291de54
7 changed files with 154 additions and 3 deletions

View File

@ -33,6 +33,7 @@ enum Opcode {
OpPutRootFH = 24,
OpRead = 25,
OpReadDir = 26,
OpRenew = 30,
OpSetClientID = 35,
OpSetClientIDConfirm = 36
};

View File

@ -13,6 +13,8 @@
NFS4Server::NFS4Server(RPC::Server* serv)
:
fThreadCancel(true),
fLeaseTime(0),
fCIDUseCount(0),
fSequenceId(0),
fServer(serv)
@ -23,6 +25,12 @@ NFS4Server::NFS4Server(RPC::Server* serv)
NFS4Server::~NFS4Server()
{
fThreadCancel = true;
fCIDUseCount = 0;
interrupt_thread(fThread);
status_t result;
wait_for_thread(fThread, &result);
mutex_destroy(&fLock);
}
@ -54,6 +62,8 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew)
result = request.Reply().SetClientIDConfirm();
if (result != B_OK)
goto out_unlock;
_StartRenewing();
}
fCIDUseCount++;
@ -72,3 +82,101 @@ NFS4Server::ReleaseCID(uint64 cid)
mutex_unlock(&fLock);
}
status_t
NFS4Server::_GetLeaseTime()
{
Request request(fServer);
request.Builder().PutRootFH();
Attribute attr[] = { FATTR4_LEASE_TIME };
request.Builder().GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
result = reply.PutRootFH();
if (result != B_OK)
return result;
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
// FATTR4_LEASE_TIM is mandatory
if (count < 1 || values[0].fAttribute != FATTR4_LEASE_TIME) {
delete[] values;
return B_BAD_VALUE;
}
fLeaseTime = values[0].fData.fValue32 * 1000000;
return B_OK;
}
status_t
NFS4Server::_StartRenewing()
{
if (!fThreadCancel)
return B_OK;
if (fLeaseTime == 0) {
status_t result = _GetLeaseTime();
if (result != B_OK)
return result;
}
fThreadCancel = false;
fThread = spawn_kernel_thread(&NFS4Server::_RenewalThreadStart,
"NFSv4 Renewal", B_NORMAL_PRIORITY, this);
if (fThread < B_OK)
return fThread;
status_t result = resume_thread(fThread);
if (result != B_OK) {
kill_thread(fThread);
return result;
}
return B_OK;
}
status_t
NFS4Server::_Renewal()
{
while (!fThreadCancel) {
// TODO: operations like OPEN, READ, CLOSE, etc also renew leases
snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT
| B_CAN_INTERRUPT);
mutex_lock(&fLock);
if (fCIDUseCount == 0) {
fThreadCancel = true;
mutex_unlock(&fLock);
return B_OK;
}
Request request(fServer);
request.Builder().Renew(fClientId);
request.Send();
mutex_unlock(&fLock);
}
return B_OK;
}
status_t
NFS4Server::_RenewalThreadStart(void* ptr)
{
NFS4Server* server = reinterpret_cast<NFS4Server*>(ptr);
return server->_Renewal();
}

View File

@ -24,6 +24,16 @@ public:
inline uint32 SequenceId();
private:
status_t _GetLeaseTime();
status_t _StartRenewing();
status_t _Renewal();
static status_t _RenewalThreadStart(void* ptr);
thread_id fThread;
bool fThreadCancel;
uint32 fLeaseTime;
uint64 fClientId;
uint32 fCIDUseCount;
mutex fLock;

View File

@ -323,6 +323,12 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
current++;
}
if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) {
values[current].fAttribute = FATTR4_LEASE_TIME;
values[current].fData.fValue32 = stream.GetUInt();
current++;
}
if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) {
values[current].fAttribute = FATTR4_FILEID;
values[current].fData.fValue64 = stream.GetUHyper();

View File

@ -58,6 +58,7 @@ public:
status_t Read(void* buffer, uint32* size, bool* eof);
status_t ReadDir(uint64* cookie, DirEntry** dirents,
uint32* count, bool* eof);
inline status_t Renew();
status_t SetClientID(uint64* clientid, uint64* verifier);
inline status_t SetClientIDConfirm();
@ -125,6 +126,13 @@ ReplyInterpreter::PutRootFH()
}
inline status_t
ReplyInterpreter::Renew()
{
return _OperationError(OpRenew);
}
inline status_t
ReplyInterpreter::SetClientIDConfirm()
{

View File

@ -262,7 +262,7 @@ RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len)
status_t
RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
uint32 attr_count)
uint32 attrCount)
{
(void)count;
@ -278,7 +278,24 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
// consider predicting this values basing on count or buffer size
fRequest->Stream().AddUInt(0x2000);
fRequest->Stream().AddUInt(0x8000);
_AttrBitmap(fRequest->Stream(), attrs, attr_count);
_AttrBitmap(fRequest->Stream(), attrs, attrCount);
fOpCount++;
return B_OK;
}
status_t
RequestBuilder::Renew(uint64 clientId)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpRenew);
fRequest->Stream().AddUHyper(clientId);
fOpCount++;

View File

@ -40,7 +40,8 @@ public:
status_t Read(const uint32* id, uint32 stateSeq,
uint64 pos, uint32 len);
status_t ReadDir(uint32 count, uint64* cookie,
Attribute* attrs, uint32 attr_count);
Attribute* attrs, uint32 attrCount);
status_t Renew(uint64 clientId);
status_t SetClientID(const RPC::Server* serv);
status_t SetClientIDConfirm(uint64 id, uint64 ver);