nfs4: Add support for file locking
This commit is contained in:
@@ -84,3 +84,15 @@ Cookie::CancelAll()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OpenFileCookie::OpenFileCookie()
|
||||||
|
{
|
||||||
|
mutex_init(&fLocksLock, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OpenFileCookie::~OpenFileCookie()
|
||||||
|
{
|
||||||
|
mutex_destroy(&fLocksLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,20 @@
|
|||||||
#include "Filesystem.h"
|
#include "Filesystem.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct LockInfo {
|
||||||
|
uint32 fStateId[3];
|
||||||
|
uint32 fStateSeq;
|
||||||
|
|
||||||
|
uint32 fSequence;
|
||||||
|
|
||||||
|
uint32 fOwner;
|
||||||
|
uint64 fStart;
|
||||||
|
uint64 fLength;
|
||||||
|
LockType fType;
|
||||||
|
|
||||||
|
LockInfo* fNext;
|
||||||
|
};
|
||||||
|
|
||||||
struct Cookie {
|
struct Cookie {
|
||||||
struct RequestEntry {
|
struct RequestEntry {
|
||||||
RPC::Request* fRequest;
|
RPC::Request* fRequest;
|
||||||
@@ -46,8 +60,14 @@ struct OpenFileCookie : public Cookie {
|
|||||||
uint64 fOwnerId;
|
uint64 fOwnerId;
|
||||||
static vint64 fLastOwnerId;
|
static vint64 fLastOwnerId;
|
||||||
|
|
||||||
|
LockInfo* fLocks;
|
||||||
|
mutex fLocksLock;
|
||||||
|
|
||||||
OpenFileCookie* fNext;
|
OpenFileCookie* fNext;
|
||||||
OpenFileCookie* fPrev;
|
OpenFileCookie* fPrev;
|
||||||
|
|
||||||
|
OpenFileCookie();
|
||||||
|
~OpenFileCookie();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OpenDirCookie : public Cookie {
|
struct OpenDirCookie : public Cookie {
|
||||||
|
|||||||
@@ -699,6 +699,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
|||||||
|
|
||||||
cookie->fMode = mode;
|
cookie->fMode = mode;
|
||||||
cookie->fSequence = 0;
|
cookie->fSequence = 0;
|
||||||
|
cookie->fLocks = NULL;
|
||||||
|
|
||||||
Filehandle fh;
|
Filehandle fh;
|
||||||
do {
|
do {
|
||||||
@@ -803,6 +804,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
cookie->fHandle = fHandle;
|
cookie->fHandle = fHandle;
|
||||||
cookie->fMode = mode;
|
cookie->fMode = mode;
|
||||||
cookie->fSequence = 0;
|
cookie->fSequence = 0;
|
||||||
|
cookie->fLocks = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||||
@@ -1275,6 +1277,208 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
|
Request request(serv);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.LockT(sGetLockType(lock->l_type, false), lock->l_start,
|
||||||
|
lock->l_len, cookie);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
reply.PutFH();
|
||||||
|
LockType ltype;
|
||||||
|
uint64 pos, len;
|
||||||
|
result = reply.LockT(&pos, &len, <ype);
|
||||||
|
if (reply.NFS4Error() == NFS4ERR_DENIED) {
|
||||||
|
lock->l_type = sLockTypeToHaiku(ltype);
|
||||||
|
lock->l_start = static_cast<off_t>(pos);
|
||||||
|
lock->l_len = static_cast<off_t>(len);
|
||||||
|
result = B_OK;
|
||||||
|
} else if (reply.NFS4Error() == NFS4_OK)
|
||||||
|
lock->l_type = F_UNLCK;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
|
||||||
|
bool wait)
|
||||||
|
{
|
||||||
|
LockInfo* linfo = new LockInfo;
|
||||||
|
if (linfo == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
linfo->fSequence = 0;
|
||||||
|
linfo->fStart = lock->l_start;
|
||||||
|
if (lock->l_len == OFF_MAX)
|
||||||
|
linfo->fLength = UINT64_MAX;
|
||||||
|
else
|
||||||
|
linfo->fLength = lock->l_len;
|
||||||
|
linfo->fType = sGetLockType(lock->l_type, wait);
|
||||||
|
linfo->fOwner = find_thread(NULL);
|
||||||
|
|
||||||
|
do {
|
||||||
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
|
Request request(serv);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.Lock(cookie, linfo);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK) {
|
||||||
|
delete linfo;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
|
||||||
|
snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
reply.PutFH();
|
||||||
|
result = reply.Lock(linfo);
|
||||||
|
if (result != B_OK) {
|
||||||
|
delete linfo;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
mutex_lock(&cookie->fLocksLock);
|
||||||
|
linfo->fNext = cookie->fLocks;
|
||||||
|
cookie->fLocks = linfo;
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
|
||||||
|
{
|
||||||
|
LockInfo* prev = NULL;
|
||||||
|
uint32 owner = find_thread(NULL);
|
||||||
|
|
||||||
|
mutex_lock(&cookie->fLocksLock);
|
||||||
|
LockInfo* linfo = cookie->fLocks;
|
||||||
|
while (linfo != NULL) {
|
||||||
|
if (linfo->fOwner == owner &&
|
||||||
|
linfo->fStart == static_cast<uint64>(lock->l_start) &&
|
||||||
|
(linfo->fLength == static_cast<uint64>(lock->l_len) ||
|
||||||
|
(linfo->fLength == UINT64_MAX && lock->l_len == OFF_MAX))) {
|
||||||
|
if (prev != NULL)
|
||||||
|
prev->fNext = linfo->fNext;
|
||||||
|
else
|
||||||
|
cookie->fLocks = linfo->fNext;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = linfo;
|
||||||
|
linfo = linfo->fNext;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
|
||||||
|
if (linfo == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
|
Request request(serv);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.LockU(linfo);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
|
||||||
|
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
reply.PutFH();
|
||||||
|
result = reply.LockU();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
delete linfo;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::ReleaseAllLocks(OpenFileCookie* cookie)
|
||||||
|
{
|
||||||
|
mutex_lock(&cookie->fLocksLock);
|
||||||
|
while (cookie->fLocks != NULL) {
|
||||||
|
do {
|
||||||
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
|
Request request(serv);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.LockU(cookie->fLocks);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK) {
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
|
||||||
|
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
reply.PutFH();
|
||||||
|
result = reply.LockU();
|
||||||
|
if (result != B_OK) {
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
LockInfo* linfo = cookie->fLocks->fNext;
|
||||||
|
delete cookie->fLocks;
|
||||||
|
cookie->fLocks = linfo;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||||
OpenFileCookie* cookie)
|
OpenFileCookie* cookie)
|
||||||
@@ -1284,6 +1488,7 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// server needs more time, we need to wait
|
// server needs more time, we need to wait
|
||||||
|
case NFS4ERR_LOCKED:
|
||||||
case NFS4ERR_DELAY:
|
case NFS4ERR_DELAY:
|
||||||
if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) {
|
if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) {
|
||||||
snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
|
snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ public:
|
|||||||
status_t ReadDir(void* buffer, uint32 size,
|
status_t ReadDir(void* buffer, uint32 size,
|
||||||
uint32* count, OpenDirCookie* cookie);
|
uint32* count, OpenDirCookie* cookie);
|
||||||
|
|
||||||
|
status_t TestLock(OpenFileCookie* cookie,
|
||||||
|
struct flock* lock);
|
||||||
|
status_t AcquireLock(OpenFileCookie* cookie,
|
||||||
|
const struct flock* lock, bool wait);
|
||||||
|
status_t ReleaseLock(OpenFileCookie* cookie,
|
||||||
|
const struct flock* lock);
|
||||||
|
status_t ReleaseAllLocks(OpenFileCookie* cookie);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Inode();
|
Inode();
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define NFS4DEFS_H
|
#define NFS4DEFS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
@@ -27,6 +28,9 @@ enum Opcode {
|
|||||||
OpGetAttr = 9,
|
OpGetAttr = 9,
|
||||||
OpGetFH = 10,
|
OpGetFH = 10,
|
||||||
OpLink = 11,
|
OpLink = 11,
|
||||||
|
OpLock = 12,
|
||||||
|
OpLockT = 13,
|
||||||
|
OpLockU = 14,
|
||||||
OpLookUp = 15,
|
OpLookUp = 15,
|
||||||
OpLookUpUp = 16,
|
OpLookUpUp = 16,
|
||||||
OpNverify = 17,
|
OpNverify = 17,
|
||||||
@@ -180,6 +184,40 @@ enum WriteStable {
|
|||||||
FILE_SYNC4 = 2
|
FILE_SYNC4 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum LockType {
|
||||||
|
READ_LT = 1,
|
||||||
|
WRITE_LT = 2,
|
||||||
|
READW_LT = 3,
|
||||||
|
WRITEW_LT = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline
|
||||||
|
LockType sGetLockType(short type, bool wait) {
|
||||||
|
switch (type) {
|
||||||
|
case F_RDLCK: return wait ? READW_LT : READ_LT;
|
||||||
|
case F_WRLCK: return wait ? WRITEW_LT : WRITE_LT;
|
||||||
|
default: return READ_LT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline
|
||||||
|
short sLockTypeToHaiku(LockType type) {
|
||||||
|
switch (type) {
|
||||||
|
case READ_LT:
|
||||||
|
case READW_LT:
|
||||||
|
return F_RDLCK;
|
||||||
|
|
||||||
|
case WRITE_LT:
|
||||||
|
case WRITEW_LT:
|
||||||
|
return F_WRLCK;
|
||||||
|
|
||||||
|
default: return F_UNLCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum Errors {
|
enum Errors {
|
||||||
NFS4_OK = 0,
|
NFS4_OK = 0,
|
||||||
NFS4ERR_PERM = 1,
|
NFS4ERR_PERM = 1,
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ NFS4Server::ServerRebooted(uint64 clientId)
|
|||||||
OpenFileCookie* current = fOpenFiles;
|
OpenFileCookie* current = fOpenFiles;
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
_ReclaimOpen(current);
|
_ReclaimOpen(current);
|
||||||
|
_ReclaimLocks(current);
|
||||||
current = current->fNext;
|
current = current->fNext;
|
||||||
}
|
}
|
||||||
mutex_unlock(&fOpenLock);
|
mutex_unlock(&fOpenLock);
|
||||||
@@ -74,7 +75,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie)
|
|||||||
req.Open(CLAIM_PREVIOUS, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ,
|
req.Open(CLAIM_PREVIOUS, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ,
|
||||||
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL);
|
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL);
|
||||||
|
|
||||||
status_t result = request.Send();;
|
status_t result = request.Send();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -108,6 +109,39 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
|
||||||
|
{
|
||||||
|
mutex_lock(&cookie->fLocksLock);
|
||||||
|
LockInfo* linfo = cookie->fLocks;
|
||||||
|
while (linfo != NULL) {
|
||||||
|
do {
|
||||||
|
Request request(fServer);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(cookie->fHandle);
|
||||||
|
req.Lock(cookie, linfo, true);
|
||||||
|
|
||||||
|
status_t result = request.Send();
|
||||||
|
if (result != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ReplyInterpreter &reply = request.Reply();
|
||||||
|
|
||||||
|
reply.PutFH();
|
||||||
|
reply.Lock(linfo);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
linfo = linfo->fNext;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cookie->fLocksLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NFS4Server::AddOpenFile(OpenFileCookie* cookie)
|
NFS4Server::AddOpenFile(OpenFileCookie* cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public:
|
|||||||
inline uint32 LeaseTime();
|
inline uint32 LeaseTime();
|
||||||
private:
|
private:
|
||||||
status_t _ReclaimOpen(OpenFileCookie* cookie);
|
status_t _ReclaimOpen(OpenFileCookie* cookie);
|
||||||
|
status_t _ReclaimLocks(OpenFileCookie* cookie);
|
||||||
|
|
||||||
status_t _GetLeaseTime();
|
status_t _GetLeaseTime();
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <util/kernel_cpp.h>
|
#include <util/kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "Cookie.h"
|
||||||
|
|
||||||
|
|
||||||
FSLocation::~FSLocation()
|
FSLocation::~FSLocation()
|
||||||
{
|
{
|
||||||
@@ -208,6 +210,56 @@ ReplyInterpreter::Link()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ReplyInterpreter::Lock(LockInfo* linfo)
|
||||||
|
{
|
||||||
|
status_t res = _OperationError(OpLock);
|
||||||
|
if (res != B_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
linfo->fStateSeq = fReply->Stream().GetUInt();
|
||||||
|
linfo->fStateId[0] = fReply->Stream().GetUInt();
|
||||||
|
linfo->fStateId[1] = fReply->Stream().GetUInt();
|
||||||
|
linfo->fStateId[2] = fReply->Stream().GetUInt();
|
||||||
|
|
||||||
|
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type)
|
||||||
|
{
|
||||||
|
status_t res = _OperationError(OpLockU);
|
||||||
|
if (res != B_WOULD_BLOCK || NFS4Error() != NFS4ERR_DENIED)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
*pos = fReply->Stream().GetUHyper();
|
||||||
|
*len = fReply->Stream().GetUHyper();
|
||||||
|
*type = static_cast<LockType>(fReply->Stream().GetInt());
|
||||||
|
|
||||||
|
fReply->Stream().GetUHyper();
|
||||||
|
fReply->Stream().GetOpaque(NULL);
|
||||||
|
|
||||||
|
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ReplyInterpreter::LockU()
|
||||||
|
{
|
||||||
|
status_t res = _OperationError(OpLockU);
|
||||||
|
if (res != B_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
fReply->Stream().GetUInt();
|
||||||
|
fReply->Stream().GetUInt();
|
||||||
|
fReply->Stream().GetUInt();
|
||||||
|
fReply->Stream().GetUInt();
|
||||||
|
|
||||||
|
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm)
|
ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm)
|
||||||
{
|
{
|
||||||
@@ -675,6 +727,8 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x)
|
|||||||
case NFS4ERR_FBIG: return B_FILE_TOO_LARGE;
|
case NFS4ERR_FBIG: return B_FILE_TOO_LARGE;
|
||||||
// ...
|
// ...
|
||||||
case NFS4ERR_DELAY:
|
case NFS4ERR_DELAY:
|
||||||
|
case NFS4ERR_DENIED:
|
||||||
|
case NFS4ERR_LOCKED:
|
||||||
case NFS4ERR_GRACE:
|
case NFS4ERR_GRACE:
|
||||||
return B_WOULD_BLOCK;
|
return B_WOULD_BLOCK;
|
||||||
// ...
|
// ...
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ struct DirEntry {
|
|||||||
~DirEntry();
|
~DirEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LockInfo;
|
||||||
|
|
||||||
class ReplyInterpreter {
|
class ReplyInterpreter {
|
||||||
public:
|
public:
|
||||||
ReplyInterpreter(RPC::Reply* reply = NULL);
|
ReplyInterpreter(RPC::Reply* reply = NULL);
|
||||||
@@ -70,6 +72,9 @@ public:
|
|||||||
status_t GetAttr(AttrValue** attrs, uint32* count);
|
status_t GetAttr(AttrValue** attrs, uint32* count);
|
||||||
status_t GetFH(Filehandle* fh);
|
status_t GetFH(Filehandle* fh);
|
||||||
status_t Link();
|
status_t Link();
|
||||||
|
status_t Lock(LockInfo* linfo);
|
||||||
|
status_t LockT(uint64* pos, uint64* len, LockType* type);
|
||||||
|
status_t LockU();
|
||||||
inline status_t LookUp();
|
inline status_t LookUp();
|
||||||
inline status_t LookUpUp();
|
inline status_t LookUpUp();
|
||||||
inline status_t Nverify();
|
inline status_t Nverify();
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Cookie.h"
|
||||||
|
|
||||||
|
|
||||||
RequestBuilder::RequestBuilder(Procedure proc)
|
RequestBuilder::RequestBuilder(Procedure proc)
|
||||||
:
|
:
|
||||||
@@ -146,6 +148,96 @@ RequestBuilder::GetFH()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpLock);
|
||||||
|
|
||||||
|
fRequest->Stream().AddInt(lock->fType);
|
||||||
|
fRequest->Stream().AddBoolean(reclaim);
|
||||||
|
|
||||||
|
fRequest->Stream().AddUHyper(lock->fStart);
|
||||||
|
fRequest->Stream().AddUHyper(lock->fLength);
|
||||||
|
|
||||||
|
fRequest->Stream().AddBoolean(true); // new lock owner
|
||||||
|
|
||||||
|
// open seq stateid
|
||||||
|
fRequest->Stream().AddUInt(cookie->fSequence++);
|
||||||
|
fRequest->Stream().AddUInt(cookie->fStateSeq);
|
||||||
|
fRequest->Stream().AddUInt(cookie->fStateId[0]);
|
||||||
|
fRequest->Stream().AddUInt(cookie->fStateId[1]);
|
||||||
|
fRequest->Stream().AddUInt(cookie->fStateId[2]);
|
||||||
|
|
||||||
|
// lock seq owner
|
||||||
|
fRequest->Stream().AddUInt(lock->fSequence++);
|
||||||
|
fRequest->Stream().AddUHyper(cookie->fClientId);
|
||||||
|
fRequest->Stream().AddOpaque(&lock->fOwner, sizeof(lock->fOwner));
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::LockT(LockType type, uint64 pos, uint64 len,
|
||||||
|
OpenFileCookie* cookie)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpLockT);
|
||||||
|
|
||||||
|
fRequest->Stream().AddInt(type);
|
||||||
|
|
||||||
|
fRequest->Stream().AddUHyper(pos);
|
||||||
|
fRequest->Stream().AddUHyper(len);
|
||||||
|
|
||||||
|
fRequest->Stream().AddUHyper(cookie->fClientId);
|
||||||
|
|
||||||
|
uint32 owner = find_thread(NULL);
|
||||||
|
fRequest->Stream().AddOpaque(&owner, sizeof(owner));
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::LockU(LockInfo* lock)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpLockU);
|
||||||
|
|
||||||
|
fRequest->Stream().AddInt(lock->fType);
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(lock->fSequence++);
|
||||||
|
fRequest->Stream().AddUInt(lock->fStateSeq);
|
||||||
|
fRequest->Stream().AddUInt(lock->fStateId[0]);
|
||||||
|
fRequest->Stream().AddUInt(lock->fStateId[1]);
|
||||||
|
fRequest->Stream().AddUInt(lock->fStateId[2]);
|
||||||
|
|
||||||
|
fRequest->Stream().AddUHyper(lock->fStart);
|
||||||
|
fRequest->Stream().AddUHyper(lock->fLength);
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RequestBuilder::Link(const char* name)
|
RequestBuilder::Link(const char* name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
#include "XDR.h"
|
#include "XDR.h"
|
||||||
|
|
||||||
|
|
||||||
|
class OpenFileCookie;
|
||||||
|
class LockInfo;
|
||||||
|
|
||||||
class RequestBuilder {
|
class RequestBuilder {
|
||||||
public:
|
public:
|
||||||
RequestBuilder(Procedure p = ProcCompound);
|
RequestBuilder(Procedure p = ProcCompound);
|
||||||
@@ -34,6 +37,11 @@ public:
|
|||||||
status_t GetAttr(Attribute* attrs, uint32 count);
|
status_t GetAttr(Attribute* attrs, uint32 count);
|
||||||
status_t GetFH();
|
status_t GetFH();
|
||||||
status_t Link(const char* name);
|
status_t Link(const char* name);
|
||||||
|
status_t Lock(OpenFileCookie* cookie,
|
||||||
|
LockInfo* lock, bool reclaim = false);
|
||||||
|
status_t LockT(LockType type, uint64 pos,
|
||||||
|
uint64 len, OpenFileCookie* cookie);
|
||||||
|
status_t LockU(LockInfo* lock);
|
||||||
status_t LookUp(const char* name);
|
status_t LookUp(const char* name);
|
||||||
status_t LookUpUp();
|
status_t LookUpUp();
|
||||||
status_t Nverify(AttrValue* attr, uint32 count);
|
status_t Nverify(AttrValue* attr, uint32 count);
|
||||||
|
|||||||
@@ -466,6 +466,39 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||||
|
struct flock* lock)
|
||||||
|
{
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||||
|
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||||
|
return inode->TestLock(cookie, lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||||
|
const struct flock* lock, bool wait)
|
||||||
|
{
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||||
|
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||||
|
return inode->AcquireLock(cookie, lock, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||||
|
const struct flock* lock)
|
||||||
|
{
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||||
|
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||||
|
if (lock != NULL)
|
||||||
|
return inode->ReleaseLock(cookie, lock);
|
||||||
|
else
|
||||||
|
return inode->ReleaseAllLocks(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
nfs4_init()
|
nfs4_init()
|
||||||
{
|
{
|
||||||
@@ -561,6 +594,35 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
|||||||
nfs4_free_dir_cookie,
|
nfs4_free_dir_cookie,
|
||||||
nfs4_read_dir,
|
nfs4_read_dir,
|
||||||
nfs4_rewind_dir,
|
nfs4_rewind_dir,
|
||||||
|
|
||||||
|
/* attribute directory operations */
|
||||||
|
NULL, // open_attr_dir
|
||||||
|
NULL, // close_attr_dir
|
||||||
|
NULL, // free_attr_dir_cookie
|
||||||
|
NULL, // read_attr_dir
|
||||||
|
NULL, // rewind_attr_dir
|
||||||
|
|
||||||
|
/* attribute operations */
|
||||||
|
NULL, // create_attr
|
||||||
|
NULL, // open_attr
|
||||||
|
NULL, // close_attr
|
||||||
|
NULL, // free_attr_cookie
|
||||||
|
NULL, // read_attr
|
||||||
|
NULL, // write_attr
|
||||||
|
|
||||||
|
NULL, // read_attr_stat
|
||||||
|
NULL, // write_attr_stat
|
||||||
|
NULL, // rename_attr
|
||||||
|
NULL, // remove_attr
|
||||||
|
|
||||||
|
/* support for node and FS layers */
|
||||||
|
NULL, // create_special_node
|
||||||
|
NULL, // get_super_vnode
|
||||||
|
|
||||||
|
/* lock operations */
|
||||||
|
nfs4_test_lock,
|
||||||
|
nfs4_acquire_lock,
|
||||||
|
nfs4_release_lock,
|
||||||
};
|
};
|
||||||
|
|
||||||
static file_system_module_info sNFSv4ModuleInfo = {
|
static file_system_module_info sNFSv4ModuleInfo = {
|
||||||
|
|||||||
Reference in New Issue
Block a user