nfs4: Let opened files survive server reboot

This commit is contained in:
Pawel Dziepak 2012-06-13 21:37:37 +02:00
parent 8b499ea677
commit d1e6b61e2e
7 changed files with 193 additions and 17 deletions

View File

@ -338,15 +338,23 @@ Inode::Open(int mode, OpenFileCookie* cookie)
{
bool confirm;
status_t result;
cookie->fHandle = fHandle;
cookie->fMode = mode;
do {
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
cookie->fOwnerTime = time(NULL);
cookie->fOwnerTID = find_thread(NULL);
req.PutFH(fParentFH);
req.Open(fFilesystem->NFSServer()->SequenceId(),
OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, fName);
req.Open(CLAIM_NULL, fFilesystem->NFSServer()->SequenceId(),
OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE,
cookie->fOwnerTime, cookie->fOwnerTID, fName);
result = request.Send();
if (result != B_OK)
@ -374,6 +382,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
break;
} while (true);
fFilesystem->NFSServer()->AddOpenFile(cookie);
if (confirm) {
Request request(fFilesystem->Server());
@ -384,18 +394,24 @@ Inode::Open(int mode, OpenFileCookie* cookie)
cookie->fStateId, cookie->fStateSeq);
result = request.Send();
if (result != B_OK)
if (result != B_OK) {
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
return result;
}
ReplyInterpreter& reply = request.Reply();
result = reply.PutFH();
if (result != B_OK)
if (result != B_OK) {
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
return result;
}
result = reply.OpenConfirm(&cookie->fStateSeq);
if (result != B_OK)
if (result != B_OK) {
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
return result;
}
}
return B_OK;
@ -405,6 +421,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
status_t
Inode::Close(OpenFileCookie* cookie)
{
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
do {
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
@ -472,6 +490,13 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
continue;
}
// server has rebooted, reclaim share and try again
if (reply.NFS4Error() == NFS4ERR_STALE_CLIENTID ||
reply.NFS4Error() == NFS4ERR_STALE_STATEID) {
fFilesystem->NFSServer()->ServerRebooted(cookie->fClientId);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;

View File

@ -19,9 +19,19 @@
struct OpenFileCookie {
uint64 fClientId;
uint32 fStateId[3];
uint32 fStateSeq;
uint64 fClientId;
uint32 fMode;
Filehandle fHandle;
uint32 fStateId[3];
uint32 fStateSeq;
uint32 fOwnerTime;
uint32 fOwnerTID;
OpenFileCookie* fNext;
OpenFileCookie* fPrev;
};
class Inode {

View File

@ -146,6 +146,13 @@ enum OpenCreate {
OPEN4_CREATE = 1
};
enum OpenClaim {
CLAIM_NULL = 0,
CLAIM_PREVIOUS = 1,
CLAIM_DELEGATE_CUR = 2,
CLAIM_DELEGATE_PREV = 3
};
enum OpenFlags {
OPEN4_RESULT_CONFIRM = 2,
OPEN4_RESULT_LOCKTYPE_POSIX = 4

View File

@ -7,6 +7,7 @@
*/
#include "Inode.h"
#include "NFS4Server.h"
#include "Request.h"
@ -17,9 +18,11 @@ NFS4Server::NFS4Server(RPC::Server* serv)
fLeaseTime(0),
fCIDUseCount(0),
fSequenceId(0),
fOpenFiles(NULL),
fServer(serv)
{
mutex_init(&fLock, NULL);
mutex_init(&fOpenLock, NULL);
}
@ -32,6 +35,110 @@ NFS4Server::~NFS4Server()
wait_for_thread(fThread, &result);
mutex_destroy(&fLock);
mutex_destroy(&fOpenLock);
}
uint64
NFS4Server::ServerRebooted(uint64 clientId)
{
if (clientId != fClientId)
return fClientId;
fClientId = ClientId(clientId, true);
// reclaim all open files
mutex_lock(&fOpenLock);
OpenFileCookie* current = fOpenFiles;
while (current != NULL) {
_ReclaimOpen(current);
current = current->fNext;
}
mutex_unlock(&fOpenLock);
return fClientId;
}
status_t
NFS4Server::_ReclaimOpen(OpenFileCookie* cookie)
{
if (cookie->fClientId == fClientId)
return B_OK;
cookie->fClientId = fClientId;
Request request(fServer);
RequestBuilder& req = request.Builder();
req.PutFH(cookie->fHandle);
req.Open(CLAIM_PREVIOUS, SequenceId(), OPEN4_SHARE_ACCESS_READ,
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerTime,
cookie->fOwnerTID, NULL);
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;
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
if (result != B_OK)
return result;
if (confirm) {
request.Reset();
req.PutFH(cookie->fHandle);
req.OpenConfirm(SequenceId(), cookie->fStateId, cookie->fStateSeq);
result = request.Send();
if (result != B_OK)
return result;
result = reply.PutFH();
if (result != B_OK)
return result;
result = reply.OpenConfirm(&cookie->fStateSeq);
if (result != B_OK)
return result;
}
return B_OK;
}
void
NFS4Server::AddOpenFile(OpenFileCookie* cookie)
{
mutex_lock(&fOpenLock);
cookie->fPrev = NULL;
cookie->fNext = fOpenFiles;
if (fOpenFiles != NULL)
fOpenFiles->fPrev = cookie;
fOpenFiles = cookie;
mutex_unlock(&fOpenLock);
}
void
NFS4Server::RemoveOpenFile(OpenFileCookie* cookie)
{
mutex_lock(&fOpenLock);
if (cookie == fOpenFiles)
fOpenFiles = cookie->fNext;
if (cookie->fNext)
cookie->fNext->fPrev = cookie->fPrev;
if (cookie->fPrev)
cookie->fPrev->fNext = cookie->fNext;
mutex_unlock(&fOpenLock);
}
@ -156,6 +263,9 @@ NFS4Server::_Renewal()
snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT
| B_CAN_INTERRUPT);
mutex_lock(&fLock);
uint64 clientId = fClientId;
if (fCIDUseCount == 0) {
fThreadCancel = true;
mutex_unlock(&fLock);
@ -165,8 +275,10 @@ NFS4Server::_Renewal()
Request request(fServer);
request.Builder().Renew(fClientId);
request.Send();
mutex_unlock(&fLock);
if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID)
ServerRebooted(clientId);
}
return B_OK;

View File

@ -14,11 +14,17 @@
#include "RPCServer.h"
class OpenFileCookie;
class NFS4Server : public RPC::ProgramData {
public:
NFS4Server(RPC::Server* serv);
virtual ~NFS4Server();
uint64 ServerRebooted(uint64 clientId);
void AddOpenFile(OpenFileCookie* cookie);
void RemoveOpenFile(OpenFileCookie* cookie);
uint64 ClientId(uint64 prevId = 0, bool forceNew = false);
void ReleaseCID(uint64 cid);
@ -26,6 +32,8 @@ public:
inline uint32 LeaseTime();
private:
status_t _ReclaimOpen(OpenFileCookie* cookie);
status_t _GetLeaseTime();
status_t _StartRenewing();
@ -42,6 +50,9 @@ private:
vint32 fSequenceId;
OpenFileCookie* fOpenFiles;
mutex fOpenLock;
RPC::Server* fServer;
};

View File

@ -152,8 +152,8 @@ RequestBuilder::LookUpUp()
status_t
RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc,
const char* name)
RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id,
OpenCreate oc, uint32 ownerTime, uint32 ownerTID, const char* name)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
@ -168,17 +168,26 @@ RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc,
char owner[128];
int pos = 0;
*(uint32*)(owner + pos) = time(NULL);
*(uint32*)(owner + pos) = ownerTime;
pos += sizeof(uint32);
*(uint32*)(owner + pos) = find_thread(NULL);
*(uint32*)(owner + pos) = ownerTID;
pos += sizeof(uint32);
fRequest->Stream().AddOpaque(owner, pos);
fRequest->Stream().AddUInt(oc);
fRequest->Stream().AddUInt(0); // claim null
fRequest->Stream().AddString(name, strlen(name));
fRequest->Stream().AddUInt(claim);
switch (claim) {
case CLAIM_NULL:
fRequest->Stream().AddString(name, strlen(name));
break;
case CLAIM_PREVIOUS:
fRequest->Stream().AddUInt(0);
break;
default:
return B_UNSUPPORTED;
}
fOpCount++;

View File

@ -31,8 +31,10 @@ public:
status_t GetFH();
status_t LookUp(const char* name);
status_t LookUpUp();
status_t Open(uint32 seq, uint32 access, uint64 id,
OpenCreate oc, const char* name);
status_t Open(OpenClaim claim, uint32 seq,
uint32 access, uint64 id, OpenCreate oc,
uint32 ownerTime, uint32 ownerTID,
const char* name);
status_t OpenConfirm(uint32 seq, const uint32* id,
uint32 stateSeq);
status_t PutFH(const Filehandle& fh);