nfs4: Filesystem is responsible for its opened files
This commit is contained in:
parent
ecf46259e7
commit
55f2930931
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user