nfs4: Add open() hook

This commit is contained in:
Pawel Dziepak 2012-06-05 22:30:23 +02:00
parent 8d513ebcb5
commit 2a292557d4
11 changed files with 350 additions and 13 deletions

View File

@ -42,6 +42,16 @@ ServerAddress::operator<(const ServerAddress& x)
}
ServerAddress&
ServerAddress::operator=(const ServerAddress& x)
{
fAddress = x.fAddress;
fPort = x.fPort;
fProtocol = x.fProtocol;
return *this;
}
Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers)
:
fSock(-1),
@ -61,6 +71,23 @@ Connection::~Connection()
}
status_t
Connection::GetLocalID(ServerAddress* addr)
{
struct sockaddr_in saddr;
socklen_t slen = sizeof(addr);
status_t result = kgetsockname(fSock, (struct sockaddr*)&saddr, &slen);
if (result != B_OK)
return result;
addr->fProtocol = fProtocol;
addr->fPort = ntohs(saddr.sin_port);
addr->fAddress = ntohl(saddr.sin_addr.s_addr);
return B_OK;
}
status_t
Connection::_SendStream(const void* buffer, uint32 size)
{

View File

@ -27,6 +27,8 @@ struct ServerAddress {
bool operator==(const ServerAddress& x);
bool operator<(const ServerAddress& x);
ServerAddress& operator=(const ServerAddress& x);
};
class Connection {
@ -38,6 +40,8 @@ public:
inline status_t Send(const void* buffer, uint32 size);
inline status_t Receive(void** buffer, uint32* size);
status_t GetLocalID(ServerAddress* addr);
status_t Reconnect();
void Disconnect();

View File

@ -185,6 +185,70 @@ Inode::Stat(struct stat* st)
}
status_t
Inode::Open(int mode, OpenFileCookie* cookie)
{
cookie->fSeq = 0;
RequestBuilder req_setid(ProcCompound);
req_setid.SetClientID(fFilesystem->Server());
RPC::Reply *rpl;
fFilesystem->Server()->SendCall(req_setid.Request(), &rpl);
ReplyInterpreter setid(rpl);
uint64 id, ver;
status_t result = setid.SetClientID(&id, &ver);
if (result != B_OK)
return result;
RequestBuilder req_conf(ProcCompound);
req_conf.SetClientIDConfirm(id, ver);
fFilesystem->Server()->SendCall(req_conf.Request(), &rpl);
ReplyInterpreter conf(rpl);
result = conf.SetClientIDConfirm();
if (result != B_OK)
return result;
RequestBuilder req(ProcCompound);
req.PutFH(fParentFH);
req.Open(cookie->fSeq, OPEN4_SHARE_ACCESS_READ, id, OPEN4_NOCREATE, fName);
cookie->fSeq++;
fFilesystem->Server()->SendCall(req.Request(), &rpl);
ReplyInterpreter reply(rpl);
result = reply.PutFH();
if (result != B_OK)
return result;
bool confirm;
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
if (result != B_OK)
return result;
if (confirm) {
RequestBuilder req(ProcCompound);
req.PutFH(fHandle);
req.OpenConfirm(cookie->fSeq, cookie->fStateId, cookie->fStateSeq);
cookie->fSeq++;
fFilesystem->Server()->SendCall(req.Request(), &rpl);
ReplyInterpreter reply(rpl);
result = reply.PutFH();
if (result != B_OK)
return result;
result = reply.OpenConfirm(&cookie->fStateSeq);
if (result != B_OK)
return result;
}
return B_OK;
}
status_t
Inode::OpenDir(uint64* cookie)
{

View File

@ -18,6 +18,12 @@
#include "ReplyInterpreter.h"
struct OpenFileCookie {
uint32 fStateId[3];
uint32 fStateSeq;
uint32 fSeq;
};
class Inode {
public:
Inode(Filesystem* fs, const FileInfo& fi);
@ -30,6 +36,8 @@ public:
status_t LookUp(const char* name, ino_t* id);
status_t Stat(struct stat* st);
status_t Open(int mode, OpenFileCookie* cookie);
status_t OpenDir(uint64* cookie);
status_t ReadDir(void* buffer, uint32 size,
uint32* count, uint64* cookie);

View File

@ -21,14 +21,18 @@ enum Procedure {
};
enum Opcode {
OpAccess = 3,
OpGetAttr = 9,
OpGetFH = 10,
OpLookUp = 15,
OpLookUpUp = 16,
OpPutFH = 22,
OpPutRootFH = 24,
OpReadDir = 26
OpAccess = 3,
OpGetAttr = 9,
OpGetFH = 10,
OpLookUp = 15,
OpLookUpUp = 16,
OpOpen = 18,
OpOpenConfirm = 20,
OpPutFH = 22,
OpPutRootFH = 24,
OpReadDir = 26,
OpSetClientID = 35,
OpSetClientIDConfirm = 36
};
enum Access {
@ -128,6 +132,21 @@ enum FileHandleExpiryType {
FH4_VOL_RENAME = 0x08
};
enum OpenAccess {
OPEN4_SHARE_ACCESS_READ = 1,
OPEN4_SHARE_ACCESS_WRITE = 2
};
enum OpenCreate {
OPEN4_NOCREATE = 0,
OPEN4_CREATE = 1
};
enum OpenFlags {
OPEN4_RESULT_CONFIRM = 2,
OPEN4_RESULT_LOCKTYPE_POSIX = 4
};
enum Errors {
NFS4_OK = 0,
NFS4ERR_PERM = 1,

View File

@ -53,6 +53,7 @@ public:
status_t Repair();
inline const ServerAddress& ID() const;
inline ServerAddress LocalID() const;
private:
inline uint32 _GetXID();
@ -80,6 +81,17 @@ Server::ID() const
return *fAddress;
}
inline ServerAddress
Server::LocalID() const
{
ServerAddress addr;
memset(&addr, 0, sizeof(addr));
fConnection->GetLocalID(&addr);
return addr;
}
struct ServerNode {
ServerAddress fID;
Server* fServer;

View File

@ -61,7 +61,7 @@ ReplyInterpreter::Access(uint32* supported, uint32* allowed)
if (allowed != NULL)
*allowed = allow;
return B_OK;
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
@ -112,7 +112,55 @@ ReplyInterpreter::GetFH(Filehandle* fh)
memcpy(fh->fFH, ptr, size);
}
return B_OK;
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
status_t
ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm)
{
status_t res = _OperationError(OpOpen);
if (res != B_OK)
return res;
*seq = fReply->Stream().GetUInt();
id[0] = fReply->Stream().GetUInt();
id[1] = fReply->Stream().GetUInt();
id[2] = fReply->Stream().GetUInt();
// change info
fReply->Stream().GetBoolean();
fReply->Stream().GetUHyper();
fReply->Stream().GetUHyper();
uint32 flags = fReply->Stream().GetUInt();
*confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM;
// attrmask
uint32 bcount = fReply->Stream().GetUInt();
for (uint32 i = 0; i < bcount; i++)
fReply->Stream().GetUInt();
// delegation info
fReply->Stream().GetUInt();
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
status_t
ReplyInterpreter::OpenConfirm(uint32* stateSeq)
{
status_t res = _OperationError(OpOpenConfirm);
if (res != B_OK)
return res;
*stateSeq = fReply->Stream().GetUInt();
fReply->Stream().GetUInt();
fReply->Stream().GetUInt();
fReply->Stream().GetUInt();
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
@ -152,7 +200,21 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count,
*_count = count;
*dirents = entries;
return B_OK;
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
status_t
ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier)
{
status_t res = _OperationError(OpSetClientID);
if (res != B_OK)
return res;
*clientid = fReply->Stream().GetUHyper();
*verifier = fReply->Stream().GetUHyper();
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
@ -230,7 +292,7 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
*count = attr_count;
*attrs = values;
return B_OK;
return str.IsEOF() ? B_BAD_VALUE : B_OK;
}

View File

@ -43,10 +43,14 @@ public:
status_t GetFH(Filehandle* fh);
inline status_t LookUp();
inline status_t LookUpUp();
status_t Open(uint32* id, uint32* seq, bool* confirm);
status_t OpenConfirm(uint32* stateSeq);
inline status_t PutFH();
inline status_t PutRootFH();
status_t ReadDir(uint64* cookie, DirEntry** dirents,
uint32* count, bool* eof);
status_t SetClientID(uint64* clientid, uint64* verifier);
inline status_t SetClientIDConfirm();
private:
status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs,
@ -87,5 +91,12 @@ ReplyInterpreter::PutRootFH()
}
inline status_t
ReplyInterpreter::SetClientIDConfirm()
{
return _OperationError(OpSetClientIDConfirm);
}
#endif // REPLYINTERPRETER_H

View File

@ -118,6 +118,62 @@ RequestBuilder::LookUpUp()
}
status_t
RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc,
const char* name)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpOpen);
fRequest->Stream().AddUInt(seq);
fRequest->Stream().AddUInt(access);
fRequest->Stream().AddUInt(0); // deny none
fRequest->Stream().AddUHyper(id);
char owner[128];
int pos = 0;
*(uint32*)(owner + pos) = time(NULL);
pos += sizeof(uint32);
*(uint32*)(owner + pos) = find_thread(NULL);
pos += sizeof(uint32);
fRequest->Stream().AddOpaque(owner, pos);
fRequest->Stream().AddUInt(oc);
fRequest->Stream().AddUInt(0); // claim null
fRequest->Stream().AddString(name, strlen(name));
fOpCount++;
return B_OK;
}
status_t
RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpOpenConfirm);
fRequest->Stream().AddUInt(stateSeq);
fRequest->Stream().AddUInt(id[0]);
fRequest->Stream().AddUInt(id[1]);
fRequest->Stream().AddUInt(id[2]);
fRequest->Stream().AddUInt(seq);
fOpCount++;
return B_OK;
}
status_t
RequestBuilder::PutFH(const Filehandle& fh)
{
@ -175,6 +231,63 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
}
status_t
RequestBuilder::SetClientID(const RPC::Server* serv)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpSetClientID);
uint64 verifier = rand();
verifier = verifier << 32 | rand();
fRequest->Stream().AddUHyper(verifier);
char id[128] = "HAIKU:kernel:";
int pos = strlen(id);
*(uint32*)(id + pos) = serv->ID().fAddress;
pos += sizeof(uint32);
*(uint16*)(id + pos) = serv->ID().fPort;
pos += sizeof(uint16);
*(uint16*)(id + pos) = serv->ID().fProtocol;
pos += sizeof(uint16);
*(uint32*)(id + pos) = serv->LocalID().fAddress;
pos += sizeof(uint32);
fRequest->Stream().AddOpaque(id, pos);
// Callbacks are currently not supported
fRequest->Stream().AddUInt(0);
fRequest->Stream().AddOpaque(NULL, 0);
fRequest->Stream().AddOpaque(NULL, 0);
fRequest->Stream().AddUInt(0);
fOpCount++;
return B_OK;
}
status_t
RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver)
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpSetClientIDConfirm);
fRequest->Stream().AddUHyper(id);
fRequest->Stream().AddUHyper(ver);
fOpCount++;
return B_OK;
}
RPC::Call*
RequestBuilder::Request()
{

View File

@ -13,6 +13,7 @@
#include "NFS4Defs.h"
#include "RPCCall.h"
#include "RPCServer.h"
#include "XDR.h"
@ -26,10 +27,16 @@ public:
status_t GetFH();
status_t LookUp(const char* name);
status_t LookUpUp();
status_t Open(uint32 seq, uint32 access, uint64 id,
OpenCreate oc, const char* name);
status_t OpenConfirm(uint32 seq, const uint32* id,
uint32 stateSeq);
status_t PutFH(const Filehandle& fh);
status_t PutRootFH();
status_t ReadDir(uint32 count, uint64* cookie,
Attribute* attrs, uint32 attr_count);
status_t SetClientID(const RPC::Server* serv);
status_t SetClientIDConfirm(uint64 id, uint64 ver);
RPC::Call* Request();

View File

@ -142,7 +142,17 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
static status_t
nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
{
return B_ERROR;
OpenFileCookie* cookie = new OpenFileCookie;
if (cookie == NULL)
return B_NO_MEMORY;
*_cookie = cookie;
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
status_t result = inode->Open(openMode, cookie);
if (result != B_OK)
delete cookie;
return result;
}