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 <arpa/inet.h>
#include <string.h>
#include <arpa/inet.h>
#include <lock.h>
#include <net/dns_resolver.h>
#include "Request.h"
@ -24,15 +25,24 @@ extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv);
Filesystem::Filesystem()
:
fNext(NULL),
fPrev(NULL),
fOpenFiles(NULL),
fOpenCount(0),
fPath(NULL),
fName(NULL),
fId(1)
{
mutex_init(&fOpenLock, NULL);
}
Filesystem::~Filesystem()
{
NFSServer()->RemoveFilesystem(this);
mutex_destroy(&fOpenLock);
free(const_cast<char*>(fName));
free(const_cast<char*>(fPath));
}
@ -170,6 +180,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
*pfs = fs;
delete[] values;
fs->NFSServer()->AddFilesystem(fs);
return B_OK;
}
@ -351,3 +363,47 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
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,
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 uint32 ExpireType() const;
@ -46,9 +52,16 @@ public:
inline dev_t DevId() const;
inline InodeIdMap* InoIdMap();
Filesystem* fNext;
Filesystem* fPrev;
private:
Filesystem();
OpenFileCookie* fOpenFiles;
uint32 fOpenCount;
mutex fOpenLock;
uint32 fExpireType;
uint32 fSupAttrs[2];
@ -69,6 +82,13 @@ private:
};
inline uint32
Filesystem::OpenFilesCount()
{
return fOpenCount;
}
inline bool
Filesystem::IsAttrSupported(Attribute attr) const
{

View File

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

View File

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

View File

@ -14,6 +14,7 @@
#include "RPCServer.h"
class Filesystem;
class OpenFileCookie;
class NFS4Server : public RPC::ProgramData {
@ -22,11 +23,14 @@ public:
virtual ~NFS4Server();
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);
void ReleaseCID(uint64 cid);
inline uint32 LeaseTime();
private:
@ -44,16 +48,36 @@ private:
uint32 fLeaseTime;
uint64 fClientId;
uint32 fCIDUseCount;
mutex fLock;
bool fClientIdInit;
time_t fClientIdLastUse;
mutex fClientIdLock;
OpenFileCookie* fOpenFiles;
mutex fOpenLock;
uint32 fUseCount;
Filesystem* fFilesystems;
mutex fFSLock;
RPC::Server* fServer;
};
inline void
NFS4Server::IncUsage()
{
MutexLocker _(fFSLock);
fUseCount++;
if (fThreadCancel)
_StartRenewing();
}
inline void
NFS4Server::DecUsage()
{
MutexLocker _(fFSLock);
fUseCount--;
}
inline uint32
NFS4Server::LeaseTime()
{