mirror of
https://review.haiku-os.org/haiku
synced 2025-02-07 06:16:11 +01:00
nfs4: Let opened files survive server reboot
This commit is contained in:
parent
8b499ea677
commit
d1e6b61e2e
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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++;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user