nfs4: Let opened files survive server reboot
This commit is contained in:
@@ -338,15 +338,23 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
{
|
{
|
||||||
bool confirm;
|
bool confirm;
|
||||||
status_t result;
|
status_t result;
|
||||||
|
|
||||||
|
cookie->fHandle = fHandle;
|
||||||
|
cookie->fMode = mode;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||||
|
|
||||||
Request request(fFilesystem->Server());
|
Request request(fFilesystem->Server());
|
||||||
RequestBuilder& req = request.Builder();
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
cookie->fOwnerTime = time(NULL);
|
||||||
|
cookie->fOwnerTID = find_thread(NULL);
|
||||||
|
|
||||||
req.PutFH(fParentFH);
|
req.PutFH(fParentFH);
|
||||||
req.Open(fFilesystem->NFSServer()->SequenceId(),
|
req.Open(CLAIM_NULL, fFilesystem->NFSServer()->SequenceId(),
|
||||||
OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, fName);
|
OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE,
|
||||||
|
cookie->fOwnerTime, cookie->fOwnerTID, fName);
|
||||||
|
|
||||||
result = request.Send();
|
result = request.Send();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
@@ -374,6 +382,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
|
fFilesystem->NFSServer()->AddOpenFile(cookie);
|
||||||
|
|
||||||
if (confirm) {
|
if (confirm) {
|
||||||
Request request(fFilesystem->Server());
|
Request request(fFilesystem->Server());
|
||||||
|
|
||||||
@@ -384,18 +394,24 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
cookie->fStateId, cookie->fStateSeq);
|
cookie->fStateId, cookie->fStateSeq);
|
||||||
|
|
||||||
result = request.Send();
|
result = request.Send();
|
||||||
if (result != B_OK)
|
if (result != B_OK) {
|
||||||
|
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ReplyInterpreter& reply = request.Reply();
|
ReplyInterpreter& reply = request.Reply();
|
||||||
|
|
||||||
result = reply.PutFH();
|
result = reply.PutFH();
|
||||||
if (result != B_OK)
|
if (result != B_OK) {
|
||||||
|
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = reply.OpenConfirm(&cookie->fStateSeq);
|
result = reply.OpenConfirm(&cookie->fStateSeq);
|
||||||
if (result != B_OK)
|
if (result != B_OK) {
|
||||||
|
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -405,6 +421,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
status_t
|
status_t
|
||||||
Inode::Close(OpenFileCookie* cookie)
|
Inode::Close(OpenFileCookie* cookie)
|
||||||
{
|
{
|
||||||
|
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Request request(fFilesystem->Server());
|
Request request(fFilesystem->Server());
|
||||||
RequestBuilder& req = request.Builder();
|
RequestBuilder& req = request.Builder();
|
||||||
@@ -472,6 +490,13 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
|||||||
continue;
|
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();
|
result = reply.PutFH();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -19,9 +19,19 @@
|
|||||||
|
|
||||||
|
|
||||||
struct OpenFileCookie {
|
struct OpenFileCookie {
|
||||||
uint64 fClientId;
|
uint64 fClientId;
|
||||||
uint32 fStateId[3];
|
|
||||||
uint32 fStateSeq;
|
uint32 fMode;
|
||||||
|
|
||||||
|
Filehandle fHandle;
|
||||||
|
uint32 fStateId[3];
|
||||||
|
uint32 fStateSeq;
|
||||||
|
|
||||||
|
uint32 fOwnerTime;
|
||||||
|
uint32 fOwnerTID;
|
||||||
|
|
||||||
|
OpenFileCookie* fNext;
|
||||||
|
OpenFileCookie* fPrev;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Inode {
|
class Inode {
|
||||||
|
|||||||
@@ -146,6 +146,13 @@ enum OpenCreate {
|
|||||||
OPEN4_CREATE = 1
|
OPEN4_CREATE = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum OpenClaim {
|
||||||
|
CLAIM_NULL = 0,
|
||||||
|
CLAIM_PREVIOUS = 1,
|
||||||
|
CLAIM_DELEGATE_CUR = 2,
|
||||||
|
CLAIM_DELEGATE_PREV = 3
|
||||||
|
};
|
||||||
|
|
||||||
enum OpenFlags {
|
enum OpenFlags {
|
||||||
OPEN4_RESULT_CONFIRM = 2,
|
OPEN4_RESULT_CONFIRM = 2,
|
||||||
OPEN4_RESULT_LOCKTYPE_POSIX = 4
|
OPEN4_RESULT_LOCKTYPE_POSIX = 4
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Inode.h"
|
||||||
#include "NFS4Server.h"
|
#include "NFS4Server.h"
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
|
|
||||||
@@ -17,9 +18,11 @@ NFS4Server::NFS4Server(RPC::Server* serv)
|
|||||||
fLeaseTime(0),
|
fLeaseTime(0),
|
||||||
fCIDUseCount(0),
|
fCIDUseCount(0),
|
||||||
fSequenceId(0),
|
fSequenceId(0),
|
||||||
|
fOpenFiles(NULL),
|
||||||
fServer(serv)
|
fServer(serv)
|
||||||
{
|
{
|
||||||
mutex_init(&fLock, NULL);
|
mutex_init(&fLock, NULL);
|
||||||
|
mutex_init(&fOpenLock, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +35,110 @@ NFS4Server::~NFS4Server()
|
|||||||
wait_for_thread(fThread, &result);
|
wait_for_thread(fThread, &result);
|
||||||
|
|
||||||
mutex_destroy(&fLock);
|
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
|
snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT
|
||||||
| B_CAN_INTERRUPT);
|
| B_CAN_INTERRUPT);
|
||||||
mutex_lock(&fLock);
|
mutex_lock(&fLock);
|
||||||
|
|
||||||
|
uint64 clientId = fClientId;
|
||||||
|
|
||||||
if (fCIDUseCount == 0) {
|
if (fCIDUseCount == 0) {
|
||||||
fThreadCancel = true;
|
fThreadCancel = true;
|
||||||
mutex_unlock(&fLock);
|
mutex_unlock(&fLock);
|
||||||
@@ -165,8 +275,10 @@ NFS4Server::_Renewal()
|
|||||||
Request request(fServer);
|
Request request(fServer);
|
||||||
request.Builder().Renew(fClientId);
|
request.Builder().Renew(fClientId);
|
||||||
request.Send();
|
request.Send();
|
||||||
|
|
||||||
mutex_unlock(&fLock);
|
mutex_unlock(&fLock);
|
||||||
|
|
||||||
|
if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID)
|
||||||
|
ServerRebooted(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -14,11 +14,17 @@
|
|||||||
#include "RPCServer.h"
|
#include "RPCServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
class OpenFileCookie;
|
||||||
|
|
||||||
class NFS4Server : public RPC::ProgramData {
|
class NFS4Server : public RPC::ProgramData {
|
||||||
public:
|
public:
|
||||||
NFS4Server(RPC::Server* serv);
|
NFS4Server(RPC::Server* serv);
|
||||||
virtual ~NFS4Server();
|
virtual ~NFS4Server();
|
||||||
|
|
||||||
|
uint64 ServerRebooted(uint64 clientId);
|
||||||
|
void AddOpenFile(OpenFileCookie* cookie);
|
||||||
|
void RemoveOpenFile(OpenFileCookie* cookie);
|
||||||
|
|
||||||
uint64 ClientId(uint64 prevId = 0, bool forceNew = false);
|
uint64 ClientId(uint64 prevId = 0, bool forceNew = false);
|
||||||
void ReleaseCID(uint64 cid);
|
void ReleaseCID(uint64 cid);
|
||||||
|
|
||||||
@@ -26,6 +32,8 @@ public:
|
|||||||
|
|
||||||
inline uint32 LeaseTime();
|
inline uint32 LeaseTime();
|
||||||
private:
|
private:
|
||||||
|
status_t _ReclaimOpen(OpenFileCookie* cookie);
|
||||||
|
|
||||||
status_t _GetLeaseTime();
|
status_t _GetLeaseTime();
|
||||||
|
|
||||||
status_t _StartRenewing();
|
status_t _StartRenewing();
|
||||||
@@ -42,6 +50,9 @@ private:
|
|||||||
|
|
||||||
vint32 fSequenceId;
|
vint32 fSequenceId;
|
||||||
|
|
||||||
|
OpenFileCookie* fOpenFiles;
|
||||||
|
mutex fOpenLock;
|
||||||
|
|
||||||
RPC::Server* fServer;
|
RPC::Server* fServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ RequestBuilder::LookUpUp()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc,
|
RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id,
|
||||||
const char* name)
|
OpenCreate oc, uint32 ownerTime, uint32 ownerTID, const char* name)
|
||||||
{
|
{
|
||||||
if (fProcedure != ProcCompound)
|
if (fProcedure != ProcCompound)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -168,17 +168,26 @@ RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc,
|
|||||||
|
|
||||||
char owner[128];
|
char owner[128];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
*(uint32*)(owner + pos) = time(NULL);
|
*(uint32*)(owner + pos) = ownerTime;
|
||||||
pos += sizeof(uint32);
|
pos += sizeof(uint32);
|
||||||
|
|
||||||
*(uint32*)(owner + pos) = find_thread(NULL);
|
*(uint32*)(owner + pos) = ownerTID;
|
||||||
pos += sizeof(uint32);
|
pos += sizeof(uint32);
|
||||||
|
|
||||||
fRequest->Stream().AddOpaque(owner, pos);
|
fRequest->Stream().AddOpaque(owner, pos);
|
||||||
|
|
||||||
fRequest->Stream().AddUInt(oc);
|
fRequest->Stream().AddUInt(oc);
|
||||||
fRequest->Stream().AddUInt(0); // claim null
|
fRequest->Stream().AddUInt(claim);
|
||||||
fRequest->Stream().AddString(name, strlen(name));
|
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++;
|
fOpCount++;
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ public:
|
|||||||
status_t GetFH();
|
status_t GetFH();
|
||||||
status_t LookUp(const char* name);
|
status_t LookUp(const char* name);
|
||||||
status_t LookUpUp();
|
status_t LookUpUp();
|
||||||
status_t Open(uint32 seq, uint32 access, uint64 id,
|
status_t Open(OpenClaim claim, uint32 seq,
|
||||||
OpenCreate oc, const char* name);
|
uint32 access, uint64 id, OpenCreate oc,
|
||||||
|
uint32 ownerTime, uint32 ownerTID,
|
||||||
|
const char* name);
|
||||||
status_t OpenConfirm(uint32 seq, const uint32* id,
|
status_t OpenConfirm(uint32 seq, const uint32* id,
|
||||||
uint32 stateSeq);
|
uint32 stateSeq);
|
||||||
status_t PutFH(const Filehandle& fh);
|
status_t PutFH(const Filehandle& fh);
|
||||||
|
|||||||
Reference in New Issue
Block a user