From d1e6b61e2e9523967fce63900692bafe3765d10f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 21:37:37 +0200 Subject: [PATCH] nfs4: Let opened files survive server reboot --- .../kernel/file_systems/nfs4/Inode.cpp | 35 +++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 16 ++- .../kernel/file_systems/nfs4/NFS4Defs.h | 7 ++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 114 +++++++++++++++++- .../kernel/file_systems/nfs4/NFS4Server.h | 11 ++ .../file_systems/nfs4/RequestBuilder.cpp | 21 +++- .../kernel/file_systems/nfs4/RequestBuilder.h | 6 +- 7 files changed, 193 insertions(+), 17 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 23a3f70cd9..d1bc6a85e1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 43fb9bdef3..edbfbece07 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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 { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index b0f9773e49..fefe9efb39 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 3bf1b5d3b5..3eab8ab502 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -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; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 506b62e5d4..1bdc5a9f66 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -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; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d361b861d6..5a97137b0e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 21e2ecbf77..c13ea4365e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -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);