nfs4: Allow the server to release unused lock owners
This commit is contained in:
@@ -134,6 +134,7 @@ Cookie::CancelAll()
|
|||||||
|
|
||||||
OpenFileCookie::OpenFileCookie()
|
OpenFileCookie::OpenFileCookie()
|
||||||
:
|
:
|
||||||
|
fLocks(NULL),
|
||||||
fLockOwners(NULL)
|
fLockOwners(NULL)
|
||||||
{
|
{
|
||||||
mutex_init(&fLocksLock, NULL);
|
mutex_init(&fLocksLock, NULL);
|
||||||
@@ -151,8 +152,6 @@ OpenFileCookie::~OpenFileCookie()
|
|||||||
LockOwner*
|
LockOwner*
|
||||||
OpenFileCookie::GetLockOwner(uint32 owner)
|
OpenFileCookie::GetLockOwner(uint32 owner)
|
||||||
{
|
{
|
||||||
MutexLocker _(fOwnerLock);
|
|
||||||
|
|
||||||
LockOwner* current = fLockOwners;
|
LockOwner* current = fLockOwners;
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
if (current->fOwner == owner)
|
if (current->fOwner == owner)
|
||||||
@@ -211,7 +210,26 @@ OpenFileCookie::DeleteLock(LockInfo* lock)
|
|||||||
if (owner->fNext)
|
if (owner->fNext)
|
||||||
owner->fNext->fPrev = owner->fPrev;
|
owner->fNext->fPrev = owner->fPrev;
|
||||||
|
|
||||||
|
_ReleaseLockOwner(owner);
|
||||||
delete owner;
|
delete owner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenFileCookie::_ReleaseLockOwner(LockOwner* owner)
|
||||||
|
{
|
||||||
|
Request request(fFilesystem->Server());
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.ReleaseLockOwner(this, owner);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
|
||||||
|
return reply.ReleaseLockOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ struct OpenFileCookie : public Cookie {
|
|||||||
void AddLock(LockInfo* lock);
|
void AddLock(LockInfo* lock);
|
||||||
void RemoveLock(LockInfo* lock, LockInfo* prev);
|
void RemoveLock(LockInfo* lock, LockInfo* prev);
|
||||||
void DeleteLock(LockInfo* lock);
|
void DeleteLock(LockInfo* lock);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ReleaseLockOwner(LockOwner* owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OpenDirCookie : public Cookie {
|
struct OpenDirCookie : public Cookie {
|
||||||
|
|||||||
@@ -735,6 +735,8 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
|
|||||||
|
|
||||||
thread_info info;
|
thread_info info;
|
||||||
get_thread_info(find_thread(NULL), &info);
|
get_thread_info(find_thread(NULL), &info);
|
||||||
|
|
||||||
|
MutexLocker locker(cookie->fOwnerLock);
|
||||||
LockOwner* owner = cookie->GetLockOwner(info.team);
|
LockOwner* owner = cookie->GetLockOwner(info.team);
|
||||||
if (owner == NULL)
|
if (owner == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@@ -742,6 +744,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
|
|||||||
LockInfo* linfo = new LockInfo(owner);
|
LockInfo* linfo = new LockInfo(owner);
|
||||||
if (linfo == NULL)
|
if (linfo == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
linfo->fStart = lock->l_start;
|
linfo->fStart = lock->l_start;
|
||||||
if (lock->l_len + lock->l_start == OFF_MAX)
|
if (lock->l_len + lock->l_start == OFF_MAX)
|
||||||
@@ -862,35 +865,38 @@ status_t
|
|||||||
Inode::ReleaseAllLocks(OpenFileCookie* cookie)
|
Inode::ReleaseAllLocks(OpenFileCookie* cookie)
|
||||||
{
|
{
|
||||||
MutexLocker _(cookie->fLocksLock);
|
MutexLocker _(cookie->fLocksLock);
|
||||||
while (cookie->fLocks != NULL) {
|
LockInfo* linfo = cookie->fLocks;
|
||||||
|
while (linfo != NULL) {
|
||||||
do {
|
do {
|
||||||
MutexLocker ownerLocker(cookie->fLocks->fOwner->fLock);
|
MutexLocker ownerLocker(linfo->fOwner->fLock);
|
||||||
|
|
||||||
RPC::Server* serv = fFilesystem->Server();
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
Request request(serv);
|
Request request(serv);
|
||||||
RequestBuilder& req = request.Builder();
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
req.PutFH(fHandle);
|
req.PutFH(fHandle);
|
||||||
req.LockU(cookie->fLocks);
|
req.LockU(linfo);
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
if (result != B_OK);
|
if (result != B_OK)
|
||||||
return result;
|
break;
|
||||||
|
|
||||||
ReplyInterpreter &reply = request.Reply();
|
ReplyInterpreter& reply = request.Reply();
|
||||||
|
|
||||||
reply.PutFH();
|
reply.PutFH();
|
||||||
reply.LockU(cookie->fLocks);
|
reply.LockU(linfo);
|
||||||
|
|
||||||
ownerLocker.Unlock();
|
ownerLocker.Unlock();
|
||||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
LockInfo* linfo = cookie->fLocks;
|
|
||||||
cookie->RemoveLock(linfo, NULL);
|
cookie->RemoveLock(linfo, NULL);
|
||||||
cookie->DeleteLock(linfo);
|
cookie->DeleteLock(linfo);
|
||||||
|
|
||||||
|
linfo = cookie->fLocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ enum Opcode {
|
|||||||
OpSetClientID = 35,
|
OpSetClientID = 35,
|
||||||
OpSetClientIDConfirm = 36,
|
OpSetClientIDConfirm = 36,
|
||||||
OpVerify = 37,
|
OpVerify = 37,
|
||||||
OpWrite = 38
|
OpWrite = 38,
|
||||||
|
OpReleaseLockOwner = 39
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Access {
|
enum Access {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ public:
|
|||||||
inline status_t SetClientIDConfirm();
|
inline status_t SetClientIDConfirm();
|
||||||
inline status_t Verify();
|
inline status_t Verify();
|
||||||
status_t Write(uint32* size);
|
status_t Write(uint32* size);
|
||||||
|
inline status_t ReleaseLockOwner();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _ParseHeader();
|
void _ParseHeader();
|
||||||
@@ -206,5 +207,12 @@ ReplyInterpreter::Verify()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline status_t
|
||||||
|
ReplyInterpreter::ReleaseLockOwner()
|
||||||
|
{
|
||||||
|
return _OperationError(OpReleaseLockOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // REPLYINTERPRETER_H
|
#endif // REPLYINTERPRETER_H
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,19 @@ RequestBuilder::GetFH()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
|
||||||
|
OpenFileCookie* cookie, LockOwner* owner)
|
||||||
|
{
|
||||||
|
stream.AddUHyper(cookie->fClientId);
|
||||||
|
|
||||||
|
uint64 lockOwner[2];
|
||||||
|
lockOwner[0] = owner->fOwner;
|
||||||
|
lockOwner[1] = cookie->fOwnerId;
|
||||||
|
stream.AddOpaque(lockOwner, sizeof(lockOwner));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
|
RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
|
||||||
{
|
{
|
||||||
@@ -178,12 +191,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
|
|||||||
|
|
||||||
// lock seq owner
|
// lock seq owner
|
||||||
fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
|
fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
|
||||||
fRequest->Stream().AddUHyper(cookie->fClientId);
|
_GenerateLockOwner(fRequest->Stream(), cookie, lock->fOwner);
|
||||||
|
|
||||||
uint64 owner[2];
|
|
||||||
owner[0] = lock->fOwner->fOwner;
|
|
||||||
owner[1] = cookie->fOwnerId;
|
|
||||||
fRequest->Stream().AddOpaque(owner, sizeof(owner));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fRequest->Stream().AddBoolean(false); // old lock owner
|
fRequest->Stream().AddBoolean(false); // old lock owner
|
||||||
@@ -681,6 +689,23 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::ReleaseLockOwner(OpenFileCookie* cookie, LockOwner* owner)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpReleaseLockOwner);
|
||||||
|
_GenerateLockOwner(fRequest->Stream(), cookie, owner);
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RPC::Call*
|
RPC::Call*
|
||||||
RequestBuilder::Request()
|
RequestBuilder::Request()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
class OpenFileCookie;
|
class OpenFileCookie;
|
||||||
class LockInfo;
|
class LockInfo;
|
||||||
|
class LockOwner;
|
||||||
|
|
||||||
class RequestBuilder {
|
class RequestBuilder {
|
||||||
public:
|
public:
|
||||||
@@ -72,12 +73,18 @@ public:
|
|||||||
status_t Write(const uint32* id, uint32 stateSeq,
|
status_t Write(const uint32* id, uint32 stateSeq,
|
||||||
const void* buffer, uint64 pos,
|
const void* buffer, uint64 pos,
|
||||||
uint32 len);
|
uint32 len);
|
||||||
|
status_t ReleaseLockOwner(OpenFileCookie* cookie,
|
||||||
|
LockOwner* owner);
|
||||||
|
|
||||||
RPC::Call* Request();
|
RPC::Call* Request();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _InitHeader();
|
void _InitHeader();
|
||||||
|
|
||||||
|
void _GenerateLockOwner(XDR::WriteStream& stream,
|
||||||
|
OpenFileCookie* cookie,
|
||||||
|
LockOwner* owner);
|
||||||
|
|
||||||
void _EncodeAttrs(XDR::WriteStream& stream,
|
void _EncodeAttrs(XDR::WriteStream& stream,
|
||||||
AttrValue* attr, uint32 count);
|
AttrValue* attr, uint32 count);
|
||||||
void _AttrBitmap(XDR::WriteStream& stream,
|
void _AttrBitmap(XDR::WriteStream& stream,
|
||||||
|
|||||||
Reference in New Issue
Block a user