From 2a292557d4bffd34841c3db2ee1095a1a51f0274 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 22:30:23 +0200 Subject: [PATCH] nfs4: Add open() hook --- .../kernel/file_systems/nfs4/Connection.cpp | 27 +++++ .../kernel/file_systems/nfs4/Connection.h | 4 + .../kernel/file_systems/nfs4/Inode.cpp | 64 ++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 8 ++ .../kernel/file_systems/nfs4/NFS4Defs.h | 35 ++++-- .../kernel/file_systems/nfs4/RPCServer.h | 12 ++ .../file_systems/nfs4/ReplyInterpreter.cpp | 70 ++++++++++- .../file_systems/nfs4/ReplyInterpreter.h | 11 ++ .../file_systems/nfs4/RequestBuilder.cpp | 113 ++++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 7 ++ .../file_systems/nfs4/kernel_interface.cpp | 12 +- 11 files changed, 350 insertions(+), 13 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index c1b7e89f75..0143f79bc6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 11029c3230..041c5deda2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -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(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b69e177a84..134a69fb7c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 4d85cf9938..769a71a6a3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 860a32ff91..f53e0fd8cb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 5a7d3d0a46..13cf8b2256 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -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; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 77d999ee03..dac46ce247 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -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; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 173ace3ab8..9a6f4188d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 783999819e..3ce7f2c98b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index e784602a85..e3b5d301eb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -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(); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 2872647b9d..d9d3e355a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -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(vnode->private_node); + status_t result = inode->Open(openMode, cookie); + if (result != B_OK) + delete cookie; + + return result; }