From e36a54427c52d685efec2862cba812ac46a15ad4 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 17:05:05 +0200 Subject: [PATCH] nfs4: Add write() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 68 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 9 ++- .../file_systems/nfs4/ReplyInterpreter.cpp | 15 ++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 24 +++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 3 + .../file_systems/nfs4/kernel_interface.cpp | 20 +++++- 8 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ae11bb6276..847b35428d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1019,6 +1019,74 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) } +status_t +Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, + size_t length) +{ + uint32 size = 0; + uint32 len = 0; + const char* buffer = reinterpret_cast(_buffer); + + while (size < length) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size, + pos + size, length - size); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + + // server is in grace period, we need to wait + if (reply.NFS4Error() == NFS4ERR_GRACE) { + snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, + B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + continue; + } + + // server has rebooted, reclaim share and try again + if (reply.NFS4Error() == NFS4ERR_STALE_CLIENTID || + reply.NFS4Error() == NFS4ERR_STALE_STATEID) { + fFilesystem->NFSServer()->ServerRebooted(cookie->fClientId); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.Write(&len); + if (result != B_OK) + return result; + + size += len; + + break; + } while (true); + } + + return B_OK; +} + + status_t Inode::OpenDir(OpenDirCookie* cookie) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index ae649add73..7139d76ee4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -49,6 +49,8 @@ public: status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* length); + status_t Write(OpenFileCookie* cookie, off_t pos, + const void* buffer, size_t length); status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7cb8e801d2..ffa17d5975 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -42,7 +42,8 @@ enum Opcode { OpSaveFH = 32, OpSetClientID = 35, OpSetClientIDConfirm = 36, - OpVerify = 37 + OpVerify = 37, + OpWrite = 38 }; enum Access { @@ -171,6 +172,12 @@ enum OpenFlags { OPEN4_RESULT_LOCKTYPE_POSIX = 4 }; +enum WriteStable { + UNSTABLE4 = 0, + DATA_SYNC4 = 1, + FILE_SYNC4 = 2 +}; + enum Errors { NFS4_OK = 0, NFS4ERR_PERM = 1, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index dd03e0ef81..81359239f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -372,6 +372,21 @@ ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) } +status_t +ReplyInterpreter::Write(uint32* size) +{ + status_t res = _OperationError(OpWrite); + if (res != B_OK) + return res; + + *size = fReply->Stream().GetUInt(); + fReply->Stream().GetInt(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + static const char* sFlattenPathname(XDR::ReadStream& str) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 9c22a5e55b..e7c7a566a2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -87,6 +87,7 @@ public: status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); inline status_t Verify(); + status_t Write(uint32* size); private: void _ParseHeader(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index eebbc0f20d..d4090cb01d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -500,6 +500,30 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count) } +status_t +RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, + uint64 pos, uint32 len) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpWrite); + fRequest->Stream().AddUInt(stateSeq); + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + fRequest->Stream().AddUHyper(pos); + fRequest->Stream().AddInt(FILE_SYNC4); + fRequest->Stream().AddOpaque(buffer, len); + + 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 e864576f7d..b6cc110d53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -58,6 +58,9 @@ public: status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); + status_t Write(const uint32* id, uint32 stateSeq, + const void* buffer, uint64 pos, + uint32 len); 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 fd24f6fa56..220c2b7aaf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -353,6 +353,24 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, } +static status_t +nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + const void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR) + return B_IS_A_DIRECTORY; + + if (inode->Type() == S_IFLNK) + return B_BAD_VALUE; + + OpenFileCookie* cookie = reinterpret_cast(_cookie); + + return inode->Write(cookie, pos, buffer, *length); +} + + static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { @@ -500,7 +518,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_close, nfs4_free_cookie, nfs4_read, - NULL, // write, + nfs4_write, /* directory operations */ NULL, // create_dir()