nfs4: Filesystem is responsible for its opened files

This commit is contained in:
Pawel Dziepak 2012-06-28 21:01:33 +02:00
parent ecf46259e7
commit 55f2930931
5 changed files with 165 additions and 69 deletions

View File

@ -9,9 +9,10 @@
#include "Filesystem.h" #include "Filesystem.h"
#include <arpa/inet.h>
#include <string.h> #include <string.h>
#include <arpa/inet.h> #include <lock.h>
#include <net/dns_resolver.h> #include <net/dns_resolver.h>
#include "Request.h" #include "Request.h"
@ -24,15 +25,24 @@ extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv);
Filesystem::Filesystem() Filesystem::Filesystem()
: :
fNext(NULL),
fPrev(NULL),
fOpenFiles(NULL),
fOpenCount(0),
fPath(NULL), fPath(NULL),
fName(NULL), fName(NULL),
fId(1) fId(1)
{ {
mutex_init(&fOpenLock, NULL);
} }
Filesystem::~Filesystem() Filesystem::~Filesystem()
{ {
NFSServer()->RemoveFilesystem(this);
mutex_destroy(&fOpenLock);
free(const_cast<char*>(fName)); free(const_cast<char*>(fName));
free(const_cast<char*>(fPath)); free(const_cast<char*>(fPath));
} }
@ -170,6 +180,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
*pfs = fs; *pfs = fs;
delete[] values; delete[] values;
fs->NFSServer()->AddFilesystem(fs);
return B_OK; return B_OK;
} }
@ -351,3 +363,47 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
return B_OK; return B_OK;
} }
OpenFileCookie*
Filesystem::OpenFilesLock()
{
mutex_lock(&fOpenLock);
return fOpenFiles;
}
void
Filesystem::OpenFilesUnlock()
{
mutex_unlock(&fOpenLock);
}
void
Filesystem::AddOpenFile(OpenFileCookie* cookie)
{
MutexLocker _(fOpenLock);
cookie->fPrev = NULL;
cookie->fNext = fOpenFiles;
if (fOpenFiles != NULL)
fOpenFiles->fPrev = cookie;
fOpenFiles = cookie;
NFSServer()->IncUsage();
}
void
Filesystem::RemoveOpenFile(OpenFileCookie* cookie)
{
MutexLocker _(fOpenLock);
if (cookie == fOpenFiles)
fOpenFiles = cookie->fNext;
if (cookie->fNext)
cookie->fNext->fPrev = cookie->fPrev;
if (cookie->fPrev)
cookie->fPrev->fNext = cookie->fNext;
NFSServer()->DecUsage();
}

View File

@ -33,6 +33,12 @@ public:
status_t Migrate(const Filehandle& fh, status_t Migrate(const Filehandle& fh,
const RPC::Server* serv); const RPC::Server* serv);
OpenFileCookie* OpenFilesLock();
void OpenFilesUnlock();
inline uint32 OpenFilesCount();
void AddOpenFile(OpenFileCookie* cookie);
void RemoveOpenFile(OpenFileCookie* cookie);
inline bool IsAttrSupported(Attribute attr) const; inline bool IsAttrSupported(Attribute attr) const;
inline uint32 ExpireType() const; inline uint32 ExpireType() const;
@ -46,9 +52,16 @@ public:
inline dev_t DevId() const; inline dev_t DevId() const;
inline InodeIdMap* InoIdMap(); inline InodeIdMap* InoIdMap();
Filesystem* fNext;
Filesystem* fPrev;
private: private:
Filesystem(); Filesystem();
OpenFileCookie* fOpenFiles;
uint32 fOpenCount;
mutex fOpenLock;
uint32 fExpireType; uint32 fExpireType;
uint32 fSupAttrs[2]; uint32 fSupAttrs[2];
@ -69,6 +82,13 @@ private:
}; };
inline uint32
Filesystem::OpenFilesCount()
{
return fOpenCount;
}
inline bool inline bool
Filesystem::IsAttrSupported(Attribute attr) const Filesystem::IsAttrSupported(Attribute attr) const
{ {

View File

@ -676,7 +676,7 @@ sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie)
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) { if (result != B_OK) {
fs->NFSServer()->RemoveOpenFile(cookie); fs->RemoveOpenFile(cookie);
return result; return result;
} }
@ -686,7 +686,7 @@ sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie)
result = reply.OpenConfirm(&cookie->fStateSeq); result = reply.OpenConfirm(&cookie->fStateSeq);
if (result != B_OK) { if (result != B_OK) {
fs->NFSServer()->RemoveOpenFile(cookie); fs->RemoveOpenFile(cookie);
return result; return result;
} }
@ -745,8 +745,6 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (reply.NFS4Error() == NFS4ERR_GRACE)
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
if (_HandleErrors(reply.NFS4Error(), serv)) if (_HandleErrors(reply.NFS4Error(), serv))
continue; continue;
@ -791,7 +789,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
break; break;
} while (true); } while (true);
fFilesystem->NFSServer()->AddOpenFile(cookie); fFilesystem->AddOpenFile(cookie);
if (confirm) if (confirm)
return sConfirmOpen(fFilesystem, fh, cookie); return sConfirmOpen(fFilesystem, fh, cookie);
@ -861,8 +859,6 @@ Inode::Open(int mode, OpenFileCookie* cookie)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (reply.NFS4Error() == NFS4ERR_GRACE)
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
if (_HandleErrors(reply.NFS4Error(), serv)) if (_HandleErrors(reply.NFS4Error(), serv))
continue; continue;
@ -889,7 +885,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
break; break;
} while (true); } while (true);
fFilesystem->NFSServer()->AddOpenFile(cookie); fFilesystem->AddOpenFile(cookie);
if (confirm) if (confirm)
return sConfirmOpen(fFilesystem, fHandle, cookie); return sConfirmOpen(fFilesystem, fHandle, cookie);
@ -901,7 +897,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
status_t status_t
Inode::Close(OpenFileCookie* cookie) Inode::Close(OpenFileCookie* cookie)
{ {
fFilesystem->NFSServer()->RemoveOpenFile(cookie); fFilesystem->RemoveOpenFile(cookie);
do { do {
RPC::Server* serv = fFilesystem->Server(); RPC::Server* serv = fFilesystem->Server();
@ -926,8 +922,6 @@ Inode::Close(OpenFileCookie* cookie)
if (result != B_OK) if (result != B_OK)
return result; return result;
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
return B_OK; return B_OK;
} while (true); } while (true);

View File

@ -7,6 +7,7 @@
*/ */
#include "Filesystem.h"
#include "Inode.h" #include "Inode.h"
#include "NFS4Server.h" #include "NFS4Server.h"
#include "Request.h" #include "Request.h"
@ -16,25 +17,26 @@ NFS4Server::NFS4Server(RPC::Server* serv)
: :
fThreadCancel(true), fThreadCancel(true),
fLeaseTime(0), fLeaseTime(0),
fCIDUseCount(0), fClientIdLastUse(0),
fOpenFiles(NULL), fUseCount(0),
fFilesystems(NULL),
fServer(serv) fServer(serv)
{ {
mutex_init(&fLock, NULL); mutex_init(&fClientIdLock, NULL);
mutex_init(&fOpenLock, NULL); mutex_init(&fFSLock, NULL);
} }
NFS4Server::~NFS4Server() NFS4Server::~NFS4Server()
{ {
fThreadCancel = true; fThreadCancel = true;
fCIDUseCount = 0; fUseCount = 0;
interrupt_thread(fThread); interrupt_thread(fThread);
status_t result; status_t result;
wait_for_thread(fThread, &result); wait_for_thread(fThread, &result);
mutex_destroy(&fLock); mutex_destroy(&fClientIdLock);
mutex_destroy(&fOpenLock); mutex_destroy(&fFSLock);
} }
@ -46,13 +48,18 @@ NFS4Server::ServerRebooted(uint64 clientId)
fClientId = ClientId(clientId, true); fClientId = ClientId(clientId, true);
// reclaim all open files // reclaim all opened files and held locks from all filesystems
MutexLocker _(fOpenLock); MutexLocker _(fFSLock);
OpenFileCookie* current = fOpenFiles; Filesystem* fs = fFilesystems;
while (current != NULL) { while (fs != NULL) {
_ReclaimOpen(current); OpenFileCookie* current = fs->OpenFilesLock();
_ReclaimLocks(current); while (current != NULL) {
current = current->fNext; _ReclaimOpen(current);
_ReclaimLocks(current);
current = current->fNext;
}
fs->OpenFilesUnlock();
fs = fs->fNext;
} }
return fClientId; return fClientId;
@ -141,36 +148,42 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
void void
NFS4Server::AddOpenFile(OpenFileCookie* cookie) NFS4Server::AddFilesystem(Filesystem* fs)
{ {
MutexLocker _(fOpenLock); MutexLocker _(fFSLock);
cookie->fPrev = NULL; fs->fPrev = NULL;
cookie->fNext = fOpenFiles; fs->fNext = fFilesystems;
if (fOpenFiles != NULL) if (fFilesystems != NULL)
fOpenFiles->fPrev = cookie; fFilesystems->fPrev = fs;
fOpenFiles = cookie; fFilesystems = fs;
fUseCount += fs->OpenFilesCount();
if (fs->OpenFilesCount() > 0 && fThreadCancel)
_StartRenewing();
} }
void void
NFS4Server::RemoveOpenFile(OpenFileCookie* cookie) NFS4Server::RemoveFilesystem(Filesystem* fs)
{ {
MutexLocker _(fOpenLock); MutexLocker _(fFSLock);
if (cookie == fOpenFiles) if (fs == fFilesystems)
fOpenFiles = cookie->fNext; fFilesystems = fs->fNext;
if (cookie->fNext) if (fs->fNext)
cookie->fNext->fPrev = cookie->fPrev; fs->fNext->fPrev = fs->fPrev;
if (cookie->fPrev) if (fs->fPrev)
cookie->fPrev->fNext = cookie->fNext; fs->fPrev->fNext = fs->fNext;
fUseCount -= fs->OpenFilesCount();
} }
uint64 uint64
NFS4Server::ClientId(uint64 prevId, bool forceNew) NFS4Server::ClientId(uint64 prevId, bool forceNew)
{ {
MutexLocker _(fLock); MutexLocker _(fClientIdLock);
if ((forceNew && fClientId == prevId) || fCIDUseCount == 0) { if (fClientIdLastUse + (time_t)LeaseTime() < time(NULL)
|| forceNew && fClientId == prevId) {
Request request(fServer); Request request(fServer);
request.Builder().SetClientID(fServer); request.Builder().SetClientID(fServer);
@ -193,24 +206,13 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew)
result = request.Reply().SetClientIDConfirm(); result = request.Reply().SetClientIDConfirm();
if (result != B_OK) if (result != B_OK)
return fClientId; return fClientId;
_StartRenewing();
} }
fCIDUseCount++; fClientIdLastUse = time(NULL);
return fClientId; return fClientId;
} }
void
NFS4Server::ReleaseCID(uint64 cid)
{
MutexLocker _(fLock);
fCIDUseCount--;
}
status_t status_t
NFS4Server::_GetLeaseTime() NFS4Server::_GetLeaseTime()
{ {
@ -233,7 +235,7 @@ NFS4Server::_GetLeaseTime()
if (result != B_OK) if (result != B_OK)
return result; return result;
// FATTR4_LEASE_TIM is mandatory // FATTR4_LEASE_TIME is mandatory
if (count < 1 || values[0].fAttribute != FATTR4_LEASE_TIME) { if (count < 1 || values[0].fAttribute != FATTR4_LEASE_TIME) {
delete[] values; delete[] values;
return B_BAD_VALUE; return B_BAD_VALUE;
@ -251,7 +253,6 @@ NFS4Server::_StartRenewing()
if (!fThreadCancel) if (!fThreadCancel)
return B_OK; return B_OK;
if (fLeaseTime == 0) { if (fLeaseTime == 0) {
status_t result = _GetLeaseTime(); status_t result = _GetLeaseTime();
if (result != B_OK) if (result != B_OK)
@ -281,19 +282,20 @@ NFS4Server::_Renewal()
// TODO: operations like OPEN, READ, CLOSE, etc also renew leases // TODO: operations like OPEN, READ, CLOSE, etc also renew leases
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);
MutexLocker locker(fLock);
uint64 clientId = fClientId; uint64 clientId = fClientId;
if (fCIDUseCount == 0) { if (fUseCount == 0) {
fThreadCancel = true; MutexLocker _(fFSLock);
return B_OK; if (fUseCount == 0) {
fThreadCancel = true;
return B_OK;
}
} }
Request request(fServer); Request request(fServer);
request.Builder().Renew(fClientId); request.Builder().Renew(fClientId);
request.Send(); request.Send();
locker.Unlock();
if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID)
ServerRebooted(clientId); ServerRebooted(clientId);

View File

@ -14,6 +14,7 @@
#include "RPCServer.h" #include "RPCServer.h"
class Filesystem;
class OpenFileCookie; class OpenFileCookie;
class NFS4Server : public RPC::ProgramData { class NFS4Server : public RPC::ProgramData {
@ -22,11 +23,14 @@ public:
virtual ~NFS4Server(); virtual ~NFS4Server();
uint64 ServerRebooted(uint64 clientId); uint64 ServerRebooted(uint64 clientId);
void AddOpenFile(OpenFileCookie* cookie);
void RemoveOpenFile(OpenFileCookie* cookie); void AddFilesystem(Filesystem* fs);
void RemoveFilesystem(Filesystem* fs);
inline void IncUsage();
inline void DecUsage();
uint64 ClientId(uint64 prevId = 0, bool forceNew = false); uint64 ClientId(uint64 prevId = 0, bool forceNew = false);
void ReleaseCID(uint64 cid);
inline uint32 LeaseTime(); inline uint32 LeaseTime();
private: private:
@ -44,16 +48,36 @@ private:
uint32 fLeaseTime; uint32 fLeaseTime;
uint64 fClientId; uint64 fClientId;
uint32 fCIDUseCount; bool fClientIdInit;
mutex fLock; time_t fClientIdLastUse;
mutex fClientIdLock;
OpenFileCookie* fOpenFiles; uint32 fUseCount;
mutex fOpenLock; Filesystem* fFilesystems;
mutex fFSLock;
RPC::Server* fServer; RPC::Server* fServer;
}; };
inline void
NFS4Server::IncUsage()
{
MutexLocker _(fFSLock);
fUseCount++;
if (fThreadCancel)
_StartRenewing();
}
inline void
NFS4Server::DecUsage()
{
MutexLocker _(fFSLock);
fUseCount--;
}
inline uint32 inline uint32
NFS4Server::LeaseTime() NFS4Server::LeaseTime()
{ {